libxt_tcp.c revision 32b8e61e4e5bd405d9ad07bf9468498dfbb19f9e
19bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt/* Shared library add-on to iptables to add TCP support. */ 29bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt#include <stdbool.h> 39bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt#include <stdio.h> 49bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt#include <netdb.h> 59bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt#include <string.h> 69bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt#include <stdlib.h> 79bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt#include <getopt.h> 89bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt#include <netinet/in.h> 99bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt#include <xtables.h> 109bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt#include <linux/netfilter/xt_tcpudp.h> 119bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt 129bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidtstatic void tcp_help(void) 139bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt{ 149bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt printf( 159bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt"tcp match options:\n" 169bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt"[!] --tcp-flags mask comp match when TCP flags & mask == comp\n" 179bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt" (Flags: SYN ACK FIN RST URG PSH ALL NONE)\n" 189bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt"[!] --syn match when only SYN flag set\n" 199bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt" (equivalent to --tcp-flags SYN,RST,ACK,FIN SYN)\n" 209bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt"[!] --source-port port[:port]\n" 219bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt" --sport ...\n" 229bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt" match source port(s)\n" 239bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt"[!] --destination-port port[:port]\n" 249bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt" --dport ...\n" 259bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt" match destination port(s)\n" 269bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt"[!] --tcp-option number match if TCP option set\n"); 279bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt} 289bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt 299bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidtstatic const struct option tcp_opts[] = { 309bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt {.name = "source-port", .has_arg = true, .val = '1'}, 319bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt {.name = "sport", .has_arg = true, .val = '1'}, /* synonym */ 329bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt {.name = "destination-port", .has_arg = true, .val = '2'}, 339bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt {.name = "dport", .has_arg = true, .val = '2'}, /* synonym */ 349bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt {.name = "syn", .has_arg = false, .val = '3'}, 359bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt {.name = "tcp-flags", .has_arg = true, .val = '4'}, 369bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt {.name = "tcp-option", .has_arg = true, .val = '5'}, 379bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt XT_GETOPT_TABLEEND, 389bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt}; 399bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt 409bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidtstatic void 419bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidtparse_tcp_ports(const char *portstring, u_int16_t *ports) 429bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt{ 439bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt char *buffer; 449bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt char *cp; 459bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt 469bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt buffer = strdup(portstring); 479bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt if ((cp = strchr(buffer, ':')) == NULL) 489bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt ports[0] = ports[1] = xtables_parse_port(buffer, "tcp"); 499bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt else { 509bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt *cp = '\0'; 519bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt cp++; 529bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt 539bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt ports[0] = buffer[0] ? xtables_parse_port(buffer, "tcp") : 0; 549bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt ports[1] = cp[0] ? xtables_parse_port(cp, "tcp") : 0xFFFF; 559bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt 569bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt if (ports[0] > ports[1]) 579bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt xtables_error(PARAMETER_PROBLEM, 589bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt "invalid portrange (min > max)"); 599bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt } 609bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt free(buffer); 619bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt} 629bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt 639bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidtstruct tcp_flag_names { 649bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt const char *name; 659bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt unsigned int flag; 669bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt}; 679bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt 689bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidtstatic const struct tcp_flag_names tcp_flag_names[] 699bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt= { { "FIN", 0x01 }, 709bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt { "SYN", 0x02 }, 719bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt { "RST", 0x04 }, 729bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt { "PSH", 0x08 }, 739bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt { "ACK", 0x10 }, 749bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt { "URG", 0x20 }, 759bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt { "ALL", 0x3F }, 769bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt { "NONE", 0 }, 779bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt}; 789bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt 799bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidtstatic unsigned int 809bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidtparse_tcp_flag(const char *flags) 819bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt{ 829bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt unsigned int ret = 0; 839bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt char *ptr; 849bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt char *buffer; 859bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt 869bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt buffer = strdup(flags); 879bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt 889bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt for (ptr = strtok(buffer, ","); ptr; ptr = strtok(NULL, ",")) { 899bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt unsigned int i; 909bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt for (i = 0; i < ARRAY_SIZE(tcp_flag_names); ++i) 919bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt if (strcasecmp(tcp_flag_names[i].name, ptr) == 0) { 929bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt ret |= tcp_flag_names[i].flag; 939bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt break; 949bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt } 959bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt if (i == ARRAY_SIZE(tcp_flag_names)) 969bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt xtables_error(PARAMETER_PROBLEM, 979bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt "Unknown TCP flag `%s'", ptr); 989bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt } 999bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt 1009bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt free(buffer); 1019bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt return ret; 1029bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt} 1039bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt 1049bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidtstatic void 1059bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidtparse_tcp_flags(struct xt_tcp *tcpinfo, 1069bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt const char *mask, 1079bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt const char *cmp, 1089bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt int invert) 1099bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt{ 1109bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt tcpinfo->flg_mask = parse_tcp_flag(mask); 1119bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt tcpinfo->flg_cmp = parse_tcp_flag(cmp); 1129bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt 1139bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt if (invert) 1149bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt tcpinfo->invflags |= XT_TCP_INV_FLAGS; 1159bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt} 1169bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt 1179bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidtstatic void 1189bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidtparse_tcp_option(const char *option, u_int8_t *result) 1199bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt{ 1209bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt unsigned int ret; 1219bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt 1229bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt if (!xtables_strtoui(option, NULL, &ret, 1, UINT8_MAX)) 1239bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt xtables_error(PARAMETER_PROBLEM, "Bad TCP option \"%s\"", option); 1249bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt 1259bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt *result = ret; 1269bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt} 1279bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt 1289bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidtstatic void tcp_init(struct xt_entry_match *m) 1299bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt{ 1309bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt struct xt_tcp *tcpinfo = (struct xt_tcp *)m->data; 1319bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt 1329bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt tcpinfo->spts[1] = tcpinfo->dpts[1] = 0xFFFF; 1339bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt} 1349bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt 1359bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt#define TCP_SRC_PORTS 0x01 1369bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt#define TCP_DST_PORTS 0x02 1379bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt#define TCP_FLAGS 0x04 1389bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt#define TCP_OPTION 0x08 1399bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt 1409bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidtstatic int 1419bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidttcp_parse(int c, char **argv, int invert, unsigned int *flags, 1429bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt const void *entry, struct xt_entry_match **match) 1439bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt{ 1449bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt struct xt_tcp *tcpinfo = (struct xt_tcp *)(*match)->data; 1459bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt 1469bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt switch (c) { 1479bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt case '1': 1489bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt if (*flags & TCP_SRC_PORTS) 1499bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt xtables_error(PARAMETER_PROBLEM, 1509bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt "Only one `--source-port' allowed"); 1519bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt xtables_check_inverse(optarg, &invert, &optind, 0, argv); 1529bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt parse_tcp_ports(optarg, tcpinfo->spts); 1539bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt if (invert) 1549bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt tcpinfo->invflags |= XT_TCP_INV_SRCPT; 1559bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt *flags |= TCP_SRC_PORTS; 1569bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt break; 1579bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt 1589bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt case '2': 1599bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt if (*flags & TCP_DST_PORTS) 1609bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt xtables_error(PARAMETER_PROBLEM, 1619bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt "Only one `--destination-port' allowed"); 1629bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt xtables_check_inverse(optarg, &invert, &optind, 0, argv); 1639bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt parse_tcp_ports(optarg, tcpinfo->dpts); 1649bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt if (invert) 1659bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt tcpinfo->invflags |= XT_TCP_INV_DSTPT; 1669bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt *flags |= TCP_DST_PORTS; 1679bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt break; 1689bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt 1699bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt case '3': 1709bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt if (*flags & TCP_FLAGS) 1719bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt xtables_error(PARAMETER_PROBLEM, 1729bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt "Only one of `--syn' or `--tcp-flags' " 1739bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt " allowed"); 1749bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt parse_tcp_flags(tcpinfo, "SYN,RST,ACK,FIN", "SYN", invert); 1759bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt *flags |= TCP_FLAGS; 1769bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt break; 1779bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt 1789bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt case '4': 1799bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt if (*flags & TCP_FLAGS) 1809bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt xtables_error(PARAMETER_PROBLEM, 1819bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt "Only one of `--syn' or `--tcp-flags' " 1829bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt " allowed"); 1839bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt xtables_check_inverse(optarg, &invert, &optind, 0, argv); 1849bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt 1859bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt if (!argv[optind] 1869bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt || argv[optind][0] == '-' || argv[optind][0] == '!') 1879bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt xtables_error(PARAMETER_PROBLEM, 1889bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt "--tcp-flags requires two args."); 1899bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt 1909bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt parse_tcp_flags(tcpinfo, optarg, argv[optind], 1919bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt invert); 1929bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt optind++; 1939bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt *flags |= TCP_FLAGS; 1949bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt break; 1959bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt 1969bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt case '5': 1979bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt if (*flags & TCP_OPTION) 1989bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt xtables_error(PARAMETER_PROBLEM, 1999bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt "Only one `--tcp-option' allowed"); 2009bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt xtables_check_inverse(optarg, &invert, &optind, 0, argv); 2019bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt parse_tcp_option(optarg, &tcpinfo->option); 2029bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt if (invert) 2039bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt tcpinfo->invflags |= XT_TCP_INV_OPTION; 2049bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt *flags |= TCP_OPTION; 2059bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt break; 2069bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt 2079bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt default: 2089bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt return 0; 2099bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt } 2109bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt 2119bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt return 1; 2129bce59c7fef20e34a05f04d1e33a4076083dca0cDmitry Shmidt} 213 214static char * 215port_to_service(int port) 216{ 217 struct servent *service; 218 219 if ((service = getservbyport(htons(port), "tcp"))) 220 return service->s_name; 221 222 return NULL; 223} 224 225static void 226print_port(u_int16_t port, int numeric) 227{ 228 char *service; 229 230 if (numeric || (service = port_to_service(port)) == NULL) 231 printf("%u", port); 232 else 233 printf("%s", service); 234} 235 236static void 237print_ports(const char *name, u_int16_t min, u_int16_t max, 238 int invert, int numeric) 239{ 240 const char *inv = invert ? "!" : ""; 241 242 if (min != 0 || max != 0xFFFF || invert) { 243 printf("%s", name); 244 if (min == max) { 245 printf(":%s", inv); 246 print_port(min, numeric); 247 } else { 248 printf("s:%s", inv); 249 print_port(min, numeric); 250 printf(":"); 251 print_port(max, numeric); 252 } 253 printf(" "); 254 } 255} 256 257static void 258print_option(u_int8_t option, int invert, int numeric) 259{ 260 if (option || invert) 261 printf("option=%s%u ", invert ? "!" : "", option); 262} 263 264static void 265print_tcpf(u_int8_t flags) 266{ 267 int have_flag = 0; 268 269 while (flags) { 270 unsigned int i; 271 272 for (i = 0; (flags & tcp_flag_names[i].flag) == 0; i++); 273 274 if (have_flag) 275 printf(","); 276 printf("%s", tcp_flag_names[i].name); 277 have_flag = 1; 278 279 flags &= ~tcp_flag_names[i].flag; 280 } 281 282 if (!have_flag) 283 printf("NONE"); 284} 285 286static void 287print_flags(u_int8_t mask, u_int8_t cmp, int invert, int numeric) 288{ 289 if (mask || invert) { 290 printf("flags:%s", invert ? "!" : ""); 291 if (numeric) 292 printf("0x%02X/0x%02X ", mask, cmp); 293 else { 294 print_tcpf(mask); 295 printf("/"); 296 print_tcpf(cmp); 297 printf(" "); 298 } 299 } 300} 301 302static void 303tcp_print(const void *ip, const struct xt_entry_match *match, int numeric) 304{ 305 const struct xt_tcp *tcp = (struct xt_tcp *)match->data; 306 307 printf("tcp "); 308 print_ports("spt", tcp->spts[0], tcp->spts[1], 309 tcp->invflags & XT_TCP_INV_SRCPT, 310 numeric); 311 print_ports("dpt", tcp->dpts[0], tcp->dpts[1], 312 tcp->invflags & XT_TCP_INV_DSTPT, 313 numeric); 314 print_option(tcp->option, 315 tcp->invflags & XT_TCP_INV_OPTION, 316 numeric); 317 print_flags(tcp->flg_mask, tcp->flg_cmp, 318 tcp->invflags & XT_TCP_INV_FLAGS, 319 numeric); 320 if (tcp->invflags & ~XT_TCP_INV_MASK) 321 printf("Unknown invflags: 0x%X ", 322 tcp->invflags & ~XT_TCP_INV_MASK); 323} 324 325static void tcp_save(const void *ip, const struct xt_entry_match *match) 326{ 327 const struct xt_tcp *tcpinfo = (struct xt_tcp *)match->data; 328 329 if (tcpinfo->spts[0] != 0 330 || tcpinfo->spts[1] != 0xFFFF) { 331 if (tcpinfo->invflags & XT_TCP_INV_SRCPT) 332 printf("! "); 333 if (tcpinfo->spts[0] 334 != tcpinfo->spts[1]) 335 printf("--sport %u:%u ", 336 tcpinfo->spts[0], 337 tcpinfo->spts[1]); 338 else 339 printf("--sport %u ", 340 tcpinfo->spts[0]); 341 } 342 343 if (tcpinfo->dpts[0] != 0 344 || tcpinfo->dpts[1] != 0xFFFF) { 345 if (tcpinfo->invflags & XT_TCP_INV_DSTPT) 346 printf("! "); 347 if (tcpinfo->dpts[0] 348 != tcpinfo->dpts[1]) 349 printf("--dport %u:%u ", 350 tcpinfo->dpts[0], 351 tcpinfo->dpts[1]); 352 else 353 printf("--dport %u ", 354 tcpinfo->dpts[0]); 355 } 356 357 if (tcpinfo->option 358 || (tcpinfo->invflags & XT_TCP_INV_OPTION)) { 359 if (tcpinfo->invflags & XT_TCP_INV_OPTION) 360 printf("! "); 361 printf("--tcp-option %u ", tcpinfo->option); 362 } 363 364 if (tcpinfo->flg_mask 365 || (tcpinfo->invflags & XT_TCP_INV_FLAGS)) { 366 if (tcpinfo->invflags & XT_TCP_INV_FLAGS) 367 printf("! "); 368 printf("--tcp-flags "); 369 if (tcpinfo->flg_mask != 0xFF) { 370 print_tcpf(tcpinfo->flg_mask); 371 } 372 printf(" "); 373 print_tcpf(tcpinfo->flg_cmp); 374 printf(" "); 375 } 376} 377 378static struct xtables_match tcp_match = { 379 .family = NFPROTO_UNSPEC, 380 .name = "tcp", 381 .version = XTABLES_VERSION, 382 .size = XT_ALIGN(sizeof(struct xt_tcp)), 383 .userspacesize = XT_ALIGN(sizeof(struct xt_tcp)), 384 .help = tcp_help, 385 .init = tcp_init, 386 .parse = tcp_parse, 387 .print = tcp_print, 388 .save = tcp_save, 389 .extra_opts = tcp_opts, 390}; 391 392void 393_init(void) 394{ 395 xtables_register_match(&tcp_match); 396} 397