/* $Id$ */ /* * Copyright (c) 2001-2010 Aaron Turner * Copyright (c) 2013-2024 Fred Klassen - AppNeta * * The Tcpreplay Suite of tools is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or with the authors permission any later version. * * The Tcpreplay Suite is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with the Tcpreplay Suite. If not, see . */ #include "parse_args.h" #include "config.h" #include "portmap.h" #include "tcpedit.h" #include "tcpedit_stub.h" #include #include /** * returns 0 for success w/o errors * returns 1 for success w/ warnings * returns -1 for error */ int tcpedit_post_args(tcpedit_t *tcpedit) { int rcode; int i; uint32_t seed = 1, rand_num; assert(tcpedit); /* --pnat */ if (HAVE_OPT(PNAT)) { int ct = STACKCT_OPT(PNAT); char **list = (char **)STACKLST_OPT(PNAT); int first = 1; tcpedit->rewrite_ip = true; do { char *p = *list++; if (first) { if (!parse_cidr_map(&tcpedit->cidrmap1, p)) { tcpedit_seterr(tcpedit, "Unable to parse first --pnat=%s", p); return -1; } } else { if (!parse_cidr_map(&tcpedit->cidrmap2, p)) { tcpedit_seterr(tcpedit, "Unable to parse second --pnat=%s", p); return -1; } } first = 0; } while (--ct > 0); } /* --srcipmap */ if (HAVE_OPT(SRCIPMAP)) { tcpedit->rewrite_ip = true; if (!parse_cidr_map(&tcpedit->srcipmap, OPT_ARG(SRCIPMAP))) { tcpedit_seterr(tcpedit, "Unable to parse --srcipmap=%s", OPT_ARG(SRCIPMAP)); return -1; } } /* --dstipmap */ if (HAVE_OPT(DSTIPMAP)) { tcpedit->rewrite_ip = true; if (!parse_cidr_map(&tcpedit->dstipmap, OPT_ARG(DSTIPMAP))) { tcpedit_seterr(tcpedit, "Unable to parse --dstipmap=%s", OPT_ARG(DSTIPMAP)); return -1; } } /* * If we have one and only one -N, then use the same map data * for both interfaces/files */ if ((tcpedit->cidrmap1 != NULL) && (tcpedit->cidrmap2 == NULL)) tcpedit->cidrmap2 = tcpedit->cidrmap1; /* --fixcsum */ if (HAVE_OPT(FIXCSUM)) tcpedit->fixcsum = true; /* --fixhdrlen */ if (HAVE_OPT(FIXHDRLEN)) tcpedit->fixhdrlen = true; /* --efcs */ if (HAVE_OPT(EFCS)) tcpedit->efcs = true; /* --ttl */ if (HAVE_OPT(TTL)) { long ttl; if (strchr(OPT_ARG(TTL), '+')) { tcpedit->ttl_mode = TCPEDIT_TTL_MODE_ADD; } else if (strchr(OPT_ARG(TTL), '-')) { tcpedit->ttl_mode = TCPEDIT_TTL_MODE_SUB; } else { tcpedit->ttl_mode = TCPEDIT_TTL_MODE_SET; } ttl = strtol(OPT_ARG(TTL), (char **)NULL, 10); if (ttl < 0) ttl *= -1; /* convert to positive value */ if (ttl > 255) { tcpedit_seterr(tcpedit, "Invalid --ttl value (must be 0-255): %ld", ttl); return -1; } tcpedit->ttl_value = (u_int8_t)ttl; } /* --tos */ if (HAVE_OPT(TOS)) tcpedit->tos = OPT_VALUE_TOS; /* --tclass */ if (HAVE_OPT(TCLASS)) tcpedit->tclass = OPT_VALUE_TCLASS; /* --flowlabel */ if (HAVE_OPT(FLOWLABEL)) tcpedit->flowlabel = OPT_VALUE_FLOWLABEL; /* --mtu */ if (HAVE_OPT(MTU)) tcpedit->mtu = OPT_VALUE_MTU; /* --mtu-trunc */ if (HAVE_OPT(MTU_TRUNC)) tcpedit->mtu_truncate = true; /* --skipbroadcast */ if (HAVE_OPT(SKIPBROADCAST)) tcpedit->skip_broadcast = true; /* --fixlen */ if (HAVE_OPT(FIXLEN)) { if (strcmp(OPT_ARG(FIXLEN), "pad") == 0) { tcpedit->fixlen = TCPEDIT_FIXLEN_PAD; } else if (strcmp(OPT_ARG(FIXLEN), "trunc") == 0) { tcpedit->fixlen = TCPEDIT_FIXLEN_TRUNC; } else if (strcmp(OPT_ARG(FIXLEN), "del") == 0) { tcpedit->fixlen = TCPEDIT_FIXLEN_DEL; } else { tcpedit_seterr(tcpedit, "Invalid --fixlen=%s", OPT_ARG(FIXLEN)); return -1; } } /* --rewrite-sequence */ if (HAVE_OPT(TCP_SEQUENCE)) { tcpedit->tcp_sequence_enable = 1; seed = OPT_VALUE_TCP_SEQUENCE; for (i = 0; i < 5; ++i) rand_num = tcpr_random(&seed); tcpedit->tcp_sequence_adjust = rand_num; } /* TCP/UDP port rewriting */ if (HAVE_OPT(PORTMAP)) { int ct = STACKCT_OPT(PORTMAP); char **list = (char **)STACKLST_OPT(PORTMAP); int first = 1; tcpedit_portmap_t *portmap_head, *portmap; do { char *p = *list++; if (first) { if (!parse_portmap(&tcpedit->portmap, p)) { tcpedit_seterr(tcpedit, "Unable to parse --portmap=%s", p); return -1; } } else { if (!parse_portmap(&portmap, p)) { tcpedit_seterr(tcpedit, "Unable to parse --portmap=%s", p); return -1; } /* append to end of tcpedit->portmap linked list */ portmap_head = tcpedit->portmap; while (portmap_head->next != NULL) portmap_head = portmap_head->next; portmap_head->next = portmap; } first = 0; } while (--ct > 0); } /* * IP address rewriting processing. Update seed by making * 5 calls to tcpr_random() as our mixer for randomizing. This should * work better since most people aren't going to write out values * close to 32bit integers. */ if (HAVE_OPT(SEED)) { tcpedit->rewrite_ip = true; seed = OPT_VALUE_SEED; } else if (HAVE_OPT(FUZZ_SEED)) { /* --fuzz-seed */ seed = OPT_VALUE_FUZZ_SEED; tcpedit->fuzz_factor = OPT_VALUE_FUZZ_FACTOR; } for (i = 0; i < 5; ++i) rand_num = tcpr_random(&seed); srandom(rand_num); if (HAVE_OPT(SEED)) { tcpedit->rewrite_ip = true; tcpedit->seed = seed; } if (HAVE_OPT(FUZZ_SEED)) { /* --fuzz-seed */ tcpedit->fuzz_seed = seed; } if (HAVE_OPT(ENDPOINTS)) { tcpedit->rewrite_ip = true; if (!parse_endpoints(&tcpedit->cidrmap1, &tcpedit->cidrmap2, OPT_ARG(ENDPOINTS))) { tcpedit_seterr(tcpedit, "Unable to parse --endpoints=%s", OPT_ARG(ENDPOINTS)); return -1; } } /* parse the tcpedit dlt args */ rcode = tcpedit_dlt_post_args(tcpedit); if (rcode < 0) { errx(-1, "Unable to parse args: %s", tcpedit_geterr(tcpedit)); } else if (rcode == 1) { warnx("%s", tcpedit_geterr(tcpedit)); } return 0; }