1 /* 2 * em_u32.c U32 Ematch 3 * 4 * This program is free software; you can distribute 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: Thomas Graf <tgraf (at) suug.ch> 10 */ 11 12 #include <stdio.h> 13 #include <stdlib.h> 14 #include <unistd.h> 15 #include <syslog.h> 16 #include <fcntl.h> 17 #include <sys/socket.h> 18 #include <netinet/in.h> 19 #include <arpa/inet.h> 20 #include <string.h> 21 #include <errno.h> 22 23 #include "m_ematch.h" 24 25 extern struct ematch_util u32_ematch_util; 26 27 static void u32_print_usage(FILE *fd) 28 { 29 fprintf(fd, 30 "Usage: u32(ALIGN VALUE MASK at [ nexthdr+ ] OFFSET)\n" \ 31 "where: ALIGN := { u8 | u16 | u32 }\n" \ 32 "\n" \ 33 "Example: u32(u16 0x1122 0xffff at nexthdr+4)\n"); 34 } 35 36 static int u32_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr, 37 struct bstr *args) 38 { 39 struct bstr *a; 40 int align, nh_len; 41 unsigned long key, mask, offmask = 0, offset; 42 struct tc_u32_key u_key = {}; 43 44 #define PARSE_ERR(CARG, FMT, ARGS...) \ 45 em_parse_error(EINVAL, args, CARG, &u32_ematch_util, FMT, ##ARGS) 46 47 if (args == NULL) 48 return PARSE_ERR(args, "u32: missing arguments"); 49 50 if (!bstrcmp(args, "u8")) 51 align = 1; 52 else if (!bstrcmp(args, "u16")) 53 align = 2; 54 else if (!bstrcmp(args, "u32")) 55 align = 4; 56 else 57 return PARSE_ERR(args, "u32: invalid alignment"); 58 59 a = bstr_next(args); 60 if (a == NULL) 61 return PARSE_ERR(a, "u32: missing key"); 62 63 key = bstrtoul(a); 64 if (key == ULONG_MAX) 65 return PARSE_ERR(a, "u32: invalid key, must be numeric"); 66 67 a = bstr_next(a); 68 if (a == NULL) 69 return PARSE_ERR(a, "u32: missing mask"); 70 71 mask = bstrtoul(a); 72 if (mask == ULONG_MAX) 73 return PARSE_ERR(a, "u32: invalid mask, must be numeric"); 74 75 a = bstr_next(a); 76 if (a == NULL || bstrcmp(a, "at") != 0) 77 return PARSE_ERR(a, "u32: missing \"at\""); 78 79 a = bstr_next(a); 80 if (a == NULL) 81 return PARSE_ERR(a, "u32: missing offset"); 82 83 nh_len = strlen("nexthdr+"); 84 if (a->len > nh_len && !memcmp(a->data, "nexthdr+", nh_len)) { 85 char buf[a->len - nh_len + 1]; 86 87 offmask = -1; 88 memcpy(buf, a->data + nh_len, a->len - nh_len); 89 offset = strtoul(buf, NULL, 0); 90 } else if (!bstrcmp(a, "nexthdr+")) { 91 a = bstr_next(a); 92 if (a == NULL) 93 return PARSE_ERR(a, "u32: missing offset"); 94 offset = bstrtoul(a); 95 } else 96 offset = bstrtoul(a); 97 98 if (offset == ULONG_MAX) 99 return PARSE_ERR(a, "u32: invalid offset"); 100 101 if (a->next) 102 return PARSE_ERR(a->next, "u32: unexpected trailer"); 103 104 switch (align) { 105 case 1: 106 if (key > 0xFF) 107 return PARSE_ERR(a, "Illegal key (>0xFF)"); 108 if (mask > 0xFF) 109 return PARSE_ERR(a, "Illegal mask (>0xFF)"); 110 111 key <<= 24 - ((offset & 3) * 8); 112 mask <<= 24 - ((offset & 3) * 8); 113 offset &= ~3; 114 break; 115 116 case 2: 117 if (key > 0xFFFF) 118 return PARSE_ERR(a, "Illegal key (>0xFFFF)"); 119 if (mask > 0xFFFF) 120 return PARSE_ERR(a, "Illegal mask (>0xFFFF)"); 121 122 if ((offset & 3) == 0) { 123 key <<= 16; 124 mask <<= 16; 125 } 126 offset &= ~3; 127 break; 128 } 129 130 key = htonl(key); 131 mask = htonl(mask); 132 133 if (offset % 4) 134 return PARSE_ERR(a, "u32: invalid offset alignment, " \ 135 "must be aligned to 4."); 136 137 key &= mask; 138 139 u_key.mask = mask; 140 u_key.val = key; 141 u_key.off = offset; 142 u_key.offmask = offmask; 143 144 addraw_l(n, MAX_MSG, hdr, sizeof(*hdr)); 145 addraw_l(n, MAX_MSG, &u_key, sizeof(u_key)); 146 147 #undef PARSE_ERR 148 return 0; 149 } 150 151 static int u32_print_eopt(FILE *fd, struct tcf_ematch_hdr *hdr, void *data, 152 int data_len) 153 { 154 struct tc_u32_key *u_key = data; 155 156 if (data_len < sizeof(*u_key)) { 157 fprintf(stderr, "U32 header size mismatch\n"); 158 return -1; 159 } 160 161 fprintf(fd, "%08x/%08x at %s%d", 162 (unsigned int) ntohl(u_key->val), 163 (unsigned int) ntohl(u_key->mask), 164 u_key->offmask ? "nexthdr+" : "", 165 u_key->off); 166 167 return 0; 168 } 169 170 struct ematch_util u32_ematch_util = { 171 .kind = "u32", 172 .kind_num = TCF_EM_U32, 173 .parse_eopt = u32_parse_eopt, 174 .print_eopt = u32_print_eopt, 175 .print_usage = u32_print_usage 176 }; 177