portmap.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  1. /* $Id$ */
  2. /*
  3. * Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
  4. * Copyright (c) 2013-2018 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;
  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_last = portmap_head;
  89. /* process a range, setting from_begin & from_end */
  90. if (strchr(from_s, '-')) {
  91. long i;
  92. from_begin = strtok_r(from_s, "-", &token2);
  93. from_end = strtok_r(NULL, "-", &token2);
  94. long from_b = strtol(from_begin, &badchar, 10);
  95. if (strlen(badchar) != 0) {
  96. free(portmap);
  97. return NULL;
  98. }
  99. long from_e = strtol(from_end, &badchar, 10);
  100. if (from_b > 65535 || from_b < 0 || from_e > 65535 || from_e < 0) {
  101. free(portmap);
  102. return NULL;
  103. }
  104. for (i = from_b; i <= from_e; i++) {
  105. portmap->from = htons(i);
  106. portmap->to = htons(to_l);
  107. portmap->next = new_portmap();
  108. portmap_last = portmap;
  109. portmap = portmap->next;
  110. }
  111. portmap_last->next = NULL;
  112. }
  113. /* process a list via +, filling in list[] */
  114. else if (strchr(from_s, '+')) {
  115. from_begin = strtok_r(from_s, "+", &token2);
  116. from_l = strtol(from_begin, &badchar, 10);
  117. if (strlen(badchar) != 0) {
  118. free(portmap);
  119. return NULL;
  120. }
  121. portmap->to = htons(to_l);
  122. portmap->from = htons(from_l);
  123. while ((from_begin = strtok_r(NULL, "+", &token2)) != NULL) {
  124. from_l = strtol(from_begin, &badchar, 10);
  125. if (strlen(badchar) != 0 || from_l > 65535 || from_l < 0) {
  126. portmap = portmap_head;
  127. while (portmap) {
  128. tcpedit_portmap_t *tmp_portmap = portmap->next;
  129. free(portmap);
  130. portmap = tmp_portmap;
  131. }
  132. return NULL;
  133. }
  134. portmap->next = new_portmap();
  135. portmap = portmap->next;
  136. portmap->to = htons(to_l);
  137. portmap->from = htons(from_l);
  138. }
  139. }
  140. /* this is just the old port:port format */
  141. else {
  142. /*
  143. * convert the strings to longs: if badchar points to anything
  144. * after, then it was a bad string
  145. */
  146. from_l = strtol(from_s, &badchar, 10);
  147. if (strlen(badchar) != 0 || from_l > 65535 || from_l < 0) {
  148. free(portmap);
  149. return NULL;
  150. }
  151. portmap->to = htons(to_l);
  152. portmap->from = htons(from_l);
  153. }
  154. /* return structure for success */
  155. return portmap_head;
  156. }
  157. /**
  158. * Processes a string (ourstr) containing the portmap ("2000:4000" for
  159. * example) and places the data in **portmapdata and finally returns 1 for
  160. * success, 0 for fail.
  161. */
  162. int
  163. parse_portmap(tcpedit_portmap_t ** portmap, const char *ourstr)
  164. {
  165. tcpedit_portmap_t *portmap_ptr;
  166. char *substr, *ourstrcpy, *token = NULL;
  167. assert(ourstr);
  168. ourstrcpy = safe_strdup(ourstr);
  169. /* first iteration of input */
  170. substr = strtok_r(ourstrcpy, ",", &token);
  171. if ((*portmap = ports2PORT(substr)) == NULL) {
  172. safe_free(ourstrcpy);
  173. return 0;
  174. }
  175. portmap_ptr = *portmap;
  176. /* ports2PORT may return a chain, so find the end of it */
  177. while (portmap_ptr->next != NULL)
  178. portmap_ptr = portmap_ptr->next;
  179. while (1) {
  180. substr = strtok_r(NULL, ",", &token);
  181. /* if that was the last one, kick out */
  182. if (substr == NULL)
  183. break;
  184. /* process next record */
  185. portmap_ptr->next = ports2PORT(substr);
  186. /* ports2PORT may return a chain, so find the end of it */
  187. while (portmap_ptr->next != NULL)
  188. portmap_ptr = portmap_ptr->next;
  189. }
  190. safe_free(ourstrcpy);
  191. return 1;
  192. }
  193. /**
  194. * Free's all the memory associated with the given portmap chain
  195. */
  196. void
  197. free_portmap(tcpedit_portmap_t * portmap)
  198. {
  199. assert(portmap);
  200. /* recursively go down the portmaps */
  201. if (portmap->next != NULL)
  202. free_portmap(portmap->next);
  203. safe_free(portmap);
  204. }
  205. /**
  206. * This function takes a pointer to a portmap list and prints each node
  207. */
  208. void
  209. print_portmap(tcpedit_portmap_t *portmap_data)
  210. {
  211. tcpedit_portmap_t *portmap_ptr;
  212. assert(portmap_data);
  213. portmap_ptr = portmap_data;
  214. while (portmap_ptr != NULL) {
  215. printf("from: %ld to: %ld\n", portmap_ptr->from, portmap_ptr->to);
  216. portmap_ptr = portmap_ptr->next;
  217. }
  218. printf("\n");
  219. }
  220. /**
  221. * This function takes a portmap and a port, and returns the mapped port,
  222. * or the original port if it isn't mapped to anything.
  223. */
  224. long
  225. map_port(tcpedit_portmap_t *portmap_data, long port)
  226. {
  227. tcpedit_portmap_t *portmap_ptr;
  228. long newport;
  229. assert(portmap_data);
  230. portmap_ptr = portmap_data;
  231. newport = port;
  232. /* step through the nodes, resetting newport if a match is found */
  233. while (portmap_ptr != NULL) {
  234. if (portmap_ptr->from == port)
  235. newport = portmap_ptr->to;
  236. portmap_ptr = portmap_ptr->next;
  237. }
  238. return(newport);
  239. }
  240. /**
  241. * rewrites the TCP or UDP ports based on a portmap
  242. * returns 1 for changes made or 0 for none
  243. */
  244. static int
  245. rewrite_ports(tcpedit_t *tcpedit, u_char protocol, u_char *layer4,
  246. const int l4len)
  247. {
  248. tcp_hdr_t *tcp_hdr = NULL;
  249. udp_hdr_t *udp_hdr = NULL;
  250. volatile uint16_t newport;
  251. tcpedit_portmap_t *portmap;
  252. assert(tcpedit);
  253. assert(tcpedit->portmap);
  254. portmap = tcpedit->portmap;
  255. if (protocol == IPPROTO_TCP) {
  256. if (l4len < (int)sizeof(tcp_hdr_t)) {
  257. tcpedit_setwarn(tcpedit, "caplen to small to set TCP port: l4 len=%d",
  258. l4len);
  259. return TCPEDIT_WARN;
  260. }
  261. tcp_hdr = (tcp_hdr_t *)layer4;
  262. /* check if we need to remap the destination port */
  263. newport = map_port(portmap, tcp_hdr->th_dport);
  264. if (newport != tcp_hdr->th_dport) {
  265. csum_replace2(&tcp_hdr->th_sum, tcp_hdr->th_dport, newport);
  266. tcp_hdr->th_dport = newport;
  267. }
  268. /* check if we need to remap the source port */
  269. newport = map_port(portmap, tcp_hdr->th_sport);
  270. if (newport != tcp_hdr->th_sport) {
  271. csum_replace2(&tcp_hdr->th_sum, tcp_hdr->th_sport, newport);
  272. tcp_hdr->th_sport = newport;
  273. }
  274. } else if (protocol == IPPROTO_UDP) {
  275. if (l4len < (int)sizeof(udp_hdr_t)) {
  276. tcpedit_setwarn(tcpedit, "caplen to small to set UDP port: l4 len=%d",
  277. l4len);
  278. return TCPEDIT_WARN;
  279. }
  280. udp_hdr = (udp_hdr_t *)layer4;
  281. /* check if we need to remap the destination port */
  282. newport = map_port(portmap, udp_hdr->uh_dport);
  283. if (newport != udp_hdr->uh_dport) {
  284. if (udp_hdr->uh_sum) {
  285. csum_replace2(&udp_hdr->uh_sum, udp_hdr->uh_dport, newport);
  286. }
  287. udp_hdr->uh_dport = newport;
  288. }
  289. /* check if we need to remap the source port */
  290. newport = map_port(portmap, udp_hdr->uh_sport);
  291. if (newport != udp_hdr->uh_sport) {
  292. if (udp_hdr->uh_sum) {
  293. csum_replace2(&udp_hdr->uh_sum, udp_hdr->uh_sport, newport);
  294. }
  295. udp_hdr->uh_sport = newport;
  296. }
  297. }
  298. return 0;
  299. }
  300. int
  301. rewrite_ipv4_ports(tcpedit_t *tcpedit, ipv4_hdr_t **ip_hdr, const int l3len)
  302. {
  303. assert(tcpedit);
  304. u_char *l4;
  305. if (*ip_hdr == NULL || ip_hdr == NULL) {
  306. tcpedit_seterr(tcpedit, "rewrite_ipv4_ports: NULL IP header: l3 len=%d",
  307. l3len);
  308. return TCPEDIT_ERROR;
  309. } else if ((*ip_hdr)->ip_p == IPPROTO_TCP || (*ip_hdr)->ip_p == IPPROTO_UDP) {
  310. l4 = get_layer4_v4(*ip_hdr, l3len);
  311. if (l4)
  312. return rewrite_ports(tcpedit, (*ip_hdr)->ip_p, l4,
  313. l3len - (l4 - (u_char*)*ip_hdr));
  314. tcpedit_setwarn(tcpedit, "Unable to rewrite ports on IP header: l3 len=%d",
  315. l3len);
  316. return TCPEDIT_WARN;
  317. }
  318. return 0;
  319. }
  320. int
  321. rewrite_ipv6_ports(tcpedit_t *tcpedit, ipv6_hdr_t **ip6_hdr, const int l3len)
  322. {
  323. assert(tcpedit);
  324. u_char *l4;
  325. if (*ip6_hdr == NULL || ip6_hdr == NULL) {
  326. tcpedit_seterr(tcpedit, "rewrite_ipv6_ports: NULL IPv6 header: l3 len=%d",
  327. l3len);
  328. return TCPEDIT_ERROR;
  329. } else if ((*ip6_hdr)->ip_nh == IPPROTO_TCP || (*ip6_hdr)->ip_nh == IPPROTO_UDP) {
  330. l4 = get_layer4_v6(*ip6_hdr, l3len);
  331. if (l4)
  332. return rewrite_ports(tcpedit, (*ip6_hdr)->ip_nh, l4,
  333. l3len - (l4 - (u_char*)*ip6_hdr));
  334. tcpedit_setwarn(tcpedit, "Unable to rewrite ports on IPv6 header: l3 len=%d",
  335. l3len);
  336. return TCPEDIT_WARN;
  337. }
  338. return 0;
  339. }