1/* ebt_ip6 2 * 3 * Authors: 4 * Kuo-Lang Tseng <kuo-lang.tseng@intel.com> 5 * Manohar Castelino <manohar.castelino@intel.com> 6 * 7 * Summary: 8 * This is just a modification of the IPv4 code written by 9 * Bart De Schuymer <bdschuym@pandora.be> 10 * with the changes required to support IPv6 11 * 12 */ 13 14#include <stdio.h> 15#include <stdlib.h> 16#include <string.h> 17#include <getopt.h> 18#include <netdb.h> 19#include "../include/ebtables_u.h" 20#include <linux/netfilter_bridge/ebt_ip6.h> 21 22 23 24#define IP_SOURCE '1' 25#define IP_DEST '2' 26#define IP_TCLASS '3' 27#define IP_PROTO '4' 28#define IP_SPORT '5' 29#define IP_DPORT '6' 30 31static struct option opts[] = 32{ 33 { "ip6-source" , required_argument, 0, IP_SOURCE }, 34 { "ip6-src" , required_argument, 0, IP_SOURCE }, 35 { "ip6-destination" , required_argument, 0, IP_DEST }, 36 { "ip6-dst" , required_argument, 0, IP_DEST }, 37 { "ip6-traffic-class" , required_argument, 0, IP_TCLASS }, 38 { "ip6-tclass" , required_argument, 0, IP_TCLASS }, 39 { "ip6-protocol" , required_argument, 0, IP_PROTO }, 40 { "ip6-proto" , required_argument, 0, IP_PROTO }, 41 { "ip6-source-port" , required_argument, 0, IP_SPORT }, 42 { "ip6-sport" , required_argument, 0, IP_SPORT }, 43 { "ip6-destination-port" , required_argument, 0, IP_DPORT }, 44 { "ip6-dport" , required_argument, 0, IP_DPORT }, 45 { 0 } 46}; 47 48/* transform a protocol and service name into a port number */ 49static uint16_t parse_port(const char *protocol, const char *name) 50{ 51 struct servent *service; 52 char *end; 53 int port; 54 55 port = strtol(name, &end, 10); 56 if (*end != '\0') { 57 if (protocol && 58 (service = getservbyname(name, protocol)) != NULL) 59 return ntohs(service->s_port); 60 } 61 else if (port >= 0 || port <= 0xFFFF) { 62 return port; 63 } 64 ebt_print_error("Problem with specified %s port '%s'", 65 protocol?protocol:"", name); 66 return 0; 67} 68 69static void 70parse_port_range(const char *protocol, const char *portstring, uint16_t *ports) 71{ 72 char *buffer; 73 char *cp; 74 75 buffer = strdup(portstring); 76 if ((cp = strchr(buffer, ':')) == NULL) 77 ports[0] = ports[1] = parse_port(protocol, buffer); 78 else { 79 *cp = '\0'; 80 cp++; 81 ports[0] = buffer[0] ? parse_port(protocol, buffer) : 0; 82 if (ebt_errormsg[0] != '\0') 83 return; 84 ports[1] = cp[0] ? parse_port(protocol, cp) : 0xFFFF; 85 if (ebt_errormsg[0] != '\0') 86 return; 87 88 if (ports[0] > ports[1]) 89 ebt_print_error("Invalid portrange (min > max)"); 90 } 91 free(buffer); 92} 93 94static void print_port_range(uint16_t *ports) 95{ 96 if (ports[0] == ports[1]) 97 printf("%d ", ports[0]); 98 else 99 printf("%d:%d ", ports[0], ports[1]); 100} 101 102static void print_help() 103{ 104 printf( 105"ip6 options:\n" 106"--ip6-src [!] address[/mask]: ipv6 source specification\n" 107"--ip6-dst [!] address[/mask]: ipv6 destination specification\n" 108"--ip6-tclass [!] tclass : ipv6 traffic class specification\n" 109"--ip6-proto [!] protocol : ipv6 protocol specification\n" 110"--ip6-sport [!] port[:port] : tcp/udp source port or port range\n" 111"--ip6-dport [!] port[:port] : tcp/udp destination port or port range\n"); 112} 113 114static void init(struct ebt_entry_match *match) 115{ 116 struct ebt_ip6_info *ipinfo = (struct ebt_ip6_info *)match->data; 117 118 ipinfo->invflags = 0; 119 ipinfo->bitmask = 0; 120} 121 122#define OPT_SOURCE 0x01 123#define OPT_DEST 0x02 124#define OPT_TCLASS 0x04 125#define OPT_PROTO 0x08 126#define OPT_SPORT 0x10 127#define OPT_DPORT 0x20 128static int parse(int c, char **argv, int argc, const struct ebt_u_entry *entry, 129 unsigned int *flags, struct ebt_entry_match **match) 130{ 131 struct ebt_ip6_info *ipinfo = (struct ebt_ip6_info *)(*match)->data; 132 char *end; 133 long int i; 134 135 switch (c) { 136 case IP_SOURCE: 137 ebt_check_option2(flags, OPT_SOURCE); 138 ipinfo->bitmask |= EBT_IP6_SOURCE; 139 if (ebt_check_inverse2(optarg)) { 140 ipinfo->invflags |= EBT_IP6_SOURCE; 141 } 142 ebt_parse_ip6_address(optarg, &ipinfo->saddr, &ipinfo->smsk); 143 break; 144 145 case IP_DEST: 146 ebt_check_option2(flags, OPT_DEST); 147 ipinfo->bitmask |= EBT_IP6_DEST; 148 if (ebt_check_inverse2(optarg)) { 149 ipinfo->invflags |= EBT_IP6_DEST; 150 } 151 ebt_parse_ip6_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_IP6_SPORT; 159 if (ebt_check_inverse2(optarg)) 160 ipinfo->invflags |= EBT_IP6_SPORT; 161 } else { 162 ebt_check_option2(flags, OPT_DPORT); 163 ipinfo->bitmask |= EBT_IP6_DPORT; 164 if (ebt_check_inverse2(optarg)) 165 ipinfo->invflags |= EBT_IP6_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_TCLASS: 174 ebt_check_option2(flags, OPT_TCLASS); 175 if (ebt_check_inverse2(optarg)) 176 ipinfo->invflags |= EBT_IP6_TCLASS; 177 i = strtol(optarg, &end, 16); 178 if (i < 0 || i > 255 || *end != '\0') 179 ebt_print_error2("Problem with specified IPv6 traffic class"); 180 ipinfo->tclass = i; 181 ipinfo->bitmask |= EBT_IP6_TCLASS; 182 break; 183 184 case IP_PROTO: 185 ebt_check_option2(flags, OPT_PROTO); 186 if (ebt_check_inverse2(optarg)) 187 ipinfo->invflags |= EBT_IP6_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_IP6_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_ip6_info *ipinfo = (struct ebt_ip6_info *)match->data; 212 213 if (entry->ethproto != ETH_P_IPV6 || entry->invflags & EBT_IPROTO) { 214 ebt_print_error("For IPv6 filtering the protocol must be " 215 "specified as IPv6"); 216 } else if (ipinfo->bitmask & (EBT_IP6_SPORT|EBT_IP6_DPORT) && 217 (!(ipinfo->bitmask & EBT_IP6_PROTO) || 218 ipinfo->invflags & EBT_IP6_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_ip6_info *ipinfo = (struct ebt_ip6_info *)match->data; 232 233 if (ipinfo->bitmask & EBT_IP6_SOURCE) { 234 printf("--ip6-src "); 235 if (ipinfo->invflags & EBT_IP6_SOURCE) 236 printf("! "); 237 printf("%s", ebt_ip6_to_numeric(&ipinfo->saddr)); 238 printf("/%s ", ebt_ip6_to_numeric(&ipinfo->smsk)); 239 } 240 if (ipinfo->bitmask & EBT_IP6_DEST) { 241 printf("--ip6-dst "); 242 if (ipinfo->invflags & EBT_IP6_DEST) 243 printf("! "); 244 printf("%s", ebt_ip6_to_numeric(&ipinfo->daddr)); 245 printf("/%s ", ebt_ip6_to_numeric(&ipinfo->dmsk)); 246 } 247 if (ipinfo->bitmask & EBT_IP6_TCLASS) { 248 printf("--ip6-tclass "); 249 if (ipinfo->invflags & EBT_IP6_TCLASS) 250 printf("! "); 251 printf("0x%02X ", ipinfo->tclass); 252 } 253 if (ipinfo->bitmask & EBT_IP6_PROTO) { 254 struct protoent *pe; 255 256 printf("--ip6-proto "); 257 if (ipinfo->invflags & EBT_IP6_PROTO) 258 printf("! "); 259 pe = getprotobynumber(ipinfo->protocol); 260 if (pe == NULL) { 261 printf("%d ", ipinfo->protocol); 262 } else { 263 printf("%s ", pe->p_name); 264 } 265 } 266 if (ipinfo->bitmask & EBT_IP6_SPORT) { 267 printf("--ip6-sport "); 268 if (ipinfo->invflags & EBT_IP6_SPORT) 269 printf("! "); 270 print_port_range(ipinfo->sport); 271 } 272 if (ipinfo->bitmask & EBT_IP6_DPORT) { 273 printf("--ip6-dport "); 274 if (ipinfo->invflags & EBT_IP6_DPORT) 275 printf("! "); 276 print_port_range(ipinfo->dport); 277 } 278} 279 280static int compare(const struct ebt_entry_match *m1, 281 const struct ebt_entry_match *m2) 282{ 283 struct ebt_ip6_info *ipinfo1 = (struct ebt_ip6_info *)m1->data; 284 struct ebt_ip6_info *ipinfo2 = (struct ebt_ip6_info *)m2->data; 285 286 if (ipinfo1->bitmask != ipinfo2->bitmask) 287 return 0; 288 if (ipinfo1->invflags != ipinfo2->invflags) 289 return 0; 290 if (ipinfo1->bitmask & EBT_IP6_SOURCE) { 291 if (!IN6_ARE_ADDR_EQUAL(&ipinfo1->saddr, &ipinfo2->saddr)) 292 return 0; 293 if (!IN6_ARE_ADDR_EQUAL(&ipinfo1->smsk, &ipinfo2->smsk)) 294 return 0; 295 } 296 if (ipinfo1->bitmask & EBT_IP6_DEST) { 297 if (!IN6_ARE_ADDR_EQUAL(&ipinfo1->daddr, &ipinfo2->daddr)) 298 return 0; 299 if (!IN6_ARE_ADDR_EQUAL(&ipinfo1->dmsk, &ipinfo2->dmsk)) 300 return 0; 301 } 302 if (ipinfo1->bitmask & EBT_IP6_TCLASS) { 303 if (ipinfo1->tclass != ipinfo2->tclass) 304 return 0; 305 } 306 if (ipinfo1->bitmask & EBT_IP6_PROTO) { 307 if (ipinfo1->protocol != ipinfo2->protocol) 308 return 0; 309 } 310 if (ipinfo1->bitmask & EBT_IP6_SPORT) { 311 if (ipinfo1->sport[0] != ipinfo2->sport[0] || 312 ipinfo1->sport[1] != ipinfo2->sport[1]) 313 return 0; 314 } 315 if (ipinfo1->bitmask & EBT_IP6_DPORT) { 316 if (ipinfo1->dport[0] != ipinfo2->dport[0] || 317 ipinfo1->dport[1] != ipinfo2->dport[1]) 318 return 0; 319 } 320 return 1; 321} 322 323static struct ebt_u_match ip6_match = 324{ 325 .name = EBT_IP6_MATCH, 326 .size = sizeof(struct ebt_ip6_info), 327 .help = print_help, 328 .init = init, 329 .parse = parse, 330 .final_check = final_check, 331 .print = print, 332 .compare = compare, 333 .extra_ops = opts, 334}; 335 336void _init(void) 337{ 338 ebt_register_match(&ip6_match); 339} 340