Home | History | Annotate | Download | only in extensions
      1 /* Shared library add-on to iptables to add UDP support. */
      2 #include <stdio.h>
      3 #include <netdb.h>
      4 #include <string.h>
      5 #include <stdlib.h>
      6 #include <getopt.h>
      7 #include <iptables.h>
      8 #include <linux/netfilter_ipv4/ip_tables.h>
      9 #include <netinet/in.h>
     10 
     11 /* Function which prints out usage message. */
     12 static void
     13 help(void)
     14 {
     15 	printf(
     16 "UDP v%s options:\n"
     17 " --source-port [!] port[:port]\n"
     18 " --sport ...\n"
     19 "				match source port(s)\n"
     20 " --destination-port [!] port[:port]\n"
     21 " --dport ...\n"
     22 "				match destination port(s)\n",
     23 IPTABLES_VERSION);
     24 }
     25 
     26 static struct option opts[] = {
     27 	{ "source-port", 1, 0, '1' },
     28 	{ "sport", 1, 0, '1' }, /* synonym */
     29 	{ "destination-port", 1, 0, '2' },
     30 	{ "dport", 1, 0, '2' }, /* synonym */
     31 	{0}
     32 };
     33 
     34 static void
     35 parse_udp_ports(const char *portstring, u_int16_t *ports)
     36 {
     37 	char *buffer;
     38 	char *cp;
     39 
     40 	buffer = strdup(portstring);
     41 	if ((cp = strchr(buffer, ':')) == NULL)
     42 		ports[0] = ports[1] = parse_port(buffer, "udp");
     43 	else {
     44 		*cp = '\0';
     45 		cp++;
     46 
     47 		ports[0] = buffer[0] ? parse_port(buffer, "udp") : 0;
     48 		ports[1] = cp[0] ? parse_port(cp, "udp") : 0xFFFF;
     49 
     50 		if (ports[0] > ports[1])
     51 			exit_error(PARAMETER_PROBLEM,
     52 				   "invalid portrange (min > max)");
     53 	}
     54 	free(buffer);
     55 }
     56 
     57 /* Initialize the match. */
     58 static void
     59 init(struct ipt_entry_match *m, unsigned int *nfcache)
     60 {
     61 	struct ipt_udp *udpinfo = (struct ipt_udp *)m->data;
     62 
     63 	udpinfo->spts[1] = udpinfo->dpts[1] = 0xFFFF;
     64 }
     65 
     66 #define UDP_SRC_PORTS 0x01
     67 #define UDP_DST_PORTS 0x02
     68 
     69 /* Function which parses command options; returns true if it
     70    ate an option */
     71 static int
     72 parse(int c, char **argv, int invert, unsigned int *flags,
     73       const struct ipt_entry *entry,
     74       unsigned int *nfcache,
     75       struct ipt_entry_match **match)
     76 {
     77 	struct ipt_udp *udpinfo = (struct ipt_udp *)(*match)->data;
     78 
     79 	switch (c) {
     80 	case '1':
     81 		if (*flags & UDP_SRC_PORTS)
     82 			exit_error(PARAMETER_PROBLEM,
     83 				   "Only one `--source-port' allowed");
     84 		check_inverse(optarg, &invert, &optind, 0);
     85 		parse_udp_ports(argv[optind-1], udpinfo->spts);
     86 		if (invert)
     87 			udpinfo->invflags |= IPT_UDP_INV_SRCPT;
     88 		*flags |= UDP_SRC_PORTS;
     89 		break;
     90 
     91 	case '2':
     92 		if (*flags & UDP_DST_PORTS)
     93 			exit_error(PARAMETER_PROBLEM,
     94 				   "Only one `--destination-port' allowed");
     95 		check_inverse(optarg, &invert, &optind, 0);
     96 		parse_udp_ports(argv[optind-1], udpinfo->dpts);
     97 		if (invert)
     98 			udpinfo->invflags |= IPT_UDP_INV_DSTPT;
     99 		*flags |= UDP_DST_PORTS;
    100 		break;
    101 
    102 	default:
    103 		return 0;
    104 	}
    105 
    106 	return 1;
    107 }
    108 
    109 /* Final check; we don't care. */
    110 static void
    111 final_check(unsigned int flags)
    112 {
    113 }
    114 
    115 static char *
    116 port_to_service(int port)
    117 {
    118 	struct servent *service;
    119 
    120 	if ((service = getservbyport(htons(port), "udp")))
    121 		return service->s_name;
    122 
    123 	return NULL;
    124 }
    125 
    126 static void
    127 print_port(u_int16_t port, int numeric)
    128 {
    129 	char *service;
    130 
    131 	if (numeric || (service = port_to_service(port)) == NULL)
    132 		printf("%u", port);
    133 	else
    134 		printf("%s", service);
    135 }
    136 
    137 static void
    138 print_ports(const char *name, u_int16_t min, u_int16_t max,
    139 	    int invert, int numeric)
    140 {
    141 	const char *inv = invert ? "!" : "";
    142 
    143 	if (min != 0 || max != 0xFFFF || invert) {
    144 		printf("%s", name);
    145 		if (min == max) {
    146 			printf(":%s", inv);
    147 			print_port(min, numeric);
    148 		} else {
    149 			printf("s:%s", inv);
    150 			print_port(min, numeric);
    151 			printf(":");
    152 			print_port(max, numeric);
    153 		}
    154 		printf(" ");
    155 	}
    156 }
    157 
    158 /* Prints out the union ipt_matchinfo. */
    159 static void
    160 print(const struct ipt_ip *ip,
    161       const struct ipt_entry_match *match, int numeric)
    162 {
    163 	const struct ipt_udp *udp = (struct ipt_udp *)match->data;
    164 
    165 	printf("udp ");
    166 	print_ports("spt", udp->spts[0], udp->spts[1],
    167 		    udp->invflags & IPT_UDP_INV_SRCPT,
    168 		    numeric);
    169 	print_ports("dpt", udp->dpts[0], udp->dpts[1],
    170 		    udp->invflags & IPT_UDP_INV_DSTPT,
    171 		    numeric);
    172 	if (udp->invflags & ~IPT_UDP_INV_MASK)
    173 		printf("Unknown invflags: 0x%X ",
    174 		       udp->invflags & ~IPT_UDP_INV_MASK);
    175 }
    176 
    177 /* Saves the union ipt_matchinfo in parsable form to stdout. */
    178 static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
    179 {
    180 	const struct ipt_udp *udpinfo = (struct ipt_udp *)match->data;
    181 
    182 	if (udpinfo->spts[0] != 0
    183 	    || udpinfo->spts[1] != 0xFFFF) {
    184 		if (udpinfo->invflags & IPT_UDP_INV_SRCPT)
    185 			printf("! ");
    186 		if (udpinfo->spts[0]
    187 		    != udpinfo->spts[1])
    188 			printf("--sport %u:%u ",
    189 			       udpinfo->spts[0],
    190 			       udpinfo->spts[1]);
    191 		else
    192 			printf("--sport %u ",
    193 			       udpinfo->spts[0]);
    194 	}
    195 
    196 	if (udpinfo->dpts[0] != 0
    197 	    || udpinfo->dpts[1] != 0xFFFF) {
    198 		if (udpinfo->invflags & IPT_UDP_INV_DSTPT)
    199 			printf("! ");
    200 		if (udpinfo->dpts[0]
    201 		    != udpinfo->dpts[1])
    202 			printf("--dport %u:%u ",
    203 			       udpinfo->dpts[0],
    204 			       udpinfo->dpts[1]);
    205 		else
    206 			printf("--dport %u ",
    207 			       udpinfo->dpts[0]);
    208 	}
    209 }
    210 
    211 static
    212 struct iptables_match udp = {
    213 	.next		= NULL,
    214 	.name		= "udp",
    215 	.version	= IPTABLES_VERSION,
    216 	.size		= IPT_ALIGN(sizeof(struct ipt_udp)),
    217 	.userspacesize	= IPT_ALIGN(sizeof(struct ipt_udp)),
    218 	.help		= &help,
    219 	.init		= &init,
    220 	.parse		= &parse,
    221 	.final_check	= &final_check,
    222 	.print		= &print,
    223 	.save		= &save,
    224 	.extra_opts	= opts
    225 };
    226 
    227 void
    228 ipt_udp_init(void)
    229 {
    230 	register_match(&udp);
    231 }
    232