libxt_udp.c revision 73866357e4a7a0fdc1b293bf8863fee2bd56da9e
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 95 return 1; 96} 97 98static char * 99port_to_service(int port) 100{ 101 struct servent *service; 102 103 if ((service = getservbyport(htons(port), "udp"))) 104 return service->s_name; 105 106 return NULL; 107} 108 109static void 110print_port(uint16_t port, int numeric) 111{ 112 char *service; 113 114 if (numeric || (service = port_to_service(port)) == NULL) 115 printf("%u", port); 116 else 117 printf("%s", service); 118} 119 120static void 121print_ports(const char *name, uint16_t min, uint16_t max, 122 int invert, int numeric) 123{ 124 const char *inv = invert ? "!" : ""; 125 126 if (min != 0 || max != 0xFFFF || invert) { 127 printf(" %s", name); 128 if (min == max) { 129 printf(":%s", inv); 130 print_port(min, numeric); 131 } else { 132 printf("s:%s", inv); 133 print_port(min, numeric); 134 printf(":"); 135 print_port(max, numeric); 136 } 137 } 138} 139 140static void 141udp_print(const void *ip, const struct xt_entry_match *match, int numeric) 142{ 143 const struct xt_udp *udp = (struct xt_udp *)match->data; 144 145 printf(" udp"); 146 print_ports("spt", udp->spts[0], udp->spts[1], 147 udp->invflags & XT_UDP_INV_SRCPT, 148 numeric); 149 print_ports("dpt", udp->dpts[0], udp->dpts[1], 150 udp->invflags & XT_UDP_INV_DSTPT, 151 numeric); 152 if (udp->invflags & ~XT_UDP_INV_MASK) 153 printf(" Unknown invflags: 0x%X", 154 udp->invflags & ~XT_UDP_INV_MASK); 155} 156 157static void udp_save(const void *ip, const struct xt_entry_match *match) 158{ 159 const struct xt_udp *udpinfo = (struct xt_udp *)match->data; 160 161 if (udpinfo->spts[0] != 0 162 || udpinfo->spts[1] != 0xFFFF) { 163 if (udpinfo->invflags & XT_UDP_INV_SRCPT) 164 printf(" !"); 165 if (udpinfo->spts[0] 166 != udpinfo->spts[1]) 167 printf(" --sport %u:%u", 168 udpinfo->spts[0], 169 udpinfo->spts[1]); 170 else 171 printf(" --sport %u", 172 udpinfo->spts[0]); 173 } 174 175 if (udpinfo->dpts[0] != 0 176 || udpinfo->dpts[1] != 0xFFFF) { 177 if (udpinfo->invflags & XT_UDP_INV_DSTPT) 178 printf(" !"); 179 if (udpinfo->dpts[0] 180 != udpinfo->dpts[1]) 181 printf(" --dport %u:%u", 182 udpinfo->dpts[0], 183 udpinfo->dpts[1]); 184 else 185 printf(" --dport %u", 186 udpinfo->dpts[0]); 187 } 188} 189 190static struct xtables_match udp_match = { 191 .family = NFPROTO_UNSPEC, 192 .name = "udp", 193 .version = XTABLES_VERSION, 194 .size = XT_ALIGN(sizeof(struct xt_udp)), 195 .userspacesize = XT_ALIGN(sizeof(struct xt_udp)), 196 .help = udp_help, 197 .init = udp_init, 198 .parse = udp_parse, 199 .print = udp_print, 200 .save = udp_save, 201 .extra_opts = udp_opts, 202}; 203 204void 205_init(void) 206{ 207 xtables_register_match(&udp_match); 208} 209