1/* Shared library add-on to iptables to add multiple TCP port 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/ipt_multiport.h> 9 10/* Function which prints out usage message. */ 11static void 12help(void) 13{ 14 printf( 15"multiport v%s options:\n" 16" --source-ports port[,port,port...]\n" 17" --sports ...\n" 18" match source port(s)\n" 19" --destination-ports port[,port,port...]\n" 20" --dports ...\n" 21" match destination port(s)\n" 22" --ports port[,port,port]\n" 23" match both source and destination port(s)\n", 24IPTABLES_VERSION); 25} 26 27static struct option opts[] = { 28 { "source-ports", 1, 0, '1' }, 29 { "sports", 1, 0, '1' }, /* synonym */ 30 { "destination-ports", 1, 0, '2' }, 31 { "dports", 1, 0, '2' }, /* synonym */ 32 { "ports", 1, 0, '3' }, 33 {0} 34}; 35 36static int 37service_to_port(const char *name, const char *proto) 38{ 39 struct servent *service; 40 41 if ((service = getservbyname(name, proto)) != NULL) 42 return ntohs((unsigned short) service->s_port); 43 44 return -1; 45} 46 47static u_int16_t 48parse_port(const char *port, const char *proto) 49{ 50 unsigned int portnum; 51 52 if (string_to_number(port, 0, 65535, &portnum) != -1 || 53 (portnum = service_to_port(port, proto)) != -1) 54 return (u_int16_t)portnum; 55 56 exit_error(PARAMETER_PROBLEM, 57 "invalid port/service `%s' specified", port); 58} 59 60static unsigned int 61parse_multi_ports(const char *portstring, u_int16_t *ports, const char *proto) 62{ 63 char *buffer, *cp, *next; 64 unsigned int i; 65 66 buffer = strdup(portstring); 67 if (!buffer) exit_error(OTHER_PROBLEM, "strdup failed"); 68 69 for (cp=buffer, i=0; cp && i<IPT_MULTI_PORTS; cp=next,i++) 70 { 71 next=strchr(cp, ','); 72 if (next) *next++='\0'; 73 ports[i] = parse_port(cp, proto); 74 } 75 if (cp) exit_error(PARAMETER_PROBLEM, "too many ports specified"); 76 free(buffer); 77 return i; 78} 79 80/* Initialize the match. */ 81static void 82init(struct ipt_entry_match *m, unsigned int *nfcache) 83{ 84} 85 86static const char * 87check_proto(const struct ipt_entry *entry) 88{ 89 if (entry->ip.proto == IPPROTO_TCP) 90 return "tcp"; 91 else if (entry->ip.proto == IPPROTO_UDP) 92 return "udp"; 93 else if (!entry->ip.proto) 94 exit_error(PARAMETER_PROBLEM, 95 "multiport needs `-p tcp' or `-p udp'"); 96 else 97 exit_error(PARAMETER_PROBLEM, 98 "multiport only works with TCP or UDP"); 99} 100 101/* Function which parses command options; returns true if it 102 ate an option */ 103static int 104parse(int c, char **argv, int invert, unsigned int *flags, 105 const struct ipt_entry *entry, 106 unsigned int *nfcache, 107 struct ipt_entry_match **match) 108{ 109 const char *proto; 110 struct ipt_multiport *multiinfo 111 = (struct ipt_multiport *)(*match)->data; 112 113 switch (c) { 114 case '1': 115 proto = check_proto(entry); 116 multiinfo->count = parse_multi_ports(argv[optind-1], 117 multiinfo->ports, proto); 118 multiinfo->flags = IPT_MULTIPORT_SOURCE; 119 *nfcache |= NFC_IP_SRC_PT; 120 break; 121 122 case '2': 123 proto = check_proto(entry); 124 multiinfo->count = parse_multi_ports(argv[optind-1], 125 multiinfo->ports, proto); 126 multiinfo->flags = IPT_MULTIPORT_DESTINATION; 127 *nfcache |= NFC_IP_DST_PT; 128 break; 129 130 case '3': 131 proto = check_proto(entry); 132 multiinfo->count = parse_multi_ports(argv[optind-1], 133 multiinfo->ports, proto); 134 multiinfo->flags = IPT_MULTIPORT_EITHER; 135 *nfcache |= NFC_IP_SRC_PT | NFC_IP_DST_PT; 136 break; 137 138 default: 139 return 0; 140 } 141 142 if (*flags) 143 exit_error(PARAMETER_PROBLEM, 144 "multiport can only have one option"); 145 *flags = 1; 146 return 1; 147} 148 149/* Final check; must specify something. */ 150static void 151final_check(unsigned int flags) 152{ 153 if (!flags) 154 exit_error(PARAMETER_PROBLEM, "multiport expection an option"); 155} 156 157static char * 158port_to_service(int port, u_int8_t proto) 159{ 160 struct servent *service; 161 162 if ((service = getservbyport(htons(port), 163 proto == IPPROTO_TCP ? "tcp" : "udp"))) 164 return service->s_name; 165 166 return NULL; 167} 168 169static void 170print_port(u_int16_t port, u_int8_t protocol, int numeric) 171{ 172 char *service; 173 174 if (numeric || (service = port_to_service(port, protocol)) == NULL) 175 printf("%u", port); 176 else 177 printf("%s", service); 178} 179 180/* Prints out the matchinfo. */ 181static void 182print(const struct ipt_ip *ip, 183 const struct ipt_entry_match *match, 184 int numeric) 185{ 186 const struct ipt_multiport *multiinfo 187 = (const struct ipt_multiport *)match->data; 188 unsigned int i; 189 190 printf("multiport "); 191 192 switch (multiinfo->flags) { 193 case IPT_MULTIPORT_SOURCE: 194 printf("sports "); 195 break; 196 197 case IPT_MULTIPORT_DESTINATION: 198 printf("dports "); 199 break; 200 201 case IPT_MULTIPORT_EITHER: 202 printf("ports "); 203 break; 204 205 default: 206 printf("ERROR "); 207 break; 208 } 209 210 for (i=0; i < multiinfo->count; i++) { 211 printf("%s", i ? "," : ""); 212 print_port(multiinfo->ports[i], ip->proto, numeric); 213 } 214 printf(" "); 215} 216 217/* Saves the union ipt_matchinfo in parsable form to stdout. */ 218static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match) 219{ 220 const struct ipt_multiport *multiinfo 221 = (const struct ipt_multiport *)match->data; 222 unsigned int i; 223 224 switch (multiinfo->flags) { 225 case IPT_MULTIPORT_SOURCE: 226 printf("--sports "); 227 break; 228 229 case IPT_MULTIPORT_DESTINATION: 230 printf("--dports "); 231 break; 232 233 case IPT_MULTIPORT_EITHER: 234 printf("--ports "); 235 break; 236 } 237 238 for (i=0; i < multiinfo->count; i++) { 239 printf("%s", i ? "," : ""); 240 print_port(multiinfo->ports[i], ip->proto, 0); 241 } 242 printf(" "); 243} 244 245static 246struct iptables_match multiport 247= { NULL, 248 "multiport", 249 IPTABLES_VERSION, 250 IPT_ALIGN(sizeof(struct ipt_multiport)), 251 IPT_ALIGN(sizeof(struct ipt_multiport)), 252 &help, 253 &init, 254 &parse, 255 &final_check, 256 &print, 257 &save, 258 opts 259}; 260 261void 262_init(void) 263{ 264 register_match(&multiport); 265} 266