portmap.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  1. /* $Id$ */
  2. /*
  3. * Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
  4. * Copyright (c) 2013-2017 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  5. *
  6. * The Tcpreplay Suite of tools is free software: you can redistribute it
  7. * and/or modify it under the terms of the GNU General Public License as
  8. * published by the Free Software Foundation, either version 3 of the
  9. * License, or with the authors permission any later version.
  10. *
  11. * The Tcpreplay Suite is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with the Tcpreplay Suite. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. /*
  20. * This file contains routines to manipulate port maps, in which
  21. * one port number is mapped to another.
  22. */
  23. #include "config.h"
  24. #include "defines.h"
  25. #include "common.h"
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include <errno.h>
  29. #include "tcpreplay.h"
  30. #include "tcpedit.h"
  31. #include "portmap.h"
  32. #include "incremental_checksum.h"
  33. /**
  34. * mallocs a new tcpedit_portmap_t structure
  35. */
  36. tcpedit_portmap_t *
  37. new_portmap()
  38. {
  39. tcpedit_portmap_t *newportmap;
  40. newportmap = (tcpedit_portmap_t *)safe_malloc(sizeof(tcpedit_portmap_t));
  41. return (newportmap);
  42. }
  43. /**
  44. * \brief parses a string <port>:<port> and returns a new tcpedit_portmap_t struct
  45. *
  46. * We support the following formats:
  47. * <port>:<port> - map a single port to a new port
  48. * <port>-<port>:<port> - map a range of ports to a new port
  49. * <port>+<port>+...:<port> - map a list of ports to a single ports
  50. *
  51. * In the case of port ranges or port lists, we actually return a
  52. * chain of tcpedit_portmap_t's
  53. */
  54. static tcpedit_portmap_t *
  55. ports2PORT(char *ports)
  56. {
  57. tcpedit_portmap_t *portmap = NULL, *portmap_head = NULL, *portmap_last = NULL;
  58. char *from_s, *to_s, *from_begin, *from_end, *badchar;
  59. long from_l, to_l, from_b, from_e, i;
  60. char *token = NULL, *token2 = NULL;
  61. assert(ports);
  62. from_begin = NULL;
  63. from_end = NULL;
  64. /* first split the port numbers */
  65. from_s = strtok_r(ports, ":", &token);
  66. to_s = strtok_r(NULL, ":", &token);
  67. /* if there's anything left, it's a syntax error */
  68. if (strtok_r(NULL, ":", &token) != NULL)
  69. return NULL;
  70. /* if either of the parsed strings is NULL, we have a problem */
  71. if (from_s == NULL || to_s == NULL)
  72. return NULL;
  73. /* source map can have - (range) or , (and), but not both */
  74. if (strchr(from_s, '-') && strchr(from_s, '+'))
  75. return NULL;
  76. /* process to the to port */
  77. to_l = strtol(to_s, &badchar, 10);
  78. if (strlen(badchar) != 0)
  79. return NULL;
  80. if (to_l > 65535 || to_l < 0)
  81. return NULL;
  82. /*
  83. * put the new portmap info into the new node
  84. * while we convert to network-byte order, b/c its better
  85. * to do it once now, rather then each time we have to do a lookup
  86. */
  87. portmap_head = new_portmap();
  88. portmap = portmap_head;
  89. /* process a range, setting from_begin & from_end */
  90. if (strchr(from_s, '-')) {
  91. from_begin = strtok_r(from_s, "-", &token2);
  92. from_end = strtok_r(NULL, "-", &token2);
  93. from_b = strtol(from_begin, &badchar, 10);
  94. if (strlen(badchar) != 0) {
  95. free(portmap);
  96. return NULL;
  97. }
  98. from_e = strtol(from_end, &badchar, 10);
  99. if (strlen(badchar) != 0) {
  100. free(portmap);
  101. return NULL;
  102. }
  103. if (from_b > 65535 || from_b < 0 || from_e > 65535 || from_e < 0) {
  104. free(portmap);
  105. return NULL;
  106. }
  107. for (i = from_b; i <= from_e; i++) {
  108. portmap->from = htons(i);
  109. portmap->to = htons(to_l);
  110. portmap->next = new_portmap();
  111. portmap_last = portmap;
  112. portmap = portmap->next;
  113. }
  114. portmap_last->next = NULL;
  115. free(portmap);
  116. }
  117. /* process a list via +, filling in list[] */
  118. else if (strchr(from_s, '+')) {
  119. from_begin = strtok_r(from_s, "+", &token2);
  120. from_l = strtol(from_begin, &badchar, 10);
  121. if (strlen(badchar) != 0) {
  122. free(portmap);
  123. return NULL;
  124. }
  125. portmap->to = htons(to_l);
  126. portmap->from = htons(from_l);
  127. while ((from_begin = strtok_r(NULL, "+", &token2)) != NULL) {
  128. from_l = strtol(from_begin, &badchar, 10);
  129. if (strlen(badchar) != 0 || from_l > 65535 || from_l < 0) {
  130. portmap = portmap_head;
  131. while (portmap) {
  132. tcpedit_portmap_t *tmp_portmap = portmap->next;
  133. free(portmap);
  134. portmap = tmp_portmap;
  135. }
  136. return NULL;
  137. }
  138. portmap->next = new_portmap();
  139. portmap = portmap->next;
  140. portmap->to = htons(to_l);
  141. portmap->from = htons(from_l);
  142. }
  143. }
  144. /* this is just the old port:port format */
  145. else {
  146. /*
  147. * convert the strings to longs: if badchar points to anything
  148. * after, then it was a bad string
  149. */
  150. from_l = strtol(from_s, &badchar, 10);
  151. if (strlen(badchar) != 0 || from_l > 65535 || from_l < 0) {
  152. free(portmap);
  153. return NULL;
  154. }
  155. portmap->to = htons(to_l);
  156. portmap->from = htons(from_l);
  157. }
  158. /* return structure for success */
  159. return portmap_head;
  160. }
  161. /**
  162. * Processes a string (ourstr) containing the portmap ("2000:4000" for
  163. * example) and places the data in **portmapdata and finally returns 1 for
  164. * success, 0 for fail.
  165. */
  166. int
  167. parse_portmap(tcpedit_portmap_t ** portmap, const char *ourstr)
  168. {
  169. tcpedit_portmap_t *portmap_ptr;
  170. char *substr = NULL, *ourstrcpy = NULL, *token = NULL;
  171. assert(ourstr);
  172. ourstrcpy = safe_strdup(ourstr);
  173. /* first iteration of input */
  174. substr = strtok_r(ourstrcpy, ",", &token);
  175. if ((*portmap = ports2PORT(substr)) == NULL)
  176. return 0;
  177. portmap_ptr = *portmap;
  178. /* ports2PORT may return a chain, so find the end of it */
  179. while (portmap_ptr->next != NULL)
  180. portmap_ptr = portmap_ptr->next;
  181. while (1) {
  182. substr = strtok_r(NULL, ",", &token);
  183. /* if that was the last one, kick out */
  184. if (substr == NULL)
  185. break;
  186. /* process next record */
  187. portmap_ptr->next = ports2PORT(substr);
  188. /* ports2PORT may return a chain, so find the end of it */
  189. while (portmap_ptr->next != NULL)
  190. portmap_ptr = portmap_ptr->next;
  191. }
  192. safe_free(ourstrcpy);
  193. return 1;
  194. }
  195. /**
  196. * Free's all the memory associated with the given portmap chain
  197. */
  198. void
  199. free_portmap(tcpedit_portmap_t * portmap)
  200. {
  201. assert(portmap);
  202. /* recursively go down the portmaps */
  203. if (portmap->next != NULL)
  204. free_portmap(portmap->next);
  205. safe_free(portmap);
  206. }
  207. /**
  208. * This function takes a pointer to a portmap list and prints each node
  209. */
  210. void
  211. print_portmap(tcpedit_portmap_t *portmap_data)
  212. {
  213. tcpedit_portmap_t *portmap_ptr;
  214. assert(portmap_data);
  215. portmap_ptr = portmap_data;
  216. while (portmap_ptr != NULL) {
  217. printf("from: %ld to: %ld\n", portmap_ptr->from, portmap_ptr->to);
  218. portmap_ptr = portmap_ptr->next;
  219. }
  220. printf("\n");
  221. }
  222. /**
  223. * This function takes a portmap and a port, and returns the mapped port,
  224. * or the original port if it isn't mapped to anything.
  225. */
  226. long
  227. map_port(tcpedit_portmap_t *portmap_data, long port)
  228. {
  229. tcpedit_portmap_t *portmap_ptr;
  230. long newport;
  231. assert(portmap_data);
  232. portmap_ptr = portmap_data;
  233. newport = port;
  234. /* step through the nodes, resetting newport if a match is found */
  235. while (portmap_ptr != NULL) {
  236. if (portmap_ptr->from == port)
  237. newport = portmap_ptr->to;
  238. portmap_ptr = portmap_ptr->next;
  239. }
  240. return(newport);
  241. }
  242. /**
  243. * rewrites the TCP or UDP ports based on a portmap
  244. * returns 1 for changes made or 0 for none
  245. */
  246. static int
  247. rewrite_ports(tcpedit_t *tcpedit, u_char protocol, u_char *layer4)
  248. {
  249. tcp_hdr_t *tcp_hdr = NULL;
  250. udp_hdr_t *udp_hdr = NULL;
  251. uint16_t newport;
  252. tcpedit_portmap_t *portmap;
  253. assert(tcpedit);
  254. assert(tcpedit->portmap);
  255. portmap = tcpedit->portmap;
  256. if (protocol == IPPROTO_TCP) {
  257. tcp_hdr = (tcp_hdr_t *)layer4;
  258. /* check if we need to remap the destination port */
  259. newport = map_port(portmap, tcp_hdr->th_dport);
  260. if (newport != tcp_hdr->th_dport) {
  261. csum_replace2(&tcp_hdr->th_sum, tcp_hdr->th_dport, newport);
  262. tcp_hdr->th_dport = newport;
  263. }
  264. /* check if we need to remap the source port */
  265. newport = map_port(portmap, tcp_hdr->th_sport);
  266. if (newport != tcp_hdr->th_sport) {
  267. csum_replace2(&tcp_hdr->th_sum, tcp_hdr->th_sport, newport);
  268. tcp_hdr->th_sport = newport;
  269. }
  270. } else if (protocol == IPPROTO_UDP) {
  271. udp_hdr = (udp_hdr_t *)layer4;
  272. /* check if we need to remap the destination port */
  273. newport = map_port(portmap, udp_hdr->uh_dport);
  274. if (newport != udp_hdr->uh_dport) {
  275. if (udp_hdr->uh_sum) {
  276. csum_replace2(&udp_hdr->uh_sum, udp_hdr->uh_dport, newport);
  277. }
  278. udp_hdr->uh_dport = newport;
  279. }
  280. /* check if we need to remap the source port */
  281. newport = map_port(portmap, udp_hdr->uh_sport);
  282. if (newport != udp_hdr->uh_sport) {
  283. if (udp_hdr->uh_sum) {
  284. csum_replace2(&udp_hdr->uh_sum, udp_hdr->uh_sport, newport);
  285. }
  286. udp_hdr->uh_sport = newport;
  287. }
  288. }
  289. return 0;
  290. }
  291. int
  292. rewrite_ipv4_ports(tcpedit_t *tcpedit, ipv4_hdr_t **ip_hdr)
  293. {
  294. assert(tcpedit);
  295. u_char *l4;
  296. if (*ip_hdr == NULL) {
  297. return 0;
  298. } else if ((*ip_hdr)->ip_p == IPPROTO_TCP || (*ip_hdr)->ip_p == IPPROTO_UDP) {
  299. l4 = get_layer4_v4(*ip_hdr, 65536);
  300. return rewrite_ports(tcpedit, (*ip_hdr)->ip_p, l4);
  301. }
  302. return 0;
  303. }
  304. int
  305. rewrite_ipv6_ports(tcpedit_t *tcpedit, ipv6_hdr_t **ip6_hdr)
  306. {
  307. assert(tcpedit);
  308. u_char *l4;
  309. if (*ip6_hdr == NULL) {
  310. return 0;
  311. } else if ((*ip6_hdr)->ip_nh == IPPROTO_TCP || (*ip6_hdr)->ip_nh == IPPROTO_UDP) {
  312. l4 = get_layer4_v6(*ip6_hdr, 65535);
  313. return rewrite_ports(tcpedit, (*ip6_hdr)->ip_nh, l4);
  314. }
  315. return 0;
  316. }