1 /* 2 * f_flow.c Flow filter 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 7 * 2 of the License, or (at your option) any later version. 8 * 9 * Authors: Patrick McHardy <kaber (at) trash.net> 10 */ 11 #include <stdio.h> 12 #include <stdlib.h> 13 #include <unistd.h> 14 #include <string.h> 15 #include <errno.h> 16 17 #include "utils.h" 18 #include "tc_util.h" 19 #include "m_ematch.h" 20 21 static void explain(void) 22 { 23 fprintf(stderr, 24 "Usage: ... flow ...\n" 25 "\n" 26 " [mapping mode]: map key KEY [ OPS ] ...\n" 27 " [hashing mode]: hash keys KEY-LIST ... [ perturb SECS ]\n" 28 "\n" 29 " [ divisor NUM ] [ baseclass ID ] [ match EMATCH_TREE ]\n" 30 " [ police POLICE_SPEC ] [ action ACTION_SPEC ]\n" 31 "\n" 32 "KEY-LIST := [ KEY-LIST , ] KEY\n" 33 "KEY := [ src | dst | proto | proto-src | proto-dst | iif | priority | \n" 34 " mark | nfct | nfct-src | nfct-dst | nfct-proto-src | \n" 35 " nfct-proto-dst | rt-classid | sk-uid | sk-gid |\n" 36 " vlan-tag ]\n" 37 "OPS := [ or NUM | and NUM | xor NUM | rshift NUM | addend NUM ]\n" 38 "ID := X:Y\n" 39 ); 40 } 41 42 static const char *flow_keys[FLOW_KEY_MAX+1] = { 43 [FLOW_KEY_SRC] = "src", 44 [FLOW_KEY_DST] = "dst", 45 [FLOW_KEY_PROTO] = "proto", 46 [FLOW_KEY_PROTO_SRC] = "proto-src", 47 [FLOW_KEY_PROTO_DST] = "proto-dst", 48 [FLOW_KEY_IIF] = "iif", 49 [FLOW_KEY_PRIORITY] = "priority", 50 [FLOW_KEY_MARK] = "mark", 51 [FLOW_KEY_NFCT] = "nfct", 52 [FLOW_KEY_NFCT_SRC] = "nfct-src", 53 [FLOW_KEY_NFCT_DST] = "nfct-dst", 54 [FLOW_KEY_NFCT_PROTO_SRC] = "nfct-proto-src", 55 [FLOW_KEY_NFCT_PROTO_DST] = "nfct-proto-dst", 56 [FLOW_KEY_RTCLASSID] = "rt-classid", 57 [FLOW_KEY_SKUID] = "sk-uid", 58 [FLOW_KEY_SKGID] = "sk-gid", 59 [FLOW_KEY_VLAN_TAG] = "vlan-tag", 60 }; 61 62 static int flow_parse_keys(__u32 *keys, __u32 *nkeys, char *argv) 63 { 64 char *s, *sep; 65 unsigned int i; 66 67 *keys = 0; 68 *nkeys = 0; 69 s = argv; 70 while (s != NULL) { 71 sep = strchr(s, ','); 72 if (sep) 73 *sep = '\0'; 74 75 for (i = 0; i <= FLOW_KEY_MAX; i++) { 76 if (matches(s, flow_keys[i]) == 0) { 77 *keys |= 1 << i; 78 (*nkeys)++; 79 break; 80 } 81 } 82 if (i > FLOW_KEY_MAX) { 83 fprintf(stderr, "Unknown flow key \"%s\"\n", s); 84 return -1; 85 } 86 s = sep ? sep + 1 : NULL; 87 } 88 return 0; 89 } 90 91 static void transfer_bitop(__u32 *mask, __u32 *xor, __u32 m, __u32 x) 92 { 93 *xor = x ^ (*xor & m); 94 *mask &= m; 95 } 96 97 static int get_addend(__u32 *addend, char *argv, __u32 keys) 98 { 99 inet_prefix addr; 100 int sign = 0; 101 __u32 tmp; 102 103 if (*argv == '-') { 104 sign = 1; 105 argv++; 106 } 107 108 if (get_u32(&tmp, argv, 0) == 0) 109 goto out; 110 111 if (keys & (FLOW_KEY_SRC | FLOW_KEY_DST | 112 FLOW_KEY_NFCT_SRC | FLOW_KEY_NFCT_DST) && 113 get_addr(&addr, argv, AF_UNSPEC) == 0) { 114 switch (addr.family) { 115 case AF_INET: 116 tmp = ntohl(addr.data[0]); 117 goto out; 118 case AF_INET6: 119 tmp = ntohl(addr.data[3]); 120 goto out; 121 } 122 } 123 124 return -1; 125 out: 126 if (sign) 127 tmp = -tmp; 128 *addend = tmp; 129 return 0; 130 } 131 132 static int flow_parse_opt(struct filter_util *fu, char *handle, 133 int argc, char **argv, struct nlmsghdr *n) 134 { 135 struct tc_police tp; 136 struct tcmsg *t = NLMSG_DATA(n); 137 struct rtattr *tail; 138 __u32 mask = ~0U, xor = 0; 139 __u32 keys = 0, nkeys = 0; 140 __u32 mode = FLOW_MODE_MAP; 141 __u32 tmp; 142 143 memset(&tp, 0, sizeof(tp)); 144 145 if (handle) { 146 if (get_u32(&t->tcm_handle, handle, 0)) { 147 fprintf(stderr, "Illegal \"handle\"\n"); 148 return -1; 149 } 150 } 151 152 tail = NLMSG_TAIL(n); 153 addattr_l(n, 4096, TCA_OPTIONS, NULL, 0); 154 155 while (argc > 0) { 156 if (matches(*argv, "map") == 0) { 157 mode = FLOW_MODE_MAP; 158 } else if (matches(*argv, "hash") == 0) { 159 mode = FLOW_MODE_HASH; 160 } else if (matches(*argv, "keys") == 0) { 161 NEXT_ARG(); 162 if (flow_parse_keys(&keys, &nkeys, *argv)) 163 return -1; 164 addattr32(n, 4096, TCA_FLOW_KEYS, keys); 165 } else if (matches(*argv, "and") == 0) { 166 NEXT_ARG(); 167 if (get_u32(&tmp, *argv, 0)) { 168 fprintf(stderr, "Illegal \"mask\"\n"); 169 return -1; 170 } 171 transfer_bitop(&mask, &xor, tmp, 0); 172 } else if (matches(*argv, "or") == 0) { 173 NEXT_ARG(); 174 if (get_u32(&tmp, *argv, 0)) { 175 fprintf(stderr, "Illegal \"or\"\n"); 176 return -1; 177 } 178 transfer_bitop(&mask, &xor, ~tmp, tmp); 179 } else if (matches(*argv, "xor") == 0) { 180 NEXT_ARG(); 181 if (get_u32(&tmp, *argv, 0)) { 182 fprintf(stderr, "Illegal \"xor\"\n"); 183 return -1; 184 } 185 transfer_bitop(&mask, &xor, ~0, tmp); 186 } else if (matches(*argv, "rshift") == 0) { 187 NEXT_ARG(); 188 if (get_u32(&tmp, *argv, 0)) { 189 fprintf(stderr, "Illegal \"rshift\"\n"); 190 return -1; 191 } 192 addattr32(n, 4096, TCA_FLOW_RSHIFT, tmp); 193 } else if (matches(*argv, "addend") == 0) { 194 NEXT_ARG(); 195 if (get_addend(&tmp, *argv, keys)) { 196 fprintf(stderr, "Illegal \"addend\"\n"); 197 return -1; 198 } 199 addattr32(n, 4096, TCA_FLOW_ADDEND, tmp); 200 } else if (matches(*argv, "divisor") == 0) { 201 NEXT_ARG(); 202 if (get_u32(&tmp, *argv, 0)) { 203 fprintf(stderr, "Illegal \"divisor\"\n"); 204 return -1; 205 } 206 addattr32(n, 4096, TCA_FLOW_DIVISOR, tmp); 207 } else if (matches(*argv, "baseclass") == 0) { 208 NEXT_ARG(); 209 if (get_tc_classid(&tmp, *argv) || TC_H_MIN(tmp) == 0) { 210 fprintf(stderr, "Illegal \"baseclass\"\n"); 211 return -1; 212 } 213 addattr32(n, 4096, TCA_FLOW_BASECLASS, tmp); 214 } else if (matches(*argv, "perturb") == 0) { 215 NEXT_ARG(); 216 if (get_u32(&tmp, *argv, 0)) { 217 fprintf(stderr, "Illegal \"perturb\"\n"); 218 return -1; 219 } 220 addattr32(n, 4096, TCA_FLOW_PERTURB, tmp); 221 } else if (matches(*argv, "police") == 0) { 222 NEXT_ARG(); 223 if (parse_police(&argc, &argv, TCA_FLOW_POLICE, n)) { 224 fprintf(stderr, "Illegal \"police\"\n"); 225 return -1; 226 } 227 continue; 228 } else if (matches(*argv, "action") == 0) { 229 NEXT_ARG(); 230 if (parse_action(&argc, &argv, TCA_FLOW_ACT, n)) { 231 fprintf(stderr, "Illegal \"action\"\n"); 232 return -1; 233 } 234 continue; 235 } else if (matches(*argv, "match") == 0) { 236 NEXT_ARG(); 237 if (parse_ematch(&argc, &argv, TCA_FLOW_EMATCHES, n)) { 238 fprintf(stderr, "Illegal \"ematch\"\n"); 239 return -1; 240 } 241 continue; 242 } else if (matches(*argv, "help") == 0) { 243 explain(); 244 return -1; 245 } else { 246 fprintf(stderr, "What is \"%s\"?\n", *argv); 247 explain(); 248 return -1; 249 } 250 argv++, argc--; 251 } 252 253 if (nkeys > 1 && mode != FLOW_MODE_HASH) { 254 fprintf(stderr, "Invalid mode \"map\" for multiple keys\n"); 255 return -1; 256 } 257 addattr32(n, 4096, TCA_FLOW_MODE, mode); 258 259 if (mask != ~0 || xor != 0) { 260 addattr32(n, 4096, TCA_FLOW_MASK, mask); 261 addattr32(n, 4096, TCA_FLOW_XOR, xor); 262 } 263 264 tail->rta_len = (void *)NLMSG_TAIL(n) - (void *)tail; 265 return 0; 266 } 267 268 static int flow_print_opt(struct filter_util *fu, FILE *f, struct rtattr *opt, 269 __u32 handle) 270 { 271 struct rtattr *tb[TCA_FLOW_MAX+1]; 272 SPRINT_BUF(b1); 273 unsigned int i; 274 __u32 mask = ~0, val = 0; 275 276 if (opt == NULL) 277 return -EINVAL; 278 279 parse_rtattr_nested(tb, TCA_FLOW_MAX, opt); 280 281 fprintf(f, "handle 0x%x ", handle); 282 283 if (tb[TCA_FLOW_MODE]) { 284 __u32 mode = *(__u32 *)RTA_DATA(tb[TCA_FLOW_MODE]); 285 286 switch (mode) { 287 case FLOW_MODE_MAP: 288 fprintf(f, "map "); 289 break; 290 case FLOW_MODE_HASH: 291 fprintf(f, "hash "); 292 break; 293 } 294 } 295 296 if (tb[TCA_FLOW_KEYS]) { 297 __u32 keymask = *(__u32 *)RTA_DATA(tb[TCA_FLOW_KEYS]); 298 char *sep = ""; 299 300 fprintf(f, "keys "); 301 for (i = 0; i <= FLOW_KEY_MAX; i++) { 302 if (keymask & (1 << i)) { 303 fprintf(f, "%s%s", sep, flow_keys[i]); 304 sep = ","; 305 } 306 } 307 fprintf(f, " "); 308 } 309 310 if (tb[TCA_FLOW_MASK]) 311 mask = *(__u32 *)RTA_DATA(tb[TCA_FLOW_MASK]); 312 if (tb[TCA_FLOW_XOR]) 313 val = *(__u32 *)RTA_DATA(tb[TCA_FLOW_XOR]); 314 315 if (mask != ~0 || val != 0) { 316 __u32 or = (mask & val) ^ val; 317 __u32 xor = mask & val; 318 319 if (mask != ~0) 320 fprintf(f, "and 0x%.8x ", mask); 321 if (xor != 0) 322 fprintf(f, "xor 0x%.8x ", xor); 323 if (or != 0) 324 fprintf(f, "or 0x%.8x ", or); 325 } 326 327 if (tb[TCA_FLOW_RSHIFT]) 328 fprintf(f, "rshift %u ", 329 *(__u32 *)RTA_DATA(tb[TCA_FLOW_RSHIFT])); 330 if (tb[TCA_FLOW_ADDEND]) 331 fprintf(f, "addend 0x%x ", 332 *(__u32 *)RTA_DATA(tb[TCA_FLOW_ADDEND])); 333 334 if (tb[TCA_FLOW_DIVISOR]) 335 fprintf(f, "divisor %u ", 336 *(__u32 *)RTA_DATA(tb[TCA_FLOW_DIVISOR])); 337 if (tb[TCA_FLOW_BASECLASS]) 338 fprintf(f, "baseclass %s ", 339 sprint_tc_classid(*(__u32 *)RTA_DATA(tb[TCA_FLOW_BASECLASS]), b1)); 340 341 if (tb[TCA_FLOW_PERTURB]) 342 fprintf(f, "perturb %usec ", 343 *(__u32 *)RTA_DATA(tb[TCA_FLOW_PERTURB])); 344 345 if (tb[TCA_FLOW_EMATCHES]) 346 print_ematch(f, tb[TCA_FLOW_EMATCHES]); 347 if (tb[TCA_FLOW_POLICE]) 348 tc_print_police(f, tb[TCA_FLOW_POLICE]); 349 if (tb[TCA_FLOW_ACT]) { 350 fprintf(f, "\n"); 351 tc_print_action(f, tb[TCA_FLOW_ACT]); 352 } 353 return 0; 354 } 355 356 struct filter_util flow_filter_util = { 357 .id = "flow", 358 .parse_fopt = flow_parse_opt, 359 .print_fopt = flow_print_opt, 360 }; 361