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 #include <libnetfilter_conntrack/libnetfilter_conntrack.h> 9 10 enum { 11 O_LABEL = 0, 12 O_SET = 1, 13 }; 14 15 static struct nfct_labelmap *map; 16 17 static void connlabel_mt_help(void) 18 { 19 puts( 20 "connlabel match options:\n" 21 "[!] --label name Match if label has been set on connection\n" 22 " --set Set label on connection"); 23 } 24 25 static const struct xt_option_entry connlabel_mt_opts[] = { 26 {.name = "label", .id = O_LABEL, .type = XTTYPE_STRING, 27 .min = 1, .flags = XTOPT_MAND|XTOPT_INVERT}, 28 {.name = "set", .id = O_SET, .type = XTTYPE_NONE}, 29 XTOPT_TABLEEND, 30 }; 31 32 /* cannot do this via _init, else static builds might spew error message 33 * for every iptables invocation. 34 */ 35 static void connlabel_open(void) 36 { 37 const char *fname; 38 39 if (map) 40 return; 41 42 map = nfct_labelmap_new(NULL); 43 if (map != NULL) 44 return; 45 46 fname = nfct_labels_get_path(); 47 if (errno) { 48 xtables_error(RESOURCE_PROBLEM, 49 "cannot open %s: %s", fname, strerror(errno)); 50 } else { 51 xtables_error(RESOURCE_PROBLEM, 52 "cannot parse %s: no labels found", fname); 53 } 54 } 55 56 static void connlabel_mt_parse(struct xt_option_call *cb) 57 { 58 struct xt_connlabel_mtinfo *info = cb->data; 59 int tmp; 60 61 connlabel_open(); 62 xtables_option_parse(cb); 63 64 switch (cb->entry->id) { 65 case O_LABEL: 66 tmp = nfct_labelmap_get_bit(map, cb->arg); 67 if (tmp < 0) 68 xtables_error(PARAMETER_PROBLEM, "label '%s' not found", cb->arg); 69 info->bit = tmp; 70 if (cb->invert) 71 info->options |= XT_CONNLABEL_OP_INVERT; 72 break; 73 case O_SET: 74 info->options |= XT_CONNLABEL_OP_SET; 75 break; 76 } 77 78 } 79 80 static const char *connlabel_get_name(int b) 81 { 82 const char *name; 83 84 connlabel_open(); 85 86 name = nfct_labelmap_get_name(map, b); 87 if (name && strcmp(name, "")) 88 return name; 89 return NULL; 90 } 91 92 static void 93 connlabel_mt_print_op(const struct xt_connlabel_mtinfo *info, const char *prefix) 94 { 95 if (info->options & XT_CONNLABEL_OP_SET) 96 printf(" %sset", prefix); 97 } 98 99 static void 100 connlabel_mt_print(const void *ip, const struct xt_entry_match *match, int numeric) 101 { 102 const struct xt_connlabel_mtinfo *info = (const void *)match->data; 103 const char *name = connlabel_get_name(info->bit); 104 105 printf(" connlabel"); 106 if (info->options & XT_CONNLABEL_OP_INVERT) 107 printf(" !"); 108 if (numeric || name == NULL) { 109 printf(" %u", info->bit); 110 } else { 111 printf(" '%s'", name); 112 } 113 connlabel_mt_print_op(info, ""); 114 } 115 116 static void 117 connlabel_mt_save(const void *ip, const struct xt_entry_match *match) 118 { 119 const struct xt_connlabel_mtinfo *info = (const void *)match->data; 120 const char *name = connlabel_get_name(info->bit); 121 122 if (info->options & XT_CONNLABEL_OP_INVERT) 123 printf(" !"); 124 if (name) 125 printf(" --label \"%s\"", name); 126 else 127 printf(" --label \"%u\"", info->bit); 128 connlabel_mt_print_op(info, "--"); 129 } 130 131 static int connlabel_mt_xlate(struct xt_xlate *xl, 132 const struct xt_xlate_mt_params *params) 133 { 134 const struct xt_connlabel_mtinfo *info = 135 (const void *)params->match->data; 136 const char *name = connlabel_get_name(info->bit); 137 138 if (name == NULL) 139 return 0; 140 141 if (info->options & XT_CONNLABEL_OP_SET) 142 xt_xlate_add(xl, "ct label set %s ", name); 143 144 xt_xlate_add(xl, "ct label "); 145 if (info->options & XT_CONNLABEL_OP_INVERT) 146 xt_xlate_add(xl, "and %s != ", name); 147 xt_xlate_add(xl, "%s", name); 148 149 return 1; 150 } 151 152 static struct xtables_match connlabel_mt_reg = { 153 .family = NFPROTO_UNSPEC, 154 .name = "connlabel", 155 .version = XTABLES_VERSION, 156 .size = XT_ALIGN(sizeof(struct xt_connlabel_mtinfo)), 157 .userspacesize = offsetof(struct xt_connlabel_mtinfo, bit), 158 .help = connlabel_mt_help, 159 .print = connlabel_mt_print, 160 .save = connlabel_mt_save, 161 .x6_parse = connlabel_mt_parse, 162 .x6_options = connlabel_mt_opts, 163 .xlate = connlabel_mt_xlate, 164 }; 165 166 void _init(void) 167 { 168 xtables_register_match(&connlabel_mt_reg); 169 } 170