PageRenderTime 46ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/release/src/router/iptables/extensions/libipt_tcp.c

https://github.com/SgtPepperKSU/TomatoVPN
C | 416 lines | 353 code | 55 blank | 8 comment | 73 complexity | ad8df9b23bf1628dc8ffd6a2d37966c9 MD5 | raw file
  1. /* Shared library add-on to iptables to add TCP 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. /* Function which prints out usage message. */
  10. static void
  11. help(void)
  12. {
  13. printf(
  14. "TCP v%s options:\n"
  15. " --tcp-flags [!] mask comp match when TCP flags & mask == comp\n"
  16. " (Flags: SYN ACK FIN RST URG PSH ALL NONE)\n"
  17. "[!] --syn match when only SYN flag set\n"
  18. " (equivalent to --tcp-flags SYN,RST,ACK SYN)\n"
  19. " --source-port [!] port[:port]\n"
  20. " --sport ...\n"
  21. " match source port(s)\n"
  22. " --destination-port [!] port[:port]\n"
  23. " --dport ...\n"
  24. " match destination port(s)\n"
  25. " --tcp-option [!] number match if TCP option set\n\n",
  26. IPTABLES_VERSION);
  27. }
  28. static struct option opts[] = {
  29. { "source-port", 1, 0, '1' },
  30. { "sport", 1, 0, '1' }, /* synonym */
  31. { "destination-port", 1, 0, '2' },
  32. { "dport", 1, 0, '2' }, /* synonym */
  33. { "syn", 0, 0, '3' },
  34. { "tcp-flags", 1, 0, '4' },
  35. { "tcp-option", 1, 0, '5' },
  36. {0}
  37. };
  38. static void
  39. parse_tcp_ports(const char *portstring, u_int16_t *ports)
  40. {
  41. char *buffer;
  42. char *cp;
  43. buffer = strdup(portstring);
  44. if ((cp = strchr(buffer, ':')) == NULL)
  45. ports[0] = ports[1] = parse_port(buffer, "tcp");
  46. else {
  47. *cp = '\0';
  48. cp++;
  49. ports[0] = buffer[0] ? parse_port(buffer, "tcp") : 0;
  50. ports[1] = cp[0] ? parse_port(cp, "tcp") : 0xFFFF;
  51. if (ports[0] > ports[1])
  52. exit_error(PARAMETER_PROBLEM,
  53. "invalid portrange (min > max)");
  54. }
  55. free(buffer);
  56. }
  57. struct tcp_flag_names {
  58. const char *name;
  59. unsigned int flag;
  60. };
  61. static struct tcp_flag_names tcp_flag_names[]
  62. = { { "FIN", 0x01 },
  63. { "SYN", 0x02 },
  64. { "RST", 0x04 },
  65. { "PSH", 0x08 },
  66. { "ACK", 0x10 },
  67. { "URG", 0x20 },
  68. { "ALL", 0x3F },
  69. { "NONE", 0 },
  70. };
  71. static unsigned int
  72. parse_tcp_flag(const char *flags)
  73. {
  74. unsigned int ret = 0;
  75. char *ptr;
  76. char *buffer;
  77. buffer = strdup(flags);
  78. for (ptr = strtok(buffer, ","); ptr; ptr = strtok(NULL, ",")) {
  79. unsigned int i;
  80. for (i = 0;
  81. i < sizeof(tcp_flag_names)/sizeof(struct tcp_flag_names);
  82. i++) {
  83. if (strcasecmp(tcp_flag_names[i].name, ptr) == 0) {
  84. ret |= tcp_flag_names[i].flag;
  85. break;
  86. }
  87. }
  88. if (i == sizeof(tcp_flag_names)/sizeof(struct tcp_flag_names))
  89. exit_error(PARAMETER_PROBLEM,
  90. "Unknown TCP flag `%s'", ptr);
  91. }
  92. free(buffer);
  93. return ret;
  94. }
  95. static void
  96. parse_tcp_flags(struct ipt_tcp *tcpinfo,
  97. const char *mask,
  98. const char *cmp,
  99. int invert)
  100. {
  101. tcpinfo->flg_mask = parse_tcp_flag(mask);
  102. tcpinfo->flg_cmp = parse_tcp_flag(cmp);
  103. if (invert)
  104. tcpinfo->invflags |= IPT_TCP_INV_FLAGS;
  105. }
  106. static void
  107. parse_tcp_option(const char *option, u_int8_t *result)
  108. {
  109. unsigned int ret;
  110. if (string_to_number(option, 1, 255, &ret) == -1)
  111. exit_error(PARAMETER_PROBLEM, "Bad TCP option `%s'", option);
  112. *result = (u_int8_t)ret;
  113. }
  114. /* Initialize the match. */
  115. static void
  116. init(struct ipt_entry_match *m, unsigned int *nfcache)
  117. {
  118. struct ipt_tcp *tcpinfo = (struct ipt_tcp *)m->data;
  119. tcpinfo->spts[1] = tcpinfo->dpts[1] = 0xFFFF;
  120. }
  121. #define TCP_SRC_PORTS 0x01
  122. #define TCP_DST_PORTS 0x02
  123. #define TCP_FLAGS 0x04
  124. #define TCP_OPTION 0x08
  125. /* Function which parses command options; returns true if it
  126. ate an option. */
  127. static int
  128. parse(int c, char **argv, int invert, unsigned int *flags,
  129. const struct ipt_entry *entry,
  130. unsigned int *nfcache,
  131. struct ipt_entry_match **match)
  132. {
  133. struct ipt_tcp *tcpinfo = (struct ipt_tcp *)(*match)->data;
  134. switch (c) {
  135. case '1':
  136. if (*flags & TCP_SRC_PORTS)
  137. exit_error(PARAMETER_PROBLEM,
  138. "Only one `--source-port' allowed");
  139. check_inverse(optarg, &invert, &optind, 0);
  140. parse_tcp_ports(argv[optind-1], tcpinfo->spts);
  141. if (invert)
  142. tcpinfo->invflags |= IPT_TCP_INV_SRCPT;
  143. *flags |= TCP_SRC_PORTS;
  144. break;
  145. case '2':
  146. if (*flags & TCP_DST_PORTS)
  147. exit_error(PARAMETER_PROBLEM,
  148. "Only one `--destination-port' allowed");
  149. check_inverse(optarg, &invert, &optind, 0);
  150. parse_tcp_ports(argv[optind-1], tcpinfo->dpts);
  151. if (invert)
  152. tcpinfo->invflags |= IPT_TCP_INV_DSTPT;
  153. *flags |= TCP_DST_PORTS;
  154. break;
  155. case '3':
  156. if (*flags & TCP_FLAGS)
  157. exit_error(PARAMETER_PROBLEM,
  158. "Only one of `--syn' or `--tcp-flags' "
  159. " allowed");
  160. parse_tcp_flags(tcpinfo, "SYN,RST,ACK,FIN", "SYN", invert);
  161. *flags |= TCP_FLAGS;
  162. break;
  163. case '4':
  164. if (*flags & TCP_FLAGS)
  165. exit_error(PARAMETER_PROBLEM,
  166. "Only one of `--syn' or `--tcp-flags' "
  167. " allowed");
  168. check_inverse(optarg, &invert, &optind, 0);
  169. if (!argv[optind]
  170. || argv[optind][0] == '-' || argv[optind][0] == '!')
  171. exit_error(PARAMETER_PROBLEM,
  172. "--tcp-flags requires two args.");
  173. parse_tcp_flags(tcpinfo, argv[optind-1], argv[optind],
  174. invert);
  175. optind++;
  176. *flags |= TCP_FLAGS;
  177. break;
  178. case '5':
  179. if (*flags & TCP_OPTION)
  180. exit_error(PARAMETER_PROBLEM,
  181. "Only one `--tcp-option' allowed");
  182. check_inverse(optarg, &invert, &optind, 0);
  183. parse_tcp_option(argv[optind-1], &tcpinfo->option);
  184. if (invert)
  185. tcpinfo->invflags |= IPT_TCP_INV_OPTION;
  186. *flags |= TCP_OPTION;
  187. break;
  188. default:
  189. return 0;
  190. }
  191. return 1;
  192. }
  193. /* Final check; we don't care. */
  194. static void
  195. final_check(unsigned int flags)
  196. {
  197. }
  198. static char *
  199. port_to_service(int port)
  200. {
  201. struct servent *service;
  202. if ((service = getservbyport(htons(port), "tcp")))
  203. return service->s_name;
  204. return NULL;
  205. }
  206. static void
  207. print_port(u_int16_t port, int numeric)
  208. {
  209. char *service;
  210. if (numeric || (service = port_to_service(port)) == NULL)
  211. printf("%u", port);
  212. else
  213. printf("%s", service);
  214. }
  215. static void
  216. print_ports(const char *name, u_int16_t min, u_int16_t max,
  217. int invert, int numeric)
  218. {
  219. const char *inv = invert ? "!" : "";
  220. if (min != 0 || max != 0xFFFF || invert) {
  221. printf("%s", name);
  222. if (min == max) {
  223. printf(":%s", inv);
  224. print_port(min, numeric);
  225. } else {
  226. printf("s:%s", inv);
  227. print_port(min, numeric);
  228. printf(":");
  229. print_port(max, numeric);
  230. }
  231. printf(" ");
  232. }
  233. }
  234. static void
  235. print_option(u_int8_t option, int invert, int numeric)
  236. {
  237. if (option || invert)
  238. printf("option=%s%u ", invert ? "!" : "", option);
  239. }
  240. static void
  241. print_tcpf(u_int8_t flags)
  242. {
  243. int have_flag = 0;
  244. while (flags) {
  245. unsigned int i;
  246. for (i = 0; (flags & tcp_flag_names[i].flag) == 0; i++);
  247. if (have_flag)
  248. printf(",");
  249. printf("%s", tcp_flag_names[i].name);
  250. have_flag = 1;
  251. flags &= ~tcp_flag_names[i].flag;
  252. }
  253. if (!have_flag)
  254. printf("NONE");
  255. }
  256. static void
  257. print_flags(u_int8_t mask, u_int8_t cmp, int invert, int numeric)
  258. {
  259. if (mask || invert) {
  260. printf("flags:%s", invert ? "!" : "");
  261. if (numeric)
  262. printf("0x%02X/0x%02X ", mask, cmp);
  263. else {
  264. print_tcpf(mask);
  265. printf("/");
  266. print_tcpf(cmp);
  267. printf(" ");
  268. }
  269. }
  270. }
  271. /* Prints out the union ipt_matchinfo. */
  272. static void
  273. print(const struct ipt_ip *ip,
  274. const struct ipt_entry_match *match, int numeric)
  275. {
  276. const struct ipt_tcp *tcp = (struct ipt_tcp *)match->data;
  277. printf("tcp ");
  278. print_ports("spt", tcp->spts[0], tcp->spts[1],
  279. tcp->invflags & IPT_TCP_INV_SRCPT,
  280. numeric);
  281. print_ports("dpt", tcp->dpts[0], tcp->dpts[1],
  282. tcp->invflags & IPT_TCP_INV_DSTPT,
  283. numeric);
  284. print_option(tcp->option,
  285. tcp->invflags & IPT_TCP_INV_OPTION,
  286. numeric);
  287. print_flags(tcp->flg_mask, tcp->flg_cmp,
  288. tcp->invflags & IPT_TCP_INV_FLAGS,
  289. numeric);
  290. if (tcp->invflags & ~IPT_TCP_INV_MASK)
  291. printf("Unknown invflags: 0x%X ",
  292. tcp->invflags & ~IPT_TCP_INV_MASK);
  293. }
  294. /* Saves the union ipt_matchinfo in parsable form to stdout. */
  295. static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
  296. {
  297. const struct ipt_tcp *tcpinfo = (struct ipt_tcp *)match->data;
  298. if (tcpinfo->spts[0] != 0
  299. || tcpinfo->spts[1] != 0xFFFF) {
  300. if (tcpinfo->invflags & IPT_TCP_INV_SRCPT)
  301. printf("! ");
  302. if (tcpinfo->spts[0]
  303. != tcpinfo->spts[1])
  304. printf("--sport %u:%u ",
  305. tcpinfo->spts[0],
  306. tcpinfo->spts[1]);
  307. else
  308. printf("--sport %u ",
  309. tcpinfo->spts[0]);
  310. }
  311. if (tcpinfo->dpts[0] != 0
  312. || tcpinfo->dpts[1] != 0xFFFF) {
  313. if (tcpinfo->invflags & IPT_TCP_INV_DSTPT)
  314. printf("! ");
  315. if (tcpinfo->dpts[0]
  316. != tcpinfo->dpts[1])
  317. printf("--dport %u:%u ",
  318. tcpinfo->dpts[0],
  319. tcpinfo->dpts[1]);
  320. else
  321. printf("--dport %u ",
  322. tcpinfo->dpts[0]);
  323. }
  324. if (tcpinfo->option
  325. || (tcpinfo->invflags & IPT_TCP_INV_OPTION)) {
  326. if (tcpinfo->invflags & IPT_TCP_INV_OPTION)
  327. printf("! ");
  328. printf("--tcp-option %u ", tcpinfo->option);
  329. }
  330. if (tcpinfo->flg_mask
  331. || (tcpinfo->invflags & IPT_TCP_INV_FLAGS)) {
  332. if (tcpinfo->invflags & IPT_TCP_INV_FLAGS)
  333. printf("! ");
  334. printf("--tcp-flags ");
  335. if (tcpinfo->flg_mask != 0xFF) {
  336. print_tcpf(tcpinfo->flg_mask);
  337. }
  338. printf(" ");
  339. print_tcpf(tcpinfo->flg_cmp);
  340. printf(" ");
  341. }
  342. }
  343. static struct iptables_match tcp = {
  344. .next = NULL,
  345. .name = "tcp",
  346. .version = IPTABLES_VERSION,
  347. .size = IPT_ALIGN(sizeof(struct ipt_tcp)),
  348. .userspacesize = IPT_ALIGN(sizeof(struct ipt_tcp)),
  349. .help = &help,
  350. .init = &init,
  351. .parse = &parse,
  352. .final_check = &final_check,
  353. .print = &print,
  354. .save = &save,
  355. .extra_opts = opts
  356. };
  357. void
  358. _init(void)
  359. {
  360. register_match(&tcp);
  361. }