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