libxt_connlabel.c revision ccbf6b6448a4210432b76fd4660798705b05f8c4
1#include <errno.h> 2#include <stdbool.h> 3#include <string.h> 4#include <stdio.h> 5#include <stdint.h> 6#include <xtables.h> 7#include <linux/netfilter/xt_connlabel.h> 8 9enum { 10 O_LABEL = 0, 11 O_SET = 1, 12}; 13 14#define CONNLABEL_CFG "/etc/xtables/connlabel.conf" 15 16static void connlabel_mt_help(void) 17{ 18 puts( 19"connlabel match options:\n" 20"[!] --label name Match if label has been set on connection\n" 21" --set Set label on connection"); 22} 23 24static const struct xt_option_entry connlabel_mt_opts[] = { 25 {.name = "label", .id = O_LABEL, .type = XTTYPE_STRING, 26 .min = 1, .flags = XTOPT_MAND|XTOPT_INVERT}, 27 {.name = "set", .id = O_SET, .type = XTTYPE_NONE}, 28 XTOPT_TABLEEND, 29}; 30 31static int 32xtables_parse_connlabel_numerical(const char *s, char **end) 33{ 34 uintmax_t value; 35 36 if (!xtables_strtoul(s, end, &value, 0, XT_CONNLABEL_MAXBIT)) 37 return -1; 38 return value; 39} 40 41static bool is_space_posix(int c) 42{ 43 return c == ' ' || c == '\f' || c == '\r' || c == '\t' || c == '\v'; 44} 45 46static char * trim_label(char *label) 47{ 48 char *end; 49 50 while (is_space_posix(*label)) 51 label++; 52 end = strchr(label, '\n'); 53 if (end) 54 *end = 0; 55 else 56 end = strchr(label, '\0'); 57 end--; 58 59 while (is_space_posix(*end) && end > label) { 60 *end = 0; 61 end--; 62 } 63 64 return *label ? label : NULL; 65} 66 67static void 68xtables_get_connlabel(uint16_t bit, char *buf, size_t len) 69{ 70 FILE *fp = fopen(CONNLABEL_CFG, "r"); 71 char label[1024]; 72 char *end; 73 74 if (!fp) 75 goto error; 76 77 while (fgets(label, sizeof(label), fp)) { 78 int tmp; 79 80 if (label[0] == '#') 81 continue; 82 tmp = xtables_parse_connlabel_numerical(label, &end); 83 if (tmp < 0 || tmp < (int) bit) 84 continue; 85 if (tmp > (int) bit) 86 break; 87 88 end = trim_label(end); 89 if (!end) 90 continue; 91 snprintf(buf, len, "%s", end); 92 fclose(fp); 93 return; 94 } 95 fclose(fp); 96 error: 97 snprintf(buf, len, "%u", (unsigned int) bit); 98} 99 100 101static uint16_t xtables_parse_connlabel(const char *s) 102{ 103 FILE *fp = fopen(CONNLABEL_CFG, "r"); 104 char label[1024]; 105 char *end; 106 int bit; 107 108 if (!fp) 109 xtables_error(PARAMETER_PROBLEM, "label '%s': could not open '%s': %s", 110 s, CONNLABEL_CFG, strerror(errno)); 111 112 while (fgets(label, sizeof(label), fp)) { 113 if (label[0] == '#' || !strstr(label, s)) 114 continue; 115 bit = xtables_parse_connlabel_numerical(label, &end); 116 if (bit < 0) 117 continue; 118 119 end = trim_label(end); 120 if (!end) 121 continue; 122 if (strcmp(end, s) == 0) { 123 fclose(fp); 124 return bit; 125 } 126 } 127 fclose(fp); 128 xtables_error(PARAMETER_PROBLEM, "label '%s' not found in config file %s", 129 s, CONNLABEL_CFG); 130} 131 132static void connlabel_mt_parse(struct xt_option_call *cb) 133{ 134 struct xt_connlabel_mtinfo *info = cb->data; 135 int tmp; 136 137 xtables_option_parse(cb); 138 139 switch (cb->entry->id) { 140 case O_LABEL: 141 tmp = xtables_parse_connlabel_numerical(cb->arg, NULL); 142 info->bit = tmp < 0 ? xtables_parse_connlabel(cb->arg) : tmp; 143 144 if (cb->invert) 145 info->options |= XT_CONNLABEL_OP_INVERT; 146 break; 147 case O_SET: 148 info->options |= XT_CONNLABEL_OP_SET; 149 break; 150 } 151 152} 153 154static void 155connlabel_mt_print_op(const struct xt_connlabel_mtinfo *info, const char *prefix) 156{ 157 if (info->options & XT_CONNLABEL_OP_SET) 158 printf(" %sset", prefix); 159} 160 161static void 162connlabel_mt_print(const void *ip, const struct xt_entry_match *match, int numeric) 163{ 164 const struct xt_connlabel_mtinfo *info = (const void *)match->data; 165 char buf[1024]; 166 167 printf(" connlabel"); 168 if (info->options & XT_CONNLABEL_OP_INVERT) 169 printf(" !"); 170 if (numeric) { 171 printf(" %u", info->bit); 172 } else { 173 xtables_get_connlabel(info->bit, buf, sizeof(buf)); 174 printf(" '%s'", buf); 175 } 176 connlabel_mt_print_op(info, ""); 177} 178 179static void 180connlabel_mt_save(const void *ip, const struct xt_entry_match *match) 181{ 182 const struct xt_connlabel_mtinfo *info = (const void *)match->data; 183 char buf[1024]; 184 185 if (info->options & XT_CONNLABEL_OP_INVERT) 186 printf(" !"); 187 188 xtables_get_connlabel(info->bit, buf, sizeof(buf)); 189 printf(" --label \"%s\"", buf); 190 191 connlabel_mt_print_op(info, "--"); 192} 193 194static struct xtables_match connlabel_mt_reg = { 195 .family = NFPROTO_UNSPEC, 196 .name = "connlabel", 197 .version = XTABLES_VERSION, 198 .size = XT_ALIGN(sizeof(struct xt_connlabel_mtinfo)), 199 .userspacesize = offsetof(struct xt_connlabel_mtinfo, bit), 200 .help = connlabel_mt_help, 201 .print = connlabel_mt_print, 202 .save = connlabel_mt_save, 203 .x6_parse = connlabel_mt_parse, 204 .x6_options = connlabel_mt_opts, 205}; 206 207void _init(void) 208{ 209 xtables_register_match(&connlabel_mt_reg); 210} 211