libxt_udp.c revision 7ac405297ec38449b30e3b05fd6bf2082fd3d803
1/* Shared library add-on to iptables to add UDP support. */ 2#include <stdbool.h> 3#include <stdio.h> 4#include <netdb.h> 5#include <string.h> 6#include <stdlib.h> 7#include <getopt.h> 8#include <netinet/in.h> 9#include <xtables.h> 10#include <linux/netfilter/xt_tcpudp.h> 11 12static void udp_help(void) 13{ 14 printf( 15"udp match 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"); 22} 23 24static const struct option udp_opts[] = { 25 {.name = "source-port", .has_arg = true, .val = '1'}, 26 {.name = "sport", .has_arg = true, .val = '1'}, /* synonym */ 27 {.name = "destination-port", .has_arg = true, .val = '2'}, 28 {.name = "dport", .has_arg = true, .val = '2'}, /* synonym */ 29 XT_GETOPT_TABLEEND, 30}; 31 32static void 33parse_udp_ports(const char *portstring, uint16_t *ports) 34{ 35 char *buffer; 36 char *cp; 37 38 buffer = strdup(portstring); 39 if ((cp = strchr(buffer, ':')) == NULL) 40 ports[0] = ports[1] = xtables_parse_port(buffer, "udp"); 41 else { 42 *cp = '\0'; 43 cp++; 44 45 ports[0] = buffer[0] ? xtables_parse_port(buffer, "udp") : 0; 46 ports[1] = cp[0] ? xtables_parse_port(cp, "udp") : 0xFFFF; 47 48 if (ports[0] > ports[1]) 49 xtables_error(PARAMETER_PROBLEM, 50 "invalid portrange (min > max)"); 51 } 52 free(buffer); 53} 54 55static void udp_init(struct xt_entry_match *m) 56{ 57 struct xt_udp *udpinfo = (struct xt_udp *)m->data; 58 59 udpinfo->spts[1] = udpinfo->dpts[1] = 0xFFFF; 60} 61 62#define UDP_SRC_PORTS 0x01 63#define UDP_DST_PORTS 0x02 64 65static int 66udp_parse(int c, char **argv, int invert, unsigned int *flags, 67 const void *entry, struct xt_entry_match **match) 68{ 69 struct xt_udp *udpinfo = (struct xt_udp *)(*match)->data; 70 71 switch (c) { 72 case '1': 73 if (*flags & UDP_SRC_PORTS) 74 xtables_error(PARAMETER_PROBLEM, 75 "Only one `--source-port' allowed"); 76 xtables_check_inverse(optarg, &invert, &optind, 0, argv); 77 parse_udp_ports(optarg, udpinfo->spts); 78 if (invert) 79 udpinfo->invflags |= XT_UDP_INV_SRCPT; 80 *flags |= UDP_SRC_PORTS; 81 break; 82 83 case '2': 84 if (*flags & UDP_DST_PORTS) 85 xtables_error(PARAMETER_PROBLEM, 86 "Only one `--destination-port' allowed"); 87 xtables_check_inverse(optarg, &invert, &optind, 0, argv); 88 parse_udp_ports(optarg, udpinfo->dpts); 89 if (invert) 90 udpinfo->invflags |= XT_UDP_INV_DSTPT; 91 *flags |= UDP_DST_PORTS; 92 break; 93 94 default: 95 return 0; 96 } 97 98 return 1; 99} 100 101static char * 102port_to_service(int port) 103{ 104 struct servent *service; 105 106 if ((service = getservbyport(htons(port), "udp"))) 107 return service->s_name; 108 109 return NULL; 110} 111 112static void 113print_port(uint16_t port, int numeric) 114{ 115 char *service; 116 117 if (numeric || (service = port_to_service(port)) == NULL) 118 printf("%u", port); 119 else 120 printf("%s", service); 121} 122 123static void 124print_ports(const char *name, uint16_t min, uint16_t max, 125 int invert, int numeric) 126{ 127 const char *inv = invert ? "!" : ""; 128 129 if (min != 0 || max != 0xFFFF || invert) { 130 printf("%s", name); 131 if (min == max) { 132 printf(":%s", inv); 133 print_port(min, numeric); 134 } else { 135 printf("s:%s", inv); 136 print_port(min, numeric); 137 printf(":"); 138 print_port(max, numeric); 139 } 140 printf(" "); 141 } 142} 143 144static void 145udp_print(const void *ip, const struct xt_entry_match *match, int numeric) 146{ 147 const struct xt_udp *udp = (struct xt_udp *)match->data; 148 149 printf("udp "); 150 print_ports("spt", udp->spts[0], udp->spts[1], 151 udp->invflags & XT_UDP_INV_SRCPT, 152 numeric); 153 print_ports("dpt", udp->dpts[0], udp->dpts[1], 154 udp->invflags & XT_UDP_INV_DSTPT, 155 numeric); 156 if (udp->invflags & ~XT_UDP_INV_MASK) 157 printf("Unknown invflags: 0x%X ", 158 udp->invflags & ~XT_UDP_INV_MASK); 159} 160 161static void udp_save(const void *ip, const struct xt_entry_match *match) 162{ 163 const struct xt_udp *udpinfo = (struct xt_udp *)match->data; 164 165 if (udpinfo->spts[0] != 0 166 || udpinfo->spts[1] != 0xFFFF) { 167 if (udpinfo->invflags & XT_UDP_INV_SRCPT) 168 printf("! "); 169 if (udpinfo->spts[0] 170 != udpinfo->spts[1]) 171 printf("--sport %u:%u ", 172 udpinfo->spts[0], 173 udpinfo->spts[1]); 174 else 175 printf("--sport %u ", 176 udpinfo->spts[0]); 177 } 178 179 if (udpinfo->dpts[0] != 0 180 || udpinfo->dpts[1] != 0xFFFF) { 181 if (udpinfo->invflags & XT_UDP_INV_DSTPT) 182 printf("! "); 183 if (udpinfo->dpts[0] 184 != udpinfo->dpts[1]) 185 printf("--dport %u:%u ", 186 udpinfo->dpts[0], 187 udpinfo->dpts[1]); 188 else 189 printf("--dport %u ", 190 udpinfo->dpts[0]); 191 } 192} 193 194static struct xtables_match udp_match = { 195 .family = NFPROTO_UNSPEC, 196 .name = "udp", 197 .version = XTABLES_VERSION, 198 .size = XT_ALIGN(sizeof(struct xt_udp)), 199 .userspacesize = XT_ALIGN(sizeof(struct xt_udp)), 200 .help = udp_help, 201 .init = udp_init, 202 .parse = udp_parse, 203 .print = udp_print, 204 .save = udp_save, 205 .extra_opts = udp_opts, 206}; 207 208void 209_init(void) 210{ 211 xtables_register_match(&udp_match); 212} 213