1/* ebt_ip 2 * 3 * Authors: 4 * Bart De Schuymer <bdschuym@pandora.be> 5 * 6 * Changes: 7 * added ip-sport and ip-dport; parsing of port arguments is 8 * based on code from iptables-1.2.7a 9 * Innominate Security Technologies AG <mhopf@innominate.com> 10 * September, 2002 11 */ 12 13#include <stdio.h> 14#include <stdlib.h> 15#include <string.h> 16#include <getopt.h> 17#include <netdb.h> 18#include "../include/ebtables_u.h" 19#include <linux/netfilter_bridge/ebt_ip.h> 20 21#define IP_SOURCE '1' 22#define IP_DEST '2' 23#define IP_myTOS '3' /* include/bits/in.h seems to already define IP_TOS */ 24#define IP_PROTO '4' 25#define IP_SPORT '5' 26#define IP_DPORT '6' 27 28static struct option opts[] = 29{ 30 { "ip-source" , required_argument, 0, IP_SOURCE }, 31 { "ip-src" , required_argument, 0, IP_SOURCE }, 32 { "ip-destination" , required_argument, 0, IP_DEST }, 33 { "ip-dst" , required_argument, 0, IP_DEST }, 34 { "ip-tos" , required_argument, 0, IP_myTOS }, 35 { "ip-protocol" , required_argument, 0, IP_PROTO }, 36 { "ip-proto" , required_argument, 0, IP_PROTO }, 37 { "ip-source-port" , required_argument, 0, IP_SPORT }, 38 { "ip-sport" , required_argument, 0, IP_SPORT }, 39 { "ip-destination-port" , required_argument, 0, IP_DPORT }, 40 { "ip-dport" , required_argument, 0, IP_DPORT }, 41 { 0 } 42}; 43 44/* put the mask into 4 bytes */ 45/* transform a protocol and service name into a port number */ 46static uint16_t parse_port(const char *protocol, const char *name) 47{ 48 struct servent *service; 49 char *end; 50 int port; 51 52 port = strtol(name, &end, 10); 53 if (*end != '\0') { 54 if (protocol && 55 (service = getservbyname(name, protocol)) != NULL) 56 return ntohs(service->s_port); 57 } 58 else if (port >= 0 || port <= 0xFFFF) { 59 return port; 60 } 61 ebt_print_error("Problem with specified %s port '%s'", 62 protocol?protocol:"", name); 63 return 0; 64} 65 66static void 67parse_port_range(const char *protocol, const char *portstring, uint16_t *ports) 68{ 69 char *buffer; 70 char *cp; 71 72 buffer = strdup(portstring); 73 if ((cp = strchr(buffer, ':')) == NULL) 74 ports[0] = ports[1] = parse_port(protocol, buffer); 75 else { 76 *cp = '\0'; 77 cp++; 78 ports[0] = buffer[0] ? parse_port(protocol, buffer) : 0; 79 if (ebt_errormsg[0] != '\0') 80 return; 81 ports[1] = cp[0] ? parse_port(protocol, cp) : 0xFFFF; 82 if (ebt_errormsg[0] != '\0') 83 return; 84 85 if (ports[0] > ports[1]) 86 ebt_print_error("Invalid portrange (min > max)"); 87 } 88 free(buffer); 89} 90 91static void print_port_range(uint16_t *ports) 92{ 93 if (ports[0] == ports[1]) 94 printf("%d ", ports[0]); 95 else 96 printf("%d:%d ", ports[0], ports[1]); 97} 98 99static void print_help() 100{ 101 printf( 102"ip options:\n" 103"--ip-src [!] address[/mask]: ip source specification\n" 104"--ip-dst [!] address[/mask]: ip destination specification\n" 105"--ip-tos [!] tos : ip tos specification\n" 106"--ip-proto [!] protocol : ip protocol specification\n" 107"--ip-sport [!] port[:port] : tcp/udp source port or port range\n" 108"--ip-dport [!] port[:port] : tcp/udp destination port or port range\n"); 109} 110 111static void init(struct ebt_entry_match *match) 112{ 113 struct ebt_ip_info *ipinfo = (struct ebt_ip_info *)match->data; 114 115 ipinfo->invflags = 0; 116 ipinfo->bitmask = 0; 117} 118 119#define OPT_SOURCE 0x01 120#define OPT_DEST 0x02 121#define OPT_TOS 0x04 122#define OPT_PROTO 0x08 123#define OPT_SPORT 0x10 124#define OPT_DPORT 0x20 125static int parse(int c, char **argv, int argc, const struct ebt_u_entry *entry, 126 unsigned int *flags, struct ebt_entry_match **match) 127{ 128 struct ebt_ip_info *ipinfo = (struct ebt_ip_info *)(*match)->data; 129 char *end; 130 long int i; 131 132 switch (c) { 133 case IP_SOURCE: 134 ebt_check_option2(flags, OPT_SOURCE); 135 ipinfo->bitmask |= EBT_IP_SOURCE; 136 137 case IP_DEST: 138 if (c == IP_DEST) { 139 ebt_check_option2(flags, OPT_DEST); 140 ipinfo->bitmask |= EBT_IP_DEST; 141 } 142 if (ebt_check_inverse2(optarg)) { 143 if (c == IP_SOURCE) 144 ipinfo->invflags |= EBT_IP_SOURCE; 145 else 146 ipinfo->invflags |= EBT_IP_DEST; 147 } 148 if (c == IP_SOURCE) 149 ebt_parse_ip_address(optarg, &ipinfo->saddr, &ipinfo->smsk); 150 else 151 ebt_parse_ip_address(optarg, &ipinfo->daddr, &ipinfo->dmsk); 152 break; 153 154 case IP_SPORT: 155 case IP_DPORT: 156 if (c == IP_SPORT) { 157 ebt_check_option2(flags, OPT_SPORT); 158 ipinfo->bitmask |= EBT_IP_SPORT; 159 if (ebt_check_inverse2(optarg)) 160 ipinfo->invflags |= EBT_IP_SPORT; 161 } else { 162 ebt_check_option2(flags, OPT_DPORT); 163 ipinfo->bitmask |= EBT_IP_DPORT; 164 if (ebt_check_inverse2(optarg)) 165 ipinfo->invflags |= EBT_IP_DPORT; 166 } 167 if (c == IP_SPORT) 168 parse_port_range(NULL, optarg, ipinfo->sport); 169 else 170 parse_port_range(NULL, optarg, ipinfo->dport); 171 break; 172 173 case IP_myTOS: 174 ebt_check_option2(flags, OPT_TOS); 175 if (ebt_check_inverse2(optarg)) 176 ipinfo->invflags |= EBT_IP_TOS; 177 i = strtol(optarg, &end, 16); 178 if (i < 0 || i > 255 || *end != '\0') 179 ebt_print_error2("Problem with specified IP tos"); 180 ipinfo->tos = i; 181 ipinfo->bitmask |= EBT_IP_TOS; 182 break; 183 184 case IP_PROTO: 185 ebt_check_option2(flags, OPT_PROTO); 186 if (ebt_check_inverse2(optarg)) 187 ipinfo->invflags |= EBT_IP_PROTO; 188 i = strtoul(optarg, &end, 10); 189 if (*end != '\0') { 190 struct protoent *pe; 191 192 pe = getprotobyname(optarg); 193 if (pe == NULL) 194 ebt_print_error("Unknown specified IP protocol - %s", argv[optind - 1]); 195 ipinfo->protocol = pe->p_proto; 196 } else { 197 ipinfo->protocol = (unsigned char) i; 198 } 199 ipinfo->bitmask |= EBT_IP_PROTO; 200 break; 201 default: 202 return 0; 203 } 204 return 1; 205} 206 207static void final_check(const struct ebt_u_entry *entry, 208 const struct ebt_entry_match *match, const char *name, 209 unsigned int hookmask, unsigned int time) 210{ 211 struct ebt_ip_info *ipinfo = (struct ebt_ip_info *)match->data; 212 213 if (entry->ethproto != ETH_P_IP || entry->invflags & EBT_IPROTO) { 214 ebt_print_error("For IP filtering the protocol must be " 215 "specified as IPv4"); 216 } else if (ipinfo->bitmask & (EBT_IP_SPORT|EBT_IP_DPORT) && 217 (!(ipinfo->bitmask & EBT_IP_PROTO) || 218 ipinfo->invflags & EBT_IP_PROTO || 219 (ipinfo->protocol!=IPPROTO_TCP && 220 ipinfo->protocol!=IPPROTO_UDP && 221 ipinfo->protocol!=IPPROTO_SCTP && 222 ipinfo->protocol!=IPPROTO_DCCP))) 223 ebt_print_error("For port filtering the IP protocol must be " 224 "either 6 (tcp), 17 (udp), 33 (dccp) or " 225 "132 (sctp)"); 226} 227 228static void print(const struct ebt_u_entry *entry, 229 const struct ebt_entry_match *match) 230{ 231 struct ebt_ip_info *ipinfo = (struct ebt_ip_info *)match->data; 232 int j; 233 234 if (ipinfo->bitmask & EBT_IP_SOURCE) { 235 printf("--ip-src "); 236 if (ipinfo->invflags & EBT_IP_SOURCE) 237 printf("! "); 238 for (j = 0; j < 4; j++) 239 printf("%d%s",((unsigned char *)&ipinfo->saddr)[j], 240 (j == 3) ? "" : "."); 241 printf("%s ", ebt_mask_to_dotted(ipinfo->smsk)); 242 } 243 if (ipinfo->bitmask & EBT_IP_DEST) { 244 printf("--ip-dst "); 245 if (ipinfo->invflags & EBT_IP_DEST) 246 printf("! "); 247 for (j = 0; j < 4; j++) 248 printf("%d%s", ((unsigned char *)&ipinfo->daddr)[j], 249 (j == 3) ? "" : "."); 250 printf("%s ", ebt_mask_to_dotted(ipinfo->dmsk)); 251 } 252 if (ipinfo->bitmask & EBT_IP_TOS) { 253 printf("--ip-tos "); 254 if (ipinfo->invflags & EBT_IP_TOS) 255 printf("! "); 256 printf("0x%02X ", ipinfo->tos); 257 } 258 if (ipinfo->bitmask & EBT_IP_PROTO) { 259 struct protoent *pe; 260 261 printf("--ip-proto "); 262 if (ipinfo->invflags & EBT_IP_PROTO) 263 printf("! "); 264 pe = getprotobynumber(ipinfo->protocol); 265 if (pe == NULL) { 266 printf("%d ", ipinfo->protocol); 267 } else { 268 printf("%s ", pe->p_name); 269 } 270 } 271 if (ipinfo->bitmask & EBT_IP_SPORT) { 272 printf("--ip-sport "); 273 if (ipinfo->invflags & EBT_IP_SPORT) 274 printf("! "); 275 print_port_range(ipinfo->sport); 276 } 277 if (ipinfo->bitmask & EBT_IP_DPORT) { 278 printf("--ip-dport "); 279 if (ipinfo->invflags & EBT_IP_DPORT) 280 printf("! "); 281 print_port_range(ipinfo->dport); 282 } 283} 284 285static int compare(const struct ebt_entry_match *m1, 286 const struct ebt_entry_match *m2) 287{ 288 struct ebt_ip_info *ipinfo1 = (struct ebt_ip_info *)m1->data; 289 struct ebt_ip_info *ipinfo2 = (struct ebt_ip_info *)m2->data; 290 291 if (ipinfo1->bitmask != ipinfo2->bitmask) 292 return 0; 293 if (ipinfo1->invflags != ipinfo2->invflags) 294 return 0; 295 if (ipinfo1->bitmask & EBT_IP_SOURCE) { 296 if (ipinfo1->saddr != ipinfo2->saddr) 297 return 0; 298 if (ipinfo1->smsk != ipinfo2->smsk) 299 return 0; 300 } 301 if (ipinfo1->bitmask & EBT_IP_DEST) { 302 if (ipinfo1->daddr != ipinfo2->daddr) 303 return 0; 304 if (ipinfo1->dmsk != ipinfo2->dmsk) 305 return 0; 306 } 307 if (ipinfo1->bitmask & EBT_IP_TOS) { 308 if (ipinfo1->tos != ipinfo2->tos) 309 return 0; 310 } 311 if (ipinfo1->bitmask & EBT_IP_PROTO) { 312 if (ipinfo1->protocol != ipinfo2->protocol) 313 return 0; 314 } 315 if (ipinfo1->bitmask & EBT_IP_SPORT) { 316 if (ipinfo1->sport[0] != ipinfo2->sport[0] || 317 ipinfo1->sport[1] != ipinfo2->sport[1]) 318 return 0; 319 } 320 if (ipinfo1->bitmask & EBT_IP_DPORT) { 321 if (ipinfo1->dport[0] != ipinfo2->dport[0] || 322 ipinfo1->dport[1] != ipinfo2->dport[1]) 323 return 0; 324 } 325 return 1; 326} 327 328static struct ebt_u_match ip_match = 329{ 330 .name = "ip", 331 .size = sizeof(struct ebt_ip_info), 332 .help = print_help, 333 .init = init, 334 .parse = parse, 335 .final_check = final_check, 336 .print = print, 337 .compare = compare, 338 .extra_ops = opts, 339}; 340 341void _init(void) 342{ 343 ebt_register_match(&ip_match); 344} 345