portmap.c 11 KB

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