1 /* 2 * m_xt.c xtables based targets 3 * utilities mostly ripped from iptables <duh, its the linux way> 4 * 5 * This program is free software; you can distribute it and/or 6 * modify it under the terms of the GNU General Public License 7 * as published by the Free Software Foundation; either version 8 * 2 of the License, or (at your option) any later version. 9 * 10 * Authors: J Hadi Salim (hadi (at) cyberus.ca) 11 */ 12 13 #include <syslog.h> 14 #include <sys/socket.h> 15 #include <netinet/in.h> 16 #include <arpa/inet.h> 17 #include <net/if.h> 18 #include <limits.h> 19 #include <linux/netfilter.h> 20 #include <linux/netfilter_ipv4/ip_tables.h> 21 #include <xtables.h> 22 #include "utils.h" 23 #include "tc_util.h" 24 #include <linux/tc_act/tc_ipt.h> 25 #include <stdio.h> 26 #include <dlfcn.h> 27 #include <getopt.h> 28 #include <errno.h> 29 #include <string.h> 30 #include <netdb.h> 31 #include <stdlib.h> 32 #include <ctype.h> 33 #include <stdarg.h> 34 #include <unistd.h> 35 #include <fcntl.h> 36 #include <sys/wait.h> 37 #ifndef XT_LIB_DIR 38 # define XT_LIB_DIR "/lib/xtables" 39 #endif 40 41 #ifndef __ALIGN_KERNEL 42 #define __ALIGN_KERNEL(x, a) \ 43 __ALIGN_KERNEL_MASK(x, (typeof(x))(a) - 1) 44 #define __ALIGN_KERNEL_MASK(x, mask) \ 45 (((x) + (mask)) & ~(mask)) 46 #endif 47 48 #ifndef ALIGN 49 #define ALIGN(x, a) __ALIGN_KERNEL((x), (a)) 50 #endif 51 52 static const char *tname = "mangle"; 53 54 char *lib_dir; 55 56 static const char * const ipthooks[] = { 57 "NF_IP_PRE_ROUTING", 58 "NF_IP_LOCAL_IN", 59 "NF_IP_FORWARD", 60 "NF_IP_LOCAL_OUT", 61 "NF_IP_POST_ROUTING", 62 }; 63 64 static struct option original_opts[] = { 65 { 66 .name = "jump", 67 .has_arg = 1, 68 .val = 'j' 69 }, 70 {0, 0, 0, 0} 71 }; 72 73 static struct xtables_globals tcipt_globals = { 74 .option_offset = 0, 75 .program_name = "tc-ipt", 76 .program_version = "0.2", 77 .orig_opts = original_opts, 78 .opts = original_opts, 79 .exit_err = NULL, 80 #if XTABLES_VERSION_CODE >= 11 81 .compat_rev = xtables_compatible_revision, 82 #endif 83 }; 84 85 /* 86 * we may need to check for version mismatch 87 */ 88 static int 89 build_st(struct xtables_target *target, struct xt_entry_target *t) 90 { 91 92 size_t size = 93 XT_ALIGN(sizeof(struct xt_entry_target)) + target->size; 94 95 if (t == NULL) { 96 target->t = xtables_calloc(1, size); 97 target->t->u.target_size = size; 98 strncpy(target->t->u.user.name, target->name, 99 sizeof(target->t->u.user.name) - 1); 100 target->t->u.user.revision = target->revision; 101 102 if (target->init != NULL) 103 target->init(target->t); 104 } else { 105 target->t = t; 106 } 107 return 0; 108 109 } 110 111 static void set_lib_dir(void) 112 { 113 114 lib_dir = getenv("XTABLES_LIBDIR"); 115 if (!lib_dir) { 116 lib_dir = getenv("IPTABLES_LIB_DIR"); 117 if (lib_dir) 118 fprintf(stderr, "using deprecated IPTABLES_LIB_DIR\n"); 119 } 120 if (lib_dir == NULL) 121 lib_dir = XT_LIB_DIR; 122 123 } 124 125 static int get_xtables_target_opts(struct xtables_globals *globals, 126 struct xtables_target *m) 127 { 128 struct option *opts; 129 130 #if XTABLES_VERSION_CODE >= 6 131 opts = xtables_options_xfrm(globals->orig_opts, 132 globals->opts, 133 m->x6_options, 134 &m->option_offset); 135 #else 136 opts = xtables_merge_options(globals->opts, 137 m->extra_opts, 138 &m->option_offset); 139 #endif 140 if (!opts) 141 return -1; 142 globals->opts = opts; 143 return 0; 144 } 145 146 static int parse_ipt(struct action_util *a, int *argc_p, 147 char ***argv_p, int tca_id, struct nlmsghdr *n) 148 { 149 struct xtables_target *m = NULL; 150 #if XTABLES_VERSION_CODE >= 6 151 struct ipt_entry fw = {}; 152 #endif 153 struct rtattr *tail; 154 155 int c; 156 char **argv = *argv_p; 157 int argc; 158 char k[16]; 159 int size = 0; 160 int iok = 0, ok = 0; 161 __u32 hook = 0, index = 0; 162 163 /* copy tcipt_globals because .opts will be modified by iptables */ 164 struct xtables_globals tmp_tcipt_globals = tcipt_globals; 165 166 xtables_init_all(&tmp_tcipt_globals, NFPROTO_IPV4); 167 set_lib_dir(); 168 169 /* parse only up until the next action */ 170 for (argc = 0; argc < *argc_p; argc++) { 171 if (!argv[argc] || !strcmp(argv[argc], "action")) 172 break; 173 } 174 175 if (argc <= 2) { 176 fprintf(stderr, 177 "too few arguments for xt, need at least '-j <target>'\n"); 178 return -1; 179 } 180 181 while (1) { 182 c = getopt_long(argc, argv, "j:", tmp_tcipt_globals.opts, NULL); 183 if (c == -1) 184 break; 185 switch (c) { 186 case 'j': 187 m = xtables_find_target(optarg, XTF_TRY_LOAD); 188 if (!m) { 189 fprintf(stderr, 190 " failed to find target %s\n\n", 191 optarg); 192 return -1; 193 } 194 195 if (build_st(m, NULL) < 0) { 196 printf(" %s error\n", m->name); 197 return -1; 198 } 199 200 if (get_xtables_target_opts(&tmp_tcipt_globals, 201 m) < 0) { 202 fprintf(stderr, 203 " failed to find additional options for target %s\n\n", 204 optarg); 205 return -1; 206 } 207 ok++; 208 break; 209 210 default: 211 #if XTABLES_VERSION_CODE >= 6 212 if (m != NULL && m->x6_parse != NULL) { 213 xtables_option_tpcall(c, argv, 0, m, &fw); 214 #else 215 if (m != NULL && m->parse != NULL) { 216 m->parse(c - m->option_offset, argv, 0, 217 &m->tflags, NULL, &m->t); 218 #endif 219 } else { 220 fprintf(stderr, 221 "failed to find target %s\n\n", optarg); 222 return -1; 223 224 } 225 ok++; 226 break; 227 } 228 } 229 230 if (argc > optind) { 231 if (matches(argv[optind], "index") == 0) { 232 if (get_u32(&index, argv[optind + 1], 10)) { 233 fprintf(stderr, "Illegal \"index\"\n"); 234 xtables_free_opts(1); 235 return -1; 236 } 237 iok++; 238 239 optind += 2; 240 } 241 } 242 243 if (!ok && !iok) { 244 fprintf(stderr, " ipt Parser BAD!! (%s)\n", *argv); 245 return -1; 246 } 247 248 /* check that we passed the correct parameters to the target */ 249 #if XTABLES_VERSION_CODE >= 6 250 if (m) 251 xtables_option_tfcall(m); 252 #else 253 if (m && m->final_check) 254 m->final_check(m->tflags); 255 #endif 256 257 { 258 struct tcmsg *t = NLMSG_DATA(n); 259 260 if (t->tcm_parent != TC_H_ROOT 261 && t->tcm_parent == TC_H_MAJ(TC_H_INGRESS)) { 262 hook = NF_IP_PRE_ROUTING; 263 } else { 264 hook = NF_IP_POST_ROUTING; 265 } 266 } 267 268 tail = NLMSG_TAIL(n); 269 addattr_l(n, MAX_MSG, tca_id, NULL, 0); 270 fprintf(stdout, "tablename: %s hook: %s\n ", tname, ipthooks[hook]); 271 fprintf(stdout, "\ttarget: "); 272 273 if (m) { 274 if (m->print) 275 m->print(NULL, m->t, 0); 276 else 277 printf("%s ", m->name); 278 } 279 fprintf(stdout, " index %d\n", index); 280 281 if (strlen(tname) >= 16) { 282 size = 15; 283 k[15] = 0; 284 } else { 285 size = 1 + strlen(tname); 286 } 287 strncpy(k, tname, size); 288 289 addattr_l(n, MAX_MSG, TCA_IPT_TABLE, k, size); 290 addattr_l(n, MAX_MSG, TCA_IPT_HOOK, &hook, 4); 291 addattr_l(n, MAX_MSG, TCA_IPT_INDEX, &index, 4); 292 if (m) 293 addattr_l(n, MAX_MSG, TCA_IPT_TARG, m->t, m->t->u.target_size); 294 tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; 295 296 argv += optind; 297 *argc_p -= argc; 298 *argv_p = argv; 299 300 optind = 0; 301 xtables_free_opts(1); 302 303 if (m) { 304 /* Clear flags if target will be used again */ 305 m->tflags = 0; 306 m->used = 0; 307 /* Free allocated memory */ 308 if (m->t) 309 free(m->t); 310 } 311 312 return 0; 313 314 } 315 316 static int 317 print_ipt(struct action_util *au, FILE *f, struct rtattr *arg) 318 { 319 struct xtables_target *m; 320 struct rtattr *tb[TCA_IPT_MAX + 1]; 321 struct xt_entry_target *t = NULL; 322 323 if (arg == NULL) 324 return -1; 325 326 /* copy tcipt_globals because .opts will be modified by iptables */ 327 struct xtables_globals tmp_tcipt_globals = tcipt_globals; 328 329 xtables_init_all(&tmp_tcipt_globals, NFPROTO_IPV4); 330 set_lib_dir(); 331 332 parse_rtattr_nested(tb, TCA_IPT_MAX, arg); 333 334 if (tb[TCA_IPT_TABLE] == NULL) { 335 fprintf(f, "[NULL ipt table name ] assuming mangle "); 336 } else { 337 fprintf(f, "tablename: %s ", 338 rta_getattr_str(tb[TCA_IPT_TABLE])); 339 } 340 341 if (tb[TCA_IPT_HOOK] == NULL) { 342 fprintf(f, "[NULL ipt hook name ]\n "); 343 return -1; 344 } else { 345 __u32 hook; 346 347 hook = rta_getattr_u32(tb[TCA_IPT_HOOK]); 348 fprintf(f, " hook: %s\n", ipthooks[hook]); 349 } 350 351 if (tb[TCA_IPT_TARG] == NULL) { 352 fprintf(f, "\t[NULL ipt target parameters ]\n"); 353 return -1; 354 } 355 356 t = RTA_DATA(tb[TCA_IPT_TARG]); 357 m = xtables_find_target(t->u.user.name, XTF_TRY_LOAD); 358 if (!m) { 359 fprintf(stderr, " failed to find target %s\n\n", 360 t->u.user.name); 361 return -1; 362 } 363 if (build_st(m, t) < 0) { 364 fprintf(stderr, " %s error\n", m->name); 365 return -1; 366 } 367 368 if (get_xtables_target_opts(&tmp_tcipt_globals, m) < 0) { 369 fprintf(stderr, 370 " failed to find additional options for target %s\n\n", 371 t->u.user.name); 372 return -1; 373 } 374 fprintf(f, "\ttarget "); 375 m->print(NULL, m->t, 0); 376 if (tb[TCA_IPT_INDEX] == NULL) { 377 fprintf(f, " [NULL ipt target index ]\n"); 378 } else { 379 __u32 index; 380 381 index = rta_getattr_u32(tb[TCA_IPT_INDEX]); 382 fprintf(f, "\n\tindex %u", index); 383 } 384 385 if (tb[TCA_IPT_CNT]) { 386 struct tc_cnt *c = RTA_DATA(tb[TCA_IPT_CNT]); 387 388 fprintf(f, " ref %d bind %d", c->refcnt, c->bindcnt); 389 } 390 if (show_stats) { 391 if (tb[TCA_IPT_TM]) { 392 struct tcf_t *tm = RTA_DATA(tb[TCA_IPT_TM]); 393 394 print_tm(f, tm); 395 } 396 } 397 fprintf(f, "\n"); 398 399 xtables_free_opts(1); 400 401 return 0; 402 } 403 404 struct action_util xt_action_util = { 405 .id = "xt", 406 .parse_aopt = parse_ipt, 407 .print_aopt = print_ipt, 408 }; 409