From 6386bdc20b4a154a91d6038180373fdc7aecaa33 Mon Sep 17 00:00:00 2001 From: Fernando Gont Date: Wed, 16 Oct 2024 04:05:59 -0300 Subject: [PATCH] Format source code with clang-format --- tools/addr6.c | 3418 ++++++------- tools/addr6.h | 122 +- tools/flow6.c | 1529 +++--- tools/flow6.h | 5 +- tools/frag6.c | 5057 ++++++++++--------- tools/frag6.h | 48 +- tools/icmp6.c | 4048 ++++++++-------- tools/icmp6.h | 2 - tools/ipv6toolkit.h | 5 +- tools/jumbo6.c | 2170 ++++----- tools/jumbo6.h | 3 +- tools/libipv6.c | 7161 ++++++++++++++------------- tools/libipv6.h | 1471 +++--- tools/mldq6.c | 1783 ++++--- tools/mldq6.h | 2 - tools/na6.c | 3174 ++++++------ tools/na6.h | 2 - tools/ni6.c | 4817 +++++++++--------- tools/ni6.h | 7 +- tools/ns6.c | 3182 ++++++------ tools/ns6.h | 2 - tools/path6.c | 3535 +++++++------- tools/path6.h | 32 +- tools/ra6.c | 3966 ++++++++------- tools/ra6.h | 18 +- tools/rd6.c | 4031 ++++++++-------- tools/rd6.h | 2 - tools/rs6.c | 1682 ++++--- tools/rs6.h | 2 - tools/scan6.c | 11001 +++++++++++++++++++++--------------------- tools/scan6.h | 204 +- tools/tcp6.c | 5668 +++++++++++----------- tools/tcp6.h | 171 +- tools/udp6.c | 3893 ++++++++------- tools/udp6.h | 12 +- 35 files changed, 35810 insertions(+), 36415 deletions(-) diff --git a/tools/addr6.c b/tools/addr6.c index b207883..402648a 100644 --- a/tools/addr6.c +++ b/tools/addr6.c @@ -16,7 +16,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - * + * * Build with: make addr6 * * It requires that the libpcap library be installed on your system. @@ -24,19 +24,19 @@ * Please send any bug reports to Fernando Gont */ -#include #include #include #include +#include #include #include -#include #include -#include -#include +#include #include +#include +#include #include #include @@ -44,1557 +44,1568 @@ #include "ipv6toolkit.h" #include "libipv6.h" -void usage(void); -void print_help(void); -void stat_ipv6_address(struct decode6 *, struct stats6 *); -void print_dec_address_script(struct decode6 *); -int init_host_list(struct hashed_host_list *); -uint16_t key(struct hashed_host_list *, struct in6_addr *); -struct hashed_host_entry * add_hashed_host_entry(struct hashed_host_list *, struct in6_addr *); -unsigned int is_ip6_in_hashed_list(struct hashed_host_list *, struct in6_addr *); -void print_stats(struct stats6 *); - -unsigned char stdin_f=FALSE, addr_f=FALSE, verbose_f=FALSE, decode_f=FALSE, block_duplicate_f=FALSE; -unsigned char block_duplicate_preflen_f=FALSE, stats_f=FALSE, filter_f=FALSE, canonic_f=FALSE; -unsigned char fixed_f=FALSE, print_unique_preflen_f= FALSE, pattern_f=FALSE, response_f=FALSE; -unsigned char reverse_f=FALSE; -unsigned int pstart, pend; -unsigned int caddr=0, naddr=0; -char line[MAX_LINE_SIZE]; - -extern char *optarg; -extern int optind, opterr, optopt; - -int main(int argc, char **argv){ - struct decode6 addr; - struct stats6 stats; - struct hashed_host_list hlist; - int r; - char *ptr, *pref, *charptr, *lasts, *endptr; - unsigned long ul_res; - char pv6addr[INET6_ADDRSTRLEN]; - char prefstr[5]; /* Buffer to store a prefix such as /128 */ - unsigned int accept_type=0, block_type=0, accept_scope=0, block_scope=0, accept_itype=0, block_itype=0; - unsigned int accept_utype=0, block_utype=0; - - unsigned char accepted_f=FALSE, acceptfilters_f=FALSE, duplicate_f=FALSE, flag_f=FALSE; - - /* Block Filters */ - struct in6_addr block[MAX_BLOCK], *ptable = NULL; - struct in6_addr genaddr, randaddr; - uint8_t genpref = 0; - - uint32_t *pcounter = NULL, pthres, pratio; - uint8_t blocklen[MAX_BLOCK]; - unsigned int nblock=0; - - /* Accept Filters */ - struct in6_addr accept[MAX_ACCEPT]; - uint8_t acceptlen[MAX_ACCEPT]; - unsigned int naccept=0, i, j, k; - - /* Filter based on prefix length */ - uint8_t dpreflen=128; /* To avoid warnings */ - - pid_t pid; - struct in6_addr dummyipv6; - struct timeval time; - - static struct option longopts[] = { - {"address", required_argument, 0, 'a'}, - {"gen-addr", required_argument, 0, 'A'}, - {"stdin", no_argument, 0, 'i'}, - {"print-canonic", no_argument, 0, 'c'}, - {"print-decode", no_argument, 0, 'd'}, - {"print-fixed", no_argument, 0, 'f'}, - {"print-reverse", no_argument, 0, 'r'}, - {"print-stats", no_argument, 0, 's'}, - {"print-pattern", required_argument, 0, 'x'}, - {"print-response", no_argument, 0, 'R'}, - {"block-dup", no_argument, 0, 'q'}, - {"print-unique", no_argument, 0, 'Q'}, - {"print-uni-preflen", required_argument, 0, 'P'}, - {"block-dup-preflen", required_argument, 0, 'p'}, - {"accept", required_argument, 0, 'j'}, - {"accept-type", required_argument, 0, 'b'}, - {"accept-scope", required_argument, 0, 'k'}, - {"accept-utype", required_argument, 0, 'w'}, - {"accept-iid", required_argument, 0, 'g'}, - {"block", required_argument, 0, 'J'}, - {"block-type", required_argument, 0, 'B'}, - {"block-scope", required_argument, 0, 'K'}, - {"block-utype", required_argument, 0, 'W'}, - {"block-iid", required_argument, 0, 'G'}, - {"verbose", no_argument, 0, 'v'}, - {"help", no_argument, 0, 'h'}, - {0, 0, 0, 0 }, - }; - - const char shortopts[]= "a:A:icrdfsx:RqQP:p:j:b:k:w:g:J:B:K:W:G:vh"; - - char option; - - if(argc<=1){ - usage(); - exit(EXIT_FAILURE); - } - - release_privileges(); - - while((r=getopt_long(argc, argv, shortopts, longopts, NULL)) != -1 && r != '?') { - option= r; - - switch(option){ - case 'a': - if( inet_pton(AF_INET6, optarg, &(addr.ip6)) <= 0){ - puts("inet_pton(): address not valid"); - exit(EXIT_FAILURE); - } - - addr_f= TRUE; - break; - - case 'A': - if((charptr = strtok_r(optarg, "/", &lasts)) == NULL){ - puts("Error in Prefix"); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, charptr, &genaddr) <= 0){ - puts("inet_pton(): Source Address not valid"); - exit(EXIT_FAILURE); - } - - - if((charptr = strtok_r(NULL, " ", &lasts)) != NULL){ - genpref = atoi(charptr); - - if(genpref > 128){ - puts("Prefix length error in IPv6 Source Address"); - exit(EXIT_FAILURE); - } - } else { - puts("Missing Prefix Length"); - exit(EXIT_FAILURE); - } - - if(gettimeofday(&time, NULL) == -1){ - perror("addr6"); - exit(EXIT_FAILURE); - } - - pid= getpid(); - srandom((unsigned int) time.tv_sec + (unsigned int) time.tv_usec + (unsigned int) pid); - randomize_ipv6_addr(&randaddr, &genaddr, genpref); - - if(inet_ntop(AF_INET6, &randaddr, pv6addr, sizeof(pv6addr)) == NULL){ - puts("inet_ntop(): Error converting IPv6 address to presentation format"); - exit(EXIT_FAILURE); - } - - puts(pv6addr); - - exit(EXIT_SUCCESS); - break; - - case 'i': /* Read from stdin */ - stdin_f= TRUE; - break; - - case 'c': /* Print addresses in canonic form */ - canonic_f= TRUE; - break; - - case 'f': /* Print addresses with fixed length */ - fixed_f= TRUE; - break; - - case 'd': /* Decode IPv6 addresses */ - decode_f= TRUE; - break; - - case 'r': /* Print addresses in reversed form */ - reverse_f= TRUE; - break; - - case 'j': /* IPv6 Address (accept) filter */ - if(naccept > MAX_ACCEPT){ - puts("Too many IPv6 Address (accept) filters."); - exit(EXIT_FAILURE); - } - - if((pref = strtok_r(optarg, "/", &lasts)) == NULL){ - printf("Error in IPv6 Address (accept) filter number %u.\n", naccept+1); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, pref, &accept[naccept]) <= 0){ - printf("Error in IPv6 Address (accept) filter number %u.\n", naccept+1); - exit(EXIT_FAILURE); - } - - if((charptr = strtok_r(NULL, " ", &lasts)) == NULL){ - acceptlen[naccept] = 128; - } - else{ - acceptlen[naccept] = atoi(charptr); - - if(acceptlen[naccept]>128){ - printf("Length error in IPv6 Source Address (accept) filter number %u.\n", naccept+1); - exit(EXIT_FAILURE); - } - } - - sanitize_ipv6_prefix(&accept[naccept], acceptlen[naccept]); - naccept++; - acceptfilters_f= TRUE; - filter_f= TRUE; - break; - - case 'J': /* IPv6 Address (block) filter */ - if(nblock >= MAX_BLOCK){ - puts("Too many IPv6 Source Address (block) filters."); - exit(EXIT_FAILURE); - } - - if((pref = strtok_r(optarg, "/", &lasts)) == NULL){ - printf("Error in IPv6 Address (block) filter number %u.\n", nblock+1); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, pref, &block[nblock]) <= 0){ - printf("Error in IPv6 Source Address (block) filter number %u.", nblock+1); - exit(EXIT_FAILURE); - } - - if((charptr = strtok_r(NULL, " ", &lasts)) == NULL){ - blocklen[nblock] = 128; - } - else{ - blocklen[nblock] = atoi(charptr); - - if(blocklen[nblock]>128){ - printf("Length error in IPv6 Address (block) filter number %u.\n", nblock+1); - exit(EXIT_FAILURE); - } - } - - sanitize_ipv6_prefix(&block[nblock], blocklen[nblock]); - - nblock++; - filter_f= TRUE; - break; - - case 'b': /* Accept type filter */ - if(strncmp(optarg, "unicast", MAX_TYPE_SIZE) == 0){ - accept_type |= IPV6_UNICAST; - } - else if(strncmp(optarg, "unspec", MAX_TYPE_SIZE) == 0 || strncmp(optarg, "unspecified", MAX_TYPE_SIZE) == 0){ - accept_type |= IPV6_UNSPEC; - } - else if(strncmp(optarg, "multicast", MAX_TYPE_SIZE) == 0){ - accept_type |= IPV6_MULTICAST; - } - else{ - printf("Unknown address type '%s' in accept type filter\n", optarg); - exit(EXIT_FAILURE); - } - - acceptfilters_f= TRUE; - filter_f= TRUE; - break; - - case 'B': /* Block type filter */ - if(strncmp(optarg, "unicast", MAX_TYPE_SIZE) == 0){ - block_type |= IPV6_UNICAST; - } - else if(strncmp(optarg, "unspec", MAX_TYPE_SIZE) == 0 || strncmp(optarg, "unspecified", MAX_TYPE_SIZE) == 0){ - block_type |= IPV6_UNSPEC; - } - else if(strncmp(optarg, "multicast", MAX_TYPE_SIZE) == 0){ - block_type |= IPV6_MULTICAST; - } - else{ - printf("Unknown address type '%s' in block type filter\n", optarg); - exit(EXIT_FAILURE); - } - - filter_f= TRUE; - break; - - case 'k': /* Accept scope filter */ - if(strncmp(optarg, "reserved", MAX_TYPE_SIZE) == 0){ - accept_scope |= SCOPE_RESERVED; - } - else if(strncmp(optarg, "interface", MAX_TYPE_SIZE) == 0 || strncmp(optarg, "interface-local", MAX_TYPE_SIZE) == 0){ - accept_scope |= SCOPE_INTERFACE; - } - else if(strncmp(optarg, "link", MAX_TYPE_SIZE) == 0 || strncmp(optarg, "link-local", MAX_TYPE_SIZE) == 0){ - accept_scope |= SCOPE_LINK; - } - else if(strncmp(optarg, "admin", MAX_TYPE_SIZE) == 0 || strncmp(optarg, "admin-local", MAX_TYPE_SIZE) == 0){ - accept_scope |= SCOPE_ADMIN; - } - else if(strncmp(optarg, "site", MAX_TYPE_SIZE) == 0 || strncmp(optarg, "site-local", MAX_TYPE_SIZE) == 0){ - accept_scope |= SCOPE_SITE; - } - else if(strncmp(optarg, "organization", MAX_TYPE_SIZE) == 0 || strncmp(optarg, "organization-local", MAX_TYPE_SIZE) == 0){ - accept_scope |= SCOPE_ORGANIZATION; - } - else if(strncmp(optarg, "global", MAX_TYPE_SIZE) == 0){ - accept_scope |= SCOPE_GLOBAL; - } - else if(strncmp(optarg, "unassigned", MAX_TYPE_SIZE) == 0){ - accept_scope |= SCOPE_UNASSIGNED; - } - else if(strncmp(optarg, "unspecified", MAX_TYPE_SIZE) == 0){ - accept_scope |= SCOPE_UNSPECIFIED; - } - else{ - printf("Unknown address scope '%s' in accept scope filter\n", optarg); - exit(EXIT_FAILURE); - } - - acceptfilters_f= TRUE; - filter_f= TRUE; - break; - - case 'K': /* Block scope filter */ - if(strncmp(optarg, "reserved", MAX_TYPE_SIZE) == 0){ - block_scope |= SCOPE_RESERVED; - } - else if(strncmp(optarg, "interface", MAX_TYPE_SIZE) == 0 || strncmp(optarg, "interface-local", MAX_TYPE_SIZE) == 0){ - block_scope |= SCOPE_INTERFACE; - } - else if(strncmp(optarg, "link", MAX_TYPE_SIZE) == 0 || strncmp(optarg, "link-local", MAX_TYPE_SIZE) == 0){ - block_scope |= SCOPE_LINK; - } - else if(strncmp(optarg, "admin", MAX_TYPE_SIZE) == 0 || strncmp(optarg, "admin-local", MAX_TYPE_SIZE) == 0){ - block_scope |= SCOPE_ADMIN; - } - else if(strncmp(optarg, "site", MAX_TYPE_SIZE) == 0 || strncmp(optarg, "site-local", MAX_TYPE_SIZE) == 0){ - block_scope |= SCOPE_SITE; - } - else if(strncmp(optarg, "organization", MAX_TYPE_SIZE) == 0 || strncmp(optarg, "organization-local", MAX_TYPE_SIZE) == 0){ - block_scope |= SCOPE_ORGANIZATION; - } - else if(strncmp(optarg, "global", MAX_TYPE_SIZE) == 0){ - block_scope |= SCOPE_GLOBAL; - } - else if(strncmp(optarg, "unassigned", MAX_TYPE_SIZE) == 0){ - block_scope |= SCOPE_UNASSIGNED; - } - else if(strncmp(optarg, "unspecified", MAX_TYPE_SIZE) == 0){ - block_scope |= SCOPE_UNSPECIFIED; - } - else{ - printf("Unknown address scope '%s' in block scope filter\n", optarg); - exit(EXIT_FAILURE); - } - - filter_f= TRUE; - break; - - case 'w': /* Accept unicast type filter */ - if(strncmp(optarg, "loopback", MAX_TYPE_SIZE) == 0){ - accept_utype |= UCAST_LOOPBACK; - } - else if(strncmp(optarg, "ipv4-compat", MAX_TYPE_SIZE) == 0 || strncmp(optarg, "ipv4-compatible", MAX_TYPE_SIZE) == 0){ - accept_utype |= UCAST_V4COMPAT; - } - else if(strncmp(optarg, "ipv4-mapped", MAX_TYPE_SIZE) == 0){ - accept_utype |= UCAST_V4MAPPED; - } - else if(strncmp(optarg, "link-local", MAX_TYPE_SIZE) == 0){ - accept_utype |= UCAST_LINKLOCAL; - } - else if(strncmp(optarg, "site-local", MAX_TYPE_SIZE) == 0){ - accept_utype |= UCAST_SITELOCAL; - } - else if(strncmp(optarg, "unique-local", MAX_TYPE_SIZE) == 0 || strncmp(optarg, "ula", MAX_TYPE_SIZE) == 0){ - accept_utype |= UCAST_UNIQUELOCAL; - } - else if(strncmp(optarg, "6to4", MAX_TYPE_SIZE) == 0){ - accept_utype |= UCAST_6TO4; - } - else if(strncmp(optarg, "teredo", MAX_TYPE_SIZE) == 0){ - accept_utype |= UCAST_TEREDO; - } - else if(strncmp(optarg, "global", MAX_TYPE_SIZE) == 0 || strncmp(optarg, "normal", MAX_TYPE_SIZE) == 0){ - accept_utype |= UCAST_GLOBAL; - } - else{ - printf("Unknown unicast address type '%s' in accept unicast address type filter\n", optarg); - exit(EXIT_FAILURE); - } - - acceptfilters_f= TRUE; - filter_f= TRUE; - break; - - - case 'W': /* Block unicast type filter */ - if(strncmp(optarg, "loopback", MAX_TYPE_SIZE) == 0){ - block_utype |= UCAST_LOOPBACK; - } - else if(strncmp(optarg, "ipv4-compat", MAX_TYPE_SIZE) == 0 || strncmp(optarg, "ipv4-compatible", MAX_TYPE_SIZE) == 0){ - block_utype |= UCAST_V4COMPAT; - } - else if(strncmp(optarg, "ipv4-mapped", MAX_TYPE_SIZE) == 0){ - block_utype |= UCAST_V4MAPPED; - } - else if(strncmp(optarg, "link-local", MAX_TYPE_SIZE) == 0){ - block_utype |= UCAST_LINKLOCAL; - } - else if(strncmp(optarg, "site-local", MAX_TYPE_SIZE) == 0){ - block_utype |= UCAST_SITELOCAL; - } - else if(strncmp(optarg, "unique-local", MAX_TYPE_SIZE) == 0 || strncmp(optarg, "ula", MAX_TYPE_SIZE) == 0){ - block_utype |= UCAST_UNIQUELOCAL; - } - else if(strncmp(optarg, "6to4", MAX_TYPE_SIZE) == 0){ - block_utype |= UCAST_6TO4; - } - else if(strncmp(optarg, "teredo", MAX_TYPE_SIZE) == 0){ - block_utype |= UCAST_TEREDO; - } - else if(strncmp(optarg, "global", MAX_TYPE_SIZE) == 0 || strncmp(optarg, "normal", MAX_TYPE_SIZE) == 0){ - block_utype |= UCAST_GLOBAL; - } - else{ - printf("Unknown unicast address type '%s' in block unicast address type filter\n", optarg); - exit(EXIT_FAILURE); - } - - filter_f= TRUE; - break; - - case 'g': /* Accept IID filter */ - if(strncmp(optarg, "ieee", MAX_TYPE_SIZE) == 0){ - accept_itype |= IID_MACDERIVED; - } - else if(strncmp(optarg, "isatap", MAX_TYPE_SIZE) == 0 || strncmp(optarg, "ISATAP", MAX_TYPE_SIZE) == 0){ - accept_itype |= IID_ISATAP; - } - else if(strncmp(optarg, "ipv4-32", MAX_TYPE_SIZE) == 0){ - accept_itype |= IID_EMBEDDEDIPV4; - } - else if(strncmp(optarg, "ipv4-64", MAX_TYPE_SIZE) == 0){ - accept_itype |= IID_EMBEDDEDIPV4_64; - } - else if(strncmp(optarg, "ipv4-all", MAX_TYPE_SIZE) == 0){ - accept_itype |= IID_EMBEDDEDIPV4; - accept_itype |= IID_EMBEDDEDIPV4_64; - } - else if(strncmp(optarg, "embed-port", MAX_TYPE_SIZE) == 0 || strncmp(optarg, "port", MAX_TYPE_SIZE) == 0){ - accept_itype |= IID_EMBEDDEDPORT; - } - else if(strncmp(optarg, "embed-port-rev", MAX_TYPE_SIZE) == 0 || strncmp(optarg, "port-rev", MAX_TYPE_SIZE) == 0){ - accept_itype |= IID_EMBEDDEDPORTREV; - } - else if(strncmp(optarg, "embed-port-all", MAX_TYPE_SIZE) == 0 || strncmp(optarg, "port-all", MAX_TYPE_SIZE) == 0){ - accept_itype |= IID_EMBEDDEDPORT; - accept_itype |= IID_EMBEDDEDPORTREV; - } - else if(strncmp(optarg, "low-byte", MAX_TYPE_SIZE) == 0 || strncmp(optarg, "lowbyte", MAX_TYPE_SIZE) == 0){ - accept_itype |= IID_LOWBYTE; - } - else if(strncmp(optarg, "byte-pattern", MAX_TYPE_SIZE) == 0 || strncmp(optarg, "bytepattern", MAX_TYPE_SIZE) == 0){ - accept_itype |= IID_PATTERN_BYTES; - } - else if(strncmp(optarg, "random", MAX_TYPE_SIZE) == 0 || strncmp(optarg, "randomized", MAX_TYPE_SIZE) == 0){ - accept_itype |= IID_RANDOM; - } - else{ - printf("Unknown IID type '%s' in accept IID type filter.\n", optarg); - exit(EXIT_FAILURE); - } - - acceptfilters_f= TRUE; - filter_f= TRUE; - break; - - case 'G': /* Block IID filter */ - if(strncmp(optarg, "ieee", MAX_TYPE_SIZE) == 0){ - block_itype |= IID_MACDERIVED; - } - else if(strncmp(optarg, "isatap", MAX_TYPE_SIZE) == 0 || strncmp(optarg, "ISATAP", MAX_TYPE_SIZE) == 0){ - block_itype |= IID_ISATAP; - } - else if(strncmp(optarg, "ipv4-32", MAX_TYPE_SIZE) == 0){ - block_itype |= IID_EMBEDDEDIPV4; - } - else if(strncmp(optarg, "ipv4-64", MAX_TYPE_SIZE) == 0){ - block_itype |= IID_EMBEDDEDIPV4_64; - } - else if(strncmp(optarg, "ipv4-all", MAX_TYPE_SIZE) == 0){ - block_itype |= IID_EMBEDDEDIPV4; - block_itype |= IID_EMBEDDEDIPV4_64; - } - else if(strncmp(optarg, "embed-port", MAX_TYPE_SIZE) == 0 || strncmp(optarg, "port", MAX_TYPE_SIZE) == 0){ - block_itype |= IID_EMBEDDEDPORT; - } - else if(strncmp(optarg, "embed-port-rev", MAX_TYPE_SIZE) == 0 || strncmp(optarg, "port-rev", MAX_TYPE_SIZE) == 0){ - block_itype |= IID_EMBEDDEDPORTREV; - } - else if(strncmp(optarg, "embed-port-all", MAX_TYPE_SIZE) == 0 || strncmp(optarg, "port-all", MAX_TYPE_SIZE) == 0){ - block_itype |= IID_EMBEDDEDPORT; - block_itype |= IID_EMBEDDEDPORTREV; - } - else if(strncmp(optarg, "low-byte", MAX_TYPE_SIZE) == 0 || strncmp(optarg, "lowbyte", MAX_TYPE_SIZE) == 0){ - block_itype |= IID_LOWBYTE; - } - else if(strncmp(optarg, "byte-pattern", MAX_TYPE_SIZE) == 0 || strncmp(optarg, "bytepattern", MAX_TYPE_SIZE) == 0){ - block_itype |= IID_PATTERN_BYTES; - } - else if(strncmp(optarg, "random", MAX_TYPE_SIZE) == 0 || strncmp(optarg, "randomized", MAX_TYPE_SIZE) == 0){ - block_itype |= IID_RANDOM; - } - else{ - printf("Unknown IID type '%s' in block IID type filter.\n", optarg); - exit(EXIT_FAILURE); - } - - filter_f= TRUE; - break; - - case 's': /* Generate IPv6 Address Statistics */ - stats_f= TRUE; - break; - - case 'q': /* Block duplicate addresses */ - case 'Q': /* For backwards-compatibility */ - block_duplicate_f= TRUE; - break; - - case 'p': /* Filter duplicate addresses on a per-prefix basis */ - if(block_duplicate_preflen_f){ - puts("Error: Cannot specify multiple --block-dup-preflen options"); - exit(EXIT_FAILURE); - } - - if((pref=strtok_r(optarg, "/", &lasts)) == NULL){ - puts("Error in '--block-dup-preflen' option"); - exit(EXIT_FAILURE); - } - - if((ul_res = strtoul(pref, &endptr, 10)) == ULONG_MAX){ - perror("Error in '--block-dup-preflen' option"); - exit(EXIT_FAILURE); - } - - if(endptr != pref){ - dpreflen = ul_res; - block_duplicate_preflen_f= TRUE; - } - else{ - puts("Error in '--block-dup-preflen' option"); - exit(EXIT_FAILURE); - } - - break; - - case 'P': /* Generate unique prefixes of specified length */ - if(print_unique_preflen_f){ - puts("Error: Cannot specify multiple --print-unique-preflen options"); - exit(EXIT_FAILURE); - } - - if((pref=strtok_r(optarg, "/", &lasts)) == NULL){ - puts("Error in '--print-unique-preflen' option"); - exit(EXIT_FAILURE); - } - - if((ul_res = strtoul(pref, &endptr, 10)) == ULONG_MAX){ - perror("Error in '--print-unique-preflen' option"); - exit(EXIT_FAILURE); - } - - if(endptr != pref){ - dpreflen = ul_res; - print_unique_preflen_f= TRUE; - } - else{ - puts("Error in '--print-unique-preflen' option"); - exit(EXIT_FAILURE); - } - - break; - - case 'x': /* Print pattern */ - pattern_f=1; - - if(sscanf(optarg, "/%u:/%u:%u%%", &pstart, &pend, &pratio) == 3){ - if(pstart % 8 != 0 || pend % 8 != 0){ - puts("Must specify range as /n1:/n2:p% where n1 and n2 are multiples of 8, and p is percentage"); - exit(EXIT_FAILURE); - } - - pstart= pstart/8; - - if(pstart > 0) - pstart= pstart - 1; - - pend= pend/8; - - if(pend > 0) - pend= pend - 1; - - } - else if(sscanf(optarg, "%u:%u:%u%%", &pstart, &pend, &pratio) != 3){ - puts("Must specify range as n1:n2:, where n1 and n2 are smaller than 16, and p is a percentage"); - exit(EXIT_FAILURE); - } - - if(pstart >= pend || pstart > 15 || pend > 15){ - puts("Inappropriate range for prefix analysis"); - exit(EXIT_FAILURE); - } - - if(pratio <= 0 || pratio > 100){ - puts("Error: percentage must be larger than 0 and smaller (or equal) to 100\n"); - exit(EXIT_FAILURE); - } - - printf("N1: %u, N2: %u\n", pstart, pend); - - if( (ptable= malloc(16 * MAX_ADDR_PATTERN)) == NULL){ - puts("Not enough memory"); - exit(EXIT_FAILURE); - } - - if( (pcounter= malloc(sizeof(uint32_t) * MAX_ADDR_PATTERN)) == NULL){ - puts("Not enough memory"); - exit(EXIT_FAILURE); - } - - break; - - case 'R': /* Be verbose */ - response_f=TRUE; - break; - - case 'v': /* Be verbose */ - verbose_f++; - break; - - case 'h': /* Help */ - print_help(); - exit(EXIT_FAILURE); - break; - - default: - usage(); - exit(EXIT_FAILURE); - break; - - } /* switch */ - } /* while(getopt) */ - - - /* Catch simultaneous use of incompatible addresses */ - - if(stdin_f && addr_f){ - puts("Cannot specify both '-a' and '-i' at the same time (try only one of them at a time)"); - exit(EXIT_FAILURE); - } - - if(!stdin_f && !addr_f){ - puts("Must specify an IPv6 address with '-a', or set '-i' to read addresses from stdin"); - exit(EXIT_FAILURE); - } - - if(!stdin_f){ - if(stats_f){ - puts("Cannot obtain statistics based on a single IPv6 address (should be using '-i')"); - exit(EXIT_FAILURE); - } - else if(pattern_f){ - puts("Cannot analyze pattern based on a single IPv6 address (should be using '-i')"); - exit(EXIT_FAILURE); - } - } - - if(block_duplicate_f && block_duplicate_preflen_f){ - puts("Cannot employ --block-dup and --block-dup-preflen options simultaneously"); - exit(EXIT_FAILURE); - } - - if(print_unique_preflen_f && (block_duplicate_f || block_duplicate_preflen_f)){ - puts("Cannot employ --print-unique-preflen with --block-dup or --block-dup-preflen options simultaneously"); - exit(EXIT_FAILURE); - } - - if(canonic_f && fixed_f){ - puts("Cannot employ --print-canonic and --print-fixed simultaneously"); - exit(EXIT_FAILURE); - } - - /* By default, addr6 decodes IPv6 addresses */ - if(!block_duplicate_f && !block_duplicate_preflen_f && !print_unique_preflen_f && !filter_f && !stats_f &&\ - !canonic_f && !fixed_f && !reverse_f) - decode_f=TRUE; - - if(block_duplicate_f || block_duplicate_preflen_f || print_unique_preflen_f){ - if(!init_host_list(&hlist)){ - puts("Not enough memory when initializing internal host list"); - exit(EXIT_FAILURE); - } - } - - if(stats_f){ - memset(&stats, 0, sizeof(stats)); - } - - - if(stdin_f){ - while(fgets(line, MAX_LINE_SIZE, stdin) != NULL){ - r= read_prefix(line, Strnlen(line, MAX_LINE_SIZE), &ptr); - - if(r==1){ - if ( inet_pton(AF_INET6, ptr, &(addr.ip6)) <= 0){ - if(decode_f) - puts("Error: Invalid IPv6 address"); - - continue; - } - - if(filter_f || decode_f || stats_f) - decode_ipv6_address(&addr); - - - if(nblock){ - if(match_ipv6(block, blocklen, nblock, &(addr.ip6))){ - if(response_f) - puts("REJECT"); - - continue; - } - } - - if(block_type || block_scope || block_itype || block_utype){ - if( (block_type & addr.type) || (block_utype & addr.subtype)\ - || (block_scope & addr.scope) || (block_itype & addr.iidtype)){ - if(response_f) - puts("REJECT"); - - continue; - } - } - - if(block_duplicate_f && is_ip6_in_hashed_list(&hlist, &(addr.ip6))){ - if(response_f) - puts("REJECT"); - - continue; - } - else if(block_duplicate_preflen_f || print_unique_preflen_f){ - dummyipv6= addr.ip6; - sanitize_ipv6_prefix(&dummyipv6, dpreflen); - - if(is_ip6_in_hashed_list(&hlist, &dummyipv6)){ - if(response_f) - puts("REJECT"); - - continue; - } - } - - accepted_f=0; - - if(naccept){ - if(match_ipv6(accept, acceptlen, naccept, &(addr.ip6))) - accepted_f= TRUE; - } - - if(!accepted_f && (accept_type || accept_scope || accept_itype || accept_utype)){ - if( (accept_type & addr.type) || (accept_utype & addr.subtype)\ - || (accept_scope & addr.scope) || (accept_itype & addr.iidtype)) - accepted_f= TRUE; - } - - if(acceptfilters_f && !accepted_f){ - if(response_f) - puts("REJECT"); - - continue; - } - /* - If we got here, and block_duplicate_f is TRUE, then this address is unique, and we must add it to - the hashed list. - */ - if(block_duplicate_f){ - if(add_hashed_host_entry(&hlist, &(addr.ip6)) == NULL){ - puts("Not enough memory (or hit internal artificial limit) when storing IPv6 address in memory"); - exit(EXIT_FAILURE); - } - } - else if(block_duplicate_preflen_f || print_unique_preflen_f){ - dummyipv6= addr.ip6; - sanitize_ipv6_prefix(&dummyipv6, dpreflen); - - if(add_hashed_host_entry(&hlist, &dummyipv6) == NULL){ - puts("Not enough memory (or hit internal artificial limit) when storing IPv6 address in memory"); - exit(EXIT_FAILURE); - } - } - - if(filter_f && response_f){ - puts("ACCEPT"); - continue; - } - - if(stats_f){ - stat_ipv6_address(&addr, &stats); - } - else if(decode_f){ - print_dec_address_script(&addr); - } - else if(reverse_f){ - print_ipv6_address_rev(&(addr.ip6)); - } - else if(pattern_f){ - /* XXX */ - /* Analyze address pattern */ - if(caddr >= MAX_ADDR_PATTERN){ - puts("Too many addresses for pattern analysis. Filter them out in smaller subsets, and retry"); - exit(EXIT_FAILURE); - } - - *(ptable+caddr)=addr.ip6; - -/* - puts("Direcciones hasta ahora"); - for(i=0; i<=caddr; i++){ - if(inet_ntof(AF_INET6, ptable+caddr, pv6addr, sizeof(pv6addr)) == NULL){ - puts("inet_ntof(): Error converting IPv6 address to fixed presentation format"); - exit(EXIT_FAILURE); - } - - printf("Address #%u: %s\n", i, pv6addr); - } - - puts(""); -*/ - /* Initialize counters for this address to 0 */ - for(i=0; i<16; i++){ - *(pcounter + (caddr * 16) + i)=0; - } - - /* Compute differences in bytes */ - for(naddr=0; naddr < caddr; naddr++){ - for(j=0; j<4; j++){ - for(k=0; k<4; k++){ - -/*printf("Comparo: %08x con %08x\n", (ntohl((ptable+naddr)->s6_addr32[j]) & (0xff000000>>(k*8))) , (ntohl((ptable+caddr)->s6_addr32[j]) & (0xff000000>>(k*8))));*/ - if( (ntohl((ptable+naddr)->s6_addr32[j]) & (0xff000000>>(k*8))) != (ntohl((ptable+caddr)->s6_addr32[j]) & (0xff000000>>(k*8)))){ - /* If the bytes were different, increment counters for both addresses */ - (*(pcounter + (naddr * 16) + j * 4 + k))++; - (*(pcounter + (caddr * 16) + j * 4 + k))++; - } - } - } - } - - caddr++; - } - else{ - if(print_unique_preflen_f){ - sanitize_ipv6_prefix(&(addr.ip6), dpreflen); - snprintf(prefstr, sizeof(prefstr), "/%u", (unsigned int) dpreflen); - } - else{ - prefstr[0]=0; /* zero-terminate the prefix string, since we don't need to print a prefix */ - } - - if(fixed_f){ - if(inet_ntof(AF_INET6, &(addr.ip6), pv6addr, sizeof(pv6addr)) == NULL){ - puts("inet_ntof(): Error converting IPv6 address to fixed presentation format"); - exit(EXIT_FAILURE); - } - } - else{ - if(inet_ntop(AF_INET6, &(addr.ip6), pv6addr, sizeof(pv6addr)) == NULL){ - puts("inet_ntop(): Error converting IPv6 address to fixed format"); - exit(EXIT_FAILURE); - } - } - - printf("%s%s\n", pv6addr, prefstr); - } - } - } - - if(stats_f){ - print_stats(&stats); - } - - else if(pattern_f){ - pthres= ((unsigned long) caddr * (100 - pratio)) / 100; - - for(i=0; i < caddr; i++){ - flag_f=0; - - for(j=pstart; j<= pend; j++){ - if(*(pcounter + i * 16 + j) <= pthres){ - flag_f=1; - } - } - - /* - If flag is set to 1, we identified some pattern -- the search space can be reduced - We just need to avoid specifying the same range twice - */ - - duplicate_f=0; - - if(flag_f == 1){ - /* We go around comparing the current address with al the previous ones */ - for(j=0; (j pthres){ - break; - } - else if((ntohl((ptable+i)->s6_addr32[k/4]) & (0xff000000>>((k%4)*8))) != (ntohl((ptable+j)->s6_addr32[k/4])\ - & (0xff000000>>((k%4)*8)))){ - break; - } - } - else if(*(pcounter + j * 16 + k) <= pthres){ - break; - } - } - - if(k>pend){ - duplicate_f=1; - } - } - - if(!duplicate_f){ - /* The address in 'i' is a unique range */ - for(k=0;k<16; k++){ - if(*(pcounter + i * 16 + k) <= pthres){ - /* (ntohl((ptable+i)->s6_addr32[k/4]) & (0xff000000>>((k%4)*8))) >> ( (3 - (k%4)) * 8) */ - printf("%02x%s", ((ntohl((ptable+i)->s6_addr32[k/4]) & (0xff000000>>((k%4)*8))) >> ( (3 - (k%4)) * 8)), \ - (k<15)?";":"\n"); - } - else{ - printf("0x00-0xff%s", (k<15)?";":"\n"); - } - } - } - } - } - -/* - for(i=0; i < caddr; i++){ - for(j=0; j<16; j++){ - if(j==0){ - printf("A%08x: ", i); - } - else if(j==8){ - printf("\n "); - } - - - printf("%08x ", *(pcounter + i * 16 + j)); - - if(j==15){ - printf("\n\n"); - } - } - } -*/ - - puts(""); - for(i=0; i < caddr; i++){ - for(j=0; j<16; j++){ - if(j==0){ - printf("A%08x: ", i); - } - else if(j==8){ - printf("\n "); - } - - - printf("%08x ", *(pcounter + i * 16 + j)); - - if(j==15){ - printf("\n\n"); - } - } - } - } - } - else{ - if(filter_f || decode_f) - decode_ipv6_address(&addr); - - - if(nblock){ - if(match_ipv6(block, blocklen, nblock, &(addr.ip6))){ - if(response_f) - puts("REJECT"); - - exit(EXIT_SUCCESS); - } - } - - if(block_type || block_scope || block_itype || block_utype){ - if( (block_type & addr.type) || (block_utype & addr.subtype)\ - || (block_scope & addr.scope) || (block_itype & addr.iidtype)){ - if(response_f) - puts("REJECT"); - - exit(EXIT_SUCCESS); - } - } - - accepted_f=FALSE; - - if(naccept){ - if(match_ipv6(accept, acceptlen, naccept, &(addr.ip6))) - accepted_f= TRUE; - } - - if(!accepted_f && (accept_type || accept_scope || accept_itype || accept_utype)){ - if( (accept_type & addr.type) || (accept_utype & addr.subtype)\ - || (accept_scope & addr.scope) || (accept_itype & addr.iidtype)) - accepted_f= TRUE; - } - - if(acceptfilters_f && !accepted_f){ - if(response_f) - puts("REJECT"); - - exit(EXIT_SUCCESS); - } - - if(filter_f && accepted_f){ - puts("ACCEPT"); - exit(EXIT_SUCCESS); - } - - if(print_unique_preflen_f){ - sanitize_ipv6_prefix(&(addr.ip6), dpreflen); - snprintf(prefstr, sizeof(prefstr), "/%u", (unsigned int) dpreflen); - } - else{ - prefstr[0]=0; /* zero-terminate the prefix string, since we don't need to print a prefix */ - } - - if(decode_f){ - print_dec_address_script(&addr); - } - else if(reverse_f){ - if(print_ipv6_address_rev(&(addr.ip6)) != EXIT_SUCCESS) - exit(EXIT_FAILURE); - } - else if(fixed_f){ - if(inet_ntof(AF_INET6, &(addr.ip6), pv6addr, sizeof(pv6addr)) == NULL){ - puts("inet_ntof(): Error converting IPv6 address to fixed presentation format"); - exit(EXIT_FAILURE); - } - - printf("%s%s\n", pv6addr, prefstr); - } - else{ - if(inet_ntop(AF_INET6, &(addr.ip6), pv6addr, sizeof(pv6addr)) == NULL){ - puts("inet_ntop(): Error converting IPv6 address to fixed format"); - exit(EXIT_FAILURE); - } - - printf("%s%s\n", pv6addr, prefstr); - } - } - - exit(EXIT_SUCCESS); +void usage(void); +void print_help(void); +void stat_ipv6_address(struct decode6 *, struct stats6 *); +void print_dec_address_script(struct decode6 *); +int init_host_list(struct hashed_host_list *); +uint16_t key(struct hashed_host_list *, struct in6_addr *); +struct hashed_host_entry *add_hashed_host_entry(struct hashed_host_list *, struct in6_addr *); +unsigned int is_ip6_in_hashed_list(struct hashed_host_list *, struct in6_addr *); +void print_stats(struct stats6 *); + +unsigned char stdin_f = FALSE, addr_f = FALSE, verbose_f = FALSE, decode_f = FALSE, block_duplicate_f = FALSE; +unsigned char block_duplicate_preflen_f = FALSE, stats_f = FALSE, filter_f = FALSE, canonic_f = FALSE; +unsigned char fixed_f = FALSE, print_unique_preflen_f = FALSE, pattern_f = FALSE, response_f = FALSE; +unsigned char reverse_f = FALSE; +unsigned int pstart, pend; +unsigned int caddr = 0, naddr = 0; +char line[MAX_LINE_SIZE]; + +extern char *optarg; +extern int optind, opterr, optopt; + +int main(int argc, char **argv) { + struct decode6 addr; + struct stats6 stats; + struct hashed_host_list hlist; + int r; + char *ptr, *pref, *charptr, *lasts, *endptr; + unsigned long ul_res; + char pv6addr[INET6_ADDRSTRLEN]; + char prefstr[5]; /* Buffer to store a prefix such as /128 */ + unsigned int accept_type = 0, block_type = 0, accept_scope = 0, block_scope = 0, accept_itype = 0, block_itype = 0; + unsigned int accept_utype = 0, block_utype = 0; + + unsigned char accepted_f = FALSE, acceptfilters_f = FALSE, duplicate_f = FALSE, flag_f = FALSE; + + /* Block Filters */ + struct in6_addr block[MAX_BLOCK], *ptable = NULL; + struct in6_addr genaddr, randaddr; + uint8_t genpref = 0; + + uint32_t *pcounter = NULL, pthres, pratio; + uint8_t blocklen[MAX_BLOCK]; + unsigned int nblock = 0; + + /* Accept Filters */ + struct in6_addr accept[MAX_ACCEPT]; + uint8_t acceptlen[MAX_ACCEPT]; + unsigned int naccept = 0, i, j, k; + + /* Filter based on prefix length */ + uint8_t dpreflen = 128; /* To avoid warnings */ + + pid_t pid; + struct in6_addr dummyipv6; + struct timeval time; + + static struct option longopts[] = { + {"address", required_argument, 0, 'a'}, + {"gen-addr", required_argument, 0, 'A'}, + {"stdin", no_argument, 0, 'i'}, + {"print-canonic", no_argument, 0, 'c'}, + {"print-decode", no_argument, 0, 'd'}, + {"print-fixed", no_argument, 0, 'f'}, + {"print-reverse", no_argument, 0, 'r'}, + {"print-stats", no_argument, 0, 's'}, + {"print-pattern", required_argument, 0, 'x'}, + {"print-response", no_argument, 0, 'R'}, + {"block-dup", no_argument, 0, 'q'}, + {"print-unique", no_argument, 0, 'Q'}, + {"print-uni-preflen", required_argument, 0, 'P'}, + {"block-dup-preflen", required_argument, 0, 'p'}, + {"accept", required_argument, 0, 'j'}, + {"accept-type", required_argument, 0, 'b'}, + {"accept-scope", required_argument, 0, 'k'}, + {"accept-utype", required_argument, 0, 'w'}, + {"accept-iid", required_argument, 0, 'g'}, + {"block", required_argument, 0, 'J'}, + {"block-type", required_argument, 0, 'B'}, + {"block-scope", required_argument, 0, 'K'}, + {"block-utype", required_argument, 0, 'W'}, + {"block-iid", required_argument, 0, 'G'}, + {"verbose", no_argument, 0, 'v'}, + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0}, + }; + + const char shortopts[] = "a:A:icrdfsx:RqQP:p:j:b:k:w:g:J:B:K:W:G:vh"; + + char option; + + if (argc <= 1) { + usage(); + exit(EXIT_FAILURE); + } + + release_privileges(); + + while ((r = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1 && r != '?') { + option = r; + + switch (option) { + case 'a': + if (inet_pton(AF_INET6, optarg, &(addr.ip6)) <= 0) { + puts("inet_pton(): address not valid"); + exit(EXIT_FAILURE); + } + + addr_f = TRUE; + break; + + case 'A': + if ((charptr = strtok_r(optarg, "/", &lasts)) == NULL) { + puts("Error in Prefix"); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, charptr, &genaddr) <= 0) { + puts("inet_pton(): Source Address not valid"); + exit(EXIT_FAILURE); + } + + if ((charptr = strtok_r(NULL, " ", &lasts)) != NULL) { + genpref = atoi(charptr); + + if (genpref > 128) { + puts("Prefix length error in IPv6 Source Address"); + exit(EXIT_FAILURE); + } + } + else { + puts("Missing Prefix Length"); + exit(EXIT_FAILURE); + } + + if (gettimeofday(&time, NULL) == -1) { + perror("addr6"); + exit(EXIT_FAILURE); + } + + pid = getpid(); + srandom((unsigned int)time.tv_sec + (unsigned int)time.tv_usec + (unsigned int)pid); + randomize_ipv6_addr(&randaddr, &genaddr, genpref); + + if (inet_ntop(AF_INET6, &randaddr, pv6addr, sizeof(pv6addr)) == NULL) { + puts("inet_ntop(): Error converting IPv6 address to presentation format"); + exit(EXIT_FAILURE); + } + + puts(pv6addr); + + exit(EXIT_SUCCESS); + break; + + case 'i': /* Read from stdin */ + stdin_f = TRUE; + break; + + case 'c': /* Print addresses in canonic form */ + canonic_f = TRUE; + break; + + case 'f': /* Print addresses with fixed length */ + fixed_f = TRUE; + break; + + case 'd': /* Decode IPv6 addresses */ + decode_f = TRUE; + break; + + case 'r': /* Print addresses in reversed form */ + reverse_f = TRUE; + break; + + case 'j': /* IPv6 Address (accept) filter */ + if (naccept > MAX_ACCEPT) { + puts("Too many IPv6 Address (accept) filters."); + exit(EXIT_FAILURE); + } + + if ((pref = strtok_r(optarg, "/", &lasts)) == NULL) { + printf("Error in IPv6 Address (accept) filter number %u.\n", naccept + 1); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, pref, &accept[naccept]) <= 0) { + printf("Error in IPv6 Address (accept) filter number %u.\n", naccept + 1); + exit(EXIT_FAILURE); + } + + if ((charptr = strtok_r(NULL, " ", &lasts)) == NULL) { + acceptlen[naccept] = 128; + } + else { + acceptlen[naccept] = atoi(charptr); + + if (acceptlen[naccept] > 128) { + printf("Length error in IPv6 Source Address (accept) filter number %u.\n", naccept + 1); + exit(EXIT_FAILURE); + } + } + + sanitize_ipv6_prefix(&accept[naccept], acceptlen[naccept]); + naccept++; + acceptfilters_f = TRUE; + filter_f = TRUE; + break; + + case 'J': /* IPv6 Address (block) filter */ + if (nblock >= MAX_BLOCK) { + puts("Too many IPv6 Source Address (block) filters."); + exit(EXIT_FAILURE); + } + + if ((pref = strtok_r(optarg, "/", &lasts)) == NULL) { + printf("Error in IPv6 Address (block) filter number %u.\n", nblock + 1); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, pref, &block[nblock]) <= 0) { + printf("Error in IPv6 Source Address (block) filter number %u.", nblock + 1); + exit(EXIT_FAILURE); + } + + if ((charptr = strtok_r(NULL, " ", &lasts)) == NULL) { + blocklen[nblock] = 128; + } + else { + blocklen[nblock] = atoi(charptr); + + if (blocklen[nblock] > 128) { + printf("Length error in IPv6 Address (block) filter number %u.\n", nblock + 1); + exit(EXIT_FAILURE); + } + } + + sanitize_ipv6_prefix(&block[nblock], blocklen[nblock]); + + nblock++; + filter_f = TRUE; + break; + + case 'b': /* Accept type filter */ + if (strncmp(optarg, "unicast", MAX_TYPE_SIZE) == 0) { + accept_type |= IPV6_UNICAST; + } + else if (strncmp(optarg, "unspec", MAX_TYPE_SIZE) == 0 || + strncmp(optarg, "unspecified", MAX_TYPE_SIZE) == 0) { + accept_type |= IPV6_UNSPEC; + } + else if (strncmp(optarg, "multicast", MAX_TYPE_SIZE) == 0) { + accept_type |= IPV6_MULTICAST; + } + else { + printf("Unknown address type '%s' in accept type filter\n", optarg); + exit(EXIT_FAILURE); + } + + acceptfilters_f = TRUE; + filter_f = TRUE; + break; + + case 'B': /* Block type filter */ + if (strncmp(optarg, "unicast", MAX_TYPE_SIZE) == 0) { + block_type |= IPV6_UNICAST; + } + else if (strncmp(optarg, "unspec", MAX_TYPE_SIZE) == 0 || + strncmp(optarg, "unspecified", MAX_TYPE_SIZE) == 0) { + block_type |= IPV6_UNSPEC; + } + else if (strncmp(optarg, "multicast", MAX_TYPE_SIZE) == 0) { + block_type |= IPV6_MULTICAST; + } + else { + printf("Unknown address type '%s' in block type filter\n", optarg); + exit(EXIT_FAILURE); + } + + filter_f = TRUE; + break; + + case 'k': /* Accept scope filter */ + if (strncmp(optarg, "reserved", MAX_TYPE_SIZE) == 0) { + accept_scope |= SCOPE_RESERVED; + } + else if (strncmp(optarg, "interface", MAX_TYPE_SIZE) == 0 || + strncmp(optarg, "interface-local", MAX_TYPE_SIZE) == 0) { + accept_scope |= SCOPE_INTERFACE; + } + else if (strncmp(optarg, "link", MAX_TYPE_SIZE) == 0 || strncmp(optarg, "link-local", MAX_TYPE_SIZE) == 0) { + accept_scope |= SCOPE_LINK; + } + else if (strncmp(optarg, "admin", MAX_TYPE_SIZE) == 0 || + strncmp(optarg, "admin-local", MAX_TYPE_SIZE) == 0) { + accept_scope |= SCOPE_ADMIN; + } + else if (strncmp(optarg, "site", MAX_TYPE_SIZE) == 0 || strncmp(optarg, "site-local", MAX_TYPE_SIZE) == 0) { + accept_scope |= SCOPE_SITE; + } + else if (strncmp(optarg, "organization", MAX_TYPE_SIZE) == 0 || + strncmp(optarg, "organization-local", MAX_TYPE_SIZE) == 0) { + accept_scope |= SCOPE_ORGANIZATION; + } + else if (strncmp(optarg, "global", MAX_TYPE_SIZE) == 0) { + accept_scope |= SCOPE_GLOBAL; + } + else if (strncmp(optarg, "unassigned", MAX_TYPE_SIZE) == 0) { + accept_scope |= SCOPE_UNASSIGNED; + } + else if (strncmp(optarg, "unspecified", MAX_TYPE_SIZE) == 0) { + accept_scope |= SCOPE_UNSPECIFIED; + } + else { + printf("Unknown address scope '%s' in accept scope filter\n", optarg); + exit(EXIT_FAILURE); + } + + acceptfilters_f = TRUE; + filter_f = TRUE; + break; + + case 'K': /* Block scope filter */ + if (strncmp(optarg, "reserved", MAX_TYPE_SIZE) == 0) { + block_scope |= SCOPE_RESERVED; + } + else if (strncmp(optarg, "interface", MAX_TYPE_SIZE) == 0 || + strncmp(optarg, "interface-local", MAX_TYPE_SIZE) == 0) { + block_scope |= SCOPE_INTERFACE; + } + else if (strncmp(optarg, "link", MAX_TYPE_SIZE) == 0 || strncmp(optarg, "link-local", MAX_TYPE_SIZE) == 0) { + block_scope |= SCOPE_LINK; + } + else if (strncmp(optarg, "admin", MAX_TYPE_SIZE) == 0 || + strncmp(optarg, "admin-local", MAX_TYPE_SIZE) == 0) { + block_scope |= SCOPE_ADMIN; + } + else if (strncmp(optarg, "site", MAX_TYPE_SIZE) == 0 || strncmp(optarg, "site-local", MAX_TYPE_SIZE) == 0) { + block_scope |= SCOPE_SITE; + } + else if (strncmp(optarg, "organization", MAX_TYPE_SIZE) == 0 || + strncmp(optarg, "organization-local", MAX_TYPE_SIZE) == 0) { + block_scope |= SCOPE_ORGANIZATION; + } + else if (strncmp(optarg, "global", MAX_TYPE_SIZE) == 0) { + block_scope |= SCOPE_GLOBAL; + } + else if (strncmp(optarg, "unassigned", MAX_TYPE_SIZE) == 0) { + block_scope |= SCOPE_UNASSIGNED; + } + else if (strncmp(optarg, "unspecified", MAX_TYPE_SIZE) == 0) { + block_scope |= SCOPE_UNSPECIFIED; + } + else { + printf("Unknown address scope '%s' in block scope filter\n", optarg); + exit(EXIT_FAILURE); + } + + filter_f = TRUE; + break; + + case 'w': /* Accept unicast type filter */ + if (strncmp(optarg, "loopback", MAX_TYPE_SIZE) == 0) { + accept_utype |= UCAST_LOOPBACK; + } + else if (strncmp(optarg, "ipv4-compat", MAX_TYPE_SIZE) == 0 || + strncmp(optarg, "ipv4-compatible", MAX_TYPE_SIZE) == 0) { + accept_utype |= UCAST_V4COMPAT; + } + else if (strncmp(optarg, "ipv4-mapped", MAX_TYPE_SIZE) == 0) { + accept_utype |= UCAST_V4MAPPED; + } + else if (strncmp(optarg, "link-local", MAX_TYPE_SIZE) == 0) { + accept_utype |= UCAST_LINKLOCAL; + } + else if (strncmp(optarg, "site-local", MAX_TYPE_SIZE) == 0) { + accept_utype |= UCAST_SITELOCAL; + } + else if (strncmp(optarg, "unique-local", MAX_TYPE_SIZE) == 0 || + strncmp(optarg, "ula", MAX_TYPE_SIZE) == 0) { + accept_utype |= UCAST_UNIQUELOCAL; + } + else if (strncmp(optarg, "6to4", MAX_TYPE_SIZE) == 0) { + accept_utype |= UCAST_6TO4; + } + else if (strncmp(optarg, "teredo", MAX_TYPE_SIZE) == 0) { + accept_utype |= UCAST_TEREDO; + } + else if (strncmp(optarg, "global", MAX_TYPE_SIZE) == 0 || strncmp(optarg, "normal", MAX_TYPE_SIZE) == 0) { + accept_utype |= UCAST_GLOBAL; + } + else { + printf("Unknown unicast address type '%s' in accept unicast address type filter\n", optarg); + exit(EXIT_FAILURE); + } + + acceptfilters_f = TRUE; + filter_f = TRUE; + break; + + case 'W': /* Block unicast type filter */ + if (strncmp(optarg, "loopback", MAX_TYPE_SIZE) == 0) { + block_utype |= UCAST_LOOPBACK; + } + else if (strncmp(optarg, "ipv4-compat", MAX_TYPE_SIZE) == 0 || + strncmp(optarg, "ipv4-compatible", MAX_TYPE_SIZE) == 0) { + block_utype |= UCAST_V4COMPAT; + } + else if (strncmp(optarg, "ipv4-mapped", MAX_TYPE_SIZE) == 0) { + block_utype |= UCAST_V4MAPPED; + } + else if (strncmp(optarg, "link-local", MAX_TYPE_SIZE) == 0) { + block_utype |= UCAST_LINKLOCAL; + } + else if (strncmp(optarg, "site-local", MAX_TYPE_SIZE) == 0) { + block_utype |= UCAST_SITELOCAL; + } + else if (strncmp(optarg, "unique-local", MAX_TYPE_SIZE) == 0 || + strncmp(optarg, "ula", MAX_TYPE_SIZE) == 0) { + block_utype |= UCAST_UNIQUELOCAL; + } + else if (strncmp(optarg, "6to4", MAX_TYPE_SIZE) == 0) { + block_utype |= UCAST_6TO4; + } + else if (strncmp(optarg, "teredo", MAX_TYPE_SIZE) == 0) { + block_utype |= UCAST_TEREDO; + } + else if (strncmp(optarg, "global", MAX_TYPE_SIZE) == 0 || strncmp(optarg, "normal", MAX_TYPE_SIZE) == 0) { + block_utype |= UCAST_GLOBAL; + } + else { + printf("Unknown unicast address type '%s' in block unicast address type filter\n", optarg); + exit(EXIT_FAILURE); + } + + filter_f = TRUE; + break; + + case 'g': /* Accept IID filter */ + if (strncmp(optarg, "ieee", MAX_TYPE_SIZE) == 0) { + accept_itype |= IID_MACDERIVED; + } + else if (strncmp(optarg, "isatap", MAX_TYPE_SIZE) == 0 || strncmp(optarg, "ISATAP", MAX_TYPE_SIZE) == 0) { + accept_itype |= IID_ISATAP; + } + else if (strncmp(optarg, "ipv4-32", MAX_TYPE_SIZE) == 0) { + accept_itype |= IID_EMBEDDEDIPV4; + } + else if (strncmp(optarg, "ipv4-64", MAX_TYPE_SIZE) == 0) { + accept_itype |= IID_EMBEDDEDIPV4_64; + } + else if (strncmp(optarg, "ipv4-all", MAX_TYPE_SIZE) == 0) { + accept_itype |= IID_EMBEDDEDIPV4; + accept_itype |= IID_EMBEDDEDIPV4_64; + } + else if (strncmp(optarg, "embed-port", MAX_TYPE_SIZE) == 0 || strncmp(optarg, "port", MAX_TYPE_SIZE) == 0) { + accept_itype |= IID_EMBEDDEDPORT; + } + else if (strncmp(optarg, "embed-port-rev", MAX_TYPE_SIZE) == 0 || + strncmp(optarg, "port-rev", MAX_TYPE_SIZE) == 0) { + accept_itype |= IID_EMBEDDEDPORTREV; + } + else if (strncmp(optarg, "embed-port-all", MAX_TYPE_SIZE) == 0 || + strncmp(optarg, "port-all", MAX_TYPE_SIZE) == 0) { + accept_itype |= IID_EMBEDDEDPORT; + accept_itype |= IID_EMBEDDEDPORTREV; + } + else if (strncmp(optarg, "low-byte", MAX_TYPE_SIZE) == 0 || + strncmp(optarg, "lowbyte", MAX_TYPE_SIZE) == 0) { + accept_itype |= IID_LOWBYTE; + } + else if (strncmp(optarg, "byte-pattern", MAX_TYPE_SIZE) == 0 || + strncmp(optarg, "bytepattern", MAX_TYPE_SIZE) == 0) { + accept_itype |= IID_PATTERN_BYTES; + } + else if (strncmp(optarg, "random", MAX_TYPE_SIZE) == 0 || + strncmp(optarg, "randomized", MAX_TYPE_SIZE) == 0) { + accept_itype |= IID_RANDOM; + } + else { + printf("Unknown IID type '%s' in accept IID type filter.\n", optarg); + exit(EXIT_FAILURE); + } + + acceptfilters_f = TRUE; + filter_f = TRUE; + break; + + case 'G': /* Block IID filter */ + if (strncmp(optarg, "ieee", MAX_TYPE_SIZE) == 0) { + block_itype |= IID_MACDERIVED; + } + else if (strncmp(optarg, "isatap", MAX_TYPE_SIZE) == 0 || strncmp(optarg, "ISATAP", MAX_TYPE_SIZE) == 0) { + block_itype |= IID_ISATAP; + } + else if (strncmp(optarg, "ipv4-32", MAX_TYPE_SIZE) == 0) { + block_itype |= IID_EMBEDDEDIPV4; + } + else if (strncmp(optarg, "ipv4-64", MAX_TYPE_SIZE) == 0) { + block_itype |= IID_EMBEDDEDIPV4_64; + } + else if (strncmp(optarg, "ipv4-all", MAX_TYPE_SIZE) == 0) { + block_itype |= IID_EMBEDDEDIPV4; + block_itype |= IID_EMBEDDEDIPV4_64; + } + else if (strncmp(optarg, "embed-port", MAX_TYPE_SIZE) == 0 || strncmp(optarg, "port", MAX_TYPE_SIZE) == 0) { + block_itype |= IID_EMBEDDEDPORT; + } + else if (strncmp(optarg, "embed-port-rev", MAX_TYPE_SIZE) == 0 || + strncmp(optarg, "port-rev", MAX_TYPE_SIZE) == 0) { + block_itype |= IID_EMBEDDEDPORTREV; + } + else if (strncmp(optarg, "embed-port-all", MAX_TYPE_SIZE) == 0 || + strncmp(optarg, "port-all", MAX_TYPE_SIZE) == 0) { + block_itype |= IID_EMBEDDEDPORT; + block_itype |= IID_EMBEDDEDPORTREV; + } + else if (strncmp(optarg, "low-byte", MAX_TYPE_SIZE) == 0 || + strncmp(optarg, "lowbyte", MAX_TYPE_SIZE) == 0) { + block_itype |= IID_LOWBYTE; + } + else if (strncmp(optarg, "byte-pattern", MAX_TYPE_SIZE) == 0 || + strncmp(optarg, "bytepattern", MAX_TYPE_SIZE) == 0) { + block_itype |= IID_PATTERN_BYTES; + } + else if (strncmp(optarg, "random", MAX_TYPE_SIZE) == 0 || + strncmp(optarg, "randomized", MAX_TYPE_SIZE) == 0) { + block_itype |= IID_RANDOM; + } + else { + printf("Unknown IID type '%s' in block IID type filter.\n", optarg); + exit(EXIT_FAILURE); + } + + filter_f = TRUE; + break; + + case 's': /* Generate IPv6 Address Statistics */ + stats_f = TRUE; + break; + + case 'q': /* Block duplicate addresses */ + case 'Q': /* For backwards-compatibility */ + block_duplicate_f = TRUE; + break; + + case 'p': /* Filter duplicate addresses on a per-prefix basis */ + if (block_duplicate_preflen_f) { + puts("Error: Cannot specify multiple --block-dup-preflen options"); + exit(EXIT_FAILURE); + } + + if ((pref = strtok_r(optarg, "/", &lasts)) == NULL) { + puts("Error in '--block-dup-preflen' option"); + exit(EXIT_FAILURE); + } + + if ((ul_res = strtoul(pref, &endptr, 10)) == ULONG_MAX) { + perror("Error in '--block-dup-preflen' option"); + exit(EXIT_FAILURE); + } + + if (endptr != pref) { + dpreflen = ul_res; + block_duplicate_preflen_f = TRUE; + } + else { + puts("Error in '--block-dup-preflen' option"); + exit(EXIT_FAILURE); + } + + break; + + case 'P': /* Generate unique prefixes of specified length */ + if (print_unique_preflen_f) { + puts("Error: Cannot specify multiple --print-unique-preflen options"); + exit(EXIT_FAILURE); + } + + if ((pref = strtok_r(optarg, "/", &lasts)) == NULL) { + puts("Error in '--print-unique-preflen' option"); + exit(EXIT_FAILURE); + } + + if ((ul_res = strtoul(pref, &endptr, 10)) == ULONG_MAX) { + perror("Error in '--print-unique-preflen' option"); + exit(EXIT_FAILURE); + } + + if (endptr != pref) { + dpreflen = ul_res; + print_unique_preflen_f = TRUE; + } + else { + puts("Error in '--print-unique-preflen' option"); + exit(EXIT_FAILURE); + } + + break; + + case 'x': /* Print pattern */ + pattern_f = 1; + + if (sscanf(optarg, "/%u:/%u:%u%%", &pstart, &pend, &pratio) == 3) { + if (pstart % 8 != 0 || pend % 8 != 0) { + puts("Must specify range as /n1:/n2:p% where n1 and n2 are multiples of 8, and p is percentage"); + exit(EXIT_FAILURE); + } + + pstart = pstart / 8; + + if (pstart > 0) + pstart = pstart - 1; + + pend = pend / 8; + + if (pend > 0) + pend = pend - 1; + } + else if (sscanf(optarg, "%u:%u:%u%%", &pstart, &pend, &pratio) != 3) { + puts("Must specify range as n1:n2:, where n1 and n2 are smaller than 16, and p is a percentage"); + exit(EXIT_FAILURE); + } + + if (pstart >= pend || pstart > 15 || pend > 15) { + puts("Inappropriate range for prefix analysis"); + exit(EXIT_FAILURE); + } + + if (pratio <= 0 || pratio > 100) { + puts("Error: percentage must be larger than 0 and smaller (or equal) to 100\n"); + exit(EXIT_FAILURE); + } + + printf("N1: %u, N2: %u\n", pstart, pend); + + if ((ptable = malloc(16 * MAX_ADDR_PATTERN)) == NULL) { + puts("Not enough memory"); + exit(EXIT_FAILURE); + } + + if ((pcounter = malloc(sizeof(uint32_t) * MAX_ADDR_PATTERN)) == NULL) { + puts("Not enough memory"); + exit(EXIT_FAILURE); + } + + break; + + case 'R': /* Be verbose */ + response_f = TRUE; + break; + + case 'v': /* Be verbose */ + verbose_f++; + break; + + case 'h': /* Help */ + print_help(); + exit(EXIT_FAILURE); + break; + + default: + usage(); + exit(EXIT_FAILURE); + break; + + } /* switch */ + } /* while(getopt) */ + + /* Catch simultaneous use of incompatible addresses */ + + if (stdin_f && addr_f) { + puts("Cannot specify both '-a' and '-i' at the same time (try only one of them at a time)"); + exit(EXIT_FAILURE); + } + + if (!stdin_f && !addr_f) { + puts("Must specify an IPv6 address with '-a', or set '-i' to read addresses from stdin"); + exit(EXIT_FAILURE); + } + + if (!stdin_f) { + if (stats_f) { + puts("Cannot obtain statistics based on a single IPv6 address (should be using '-i')"); + exit(EXIT_FAILURE); + } + else if (pattern_f) { + puts("Cannot analyze pattern based on a single IPv6 address (should be using '-i')"); + exit(EXIT_FAILURE); + } + } + + if (block_duplicate_f && block_duplicate_preflen_f) { + puts("Cannot employ --block-dup and --block-dup-preflen options simultaneously"); + exit(EXIT_FAILURE); + } + + if (print_unique_preflen_f && (block_duplicate_f || block_duplicate_preflen_f)) { + puts("Cannot employ --print-unique-preflen with --block-dup or --block-dup-preflen options simultaneously"); + exit(EXIT_FAILURE); + } + + if (canonic_f && fixed_f) { + puts("Cannot employ --print-canonic and --print-fixed simultaneously"); + exit(EXIT_FAILURE); + } + + /* By default, addr6 decodes IPv6 addresses */ + if (!block_duplicate_f && !block_duplicate_preflen_f && !print_unique_preflen_f && !filter_f && !stats_f && + !canonic_f && !fixed_f && !reverse_f) + decode_f = TRUE; + + if (block_duplicate_f || block_duplicate_preflen_f || print_unique_preflen_f) { + if (!init_host_list(&hlist)) { + puts("Not enough memory when initializing internal host list"); + exit(EXIT_FAILURE); + } + } + + if (stats_f) { + memset(&stats, 0, sizeof(stats)); + } + + if (stdin_f) { + while (fgets(line, MAX_LINE_SIZE, stdin) != NULL) { + r = read_prefix(line, Strnlen(line, MAX_LINE_SIZE), &ptr); + + if (r == 1) { + if (inet_pton(AF_INET6, ptr, &(addr.ip6)) <= 0) { + if (decode_f) + puts("Error: Invalid IPv6 address"); + + continue; + } + + if (filter_f || decode_f || stats_f) + decode_ipv6_address(&addr); + + if (nblock) { + if (match_ipv6(block, blocklen, nblock, &(addr.ip6))) { + if (response_f) + puts("REJECT"); + + continue; + } + } + + if (block_type || block_scope || block_itype || block_utype) { + if ((block_type & addr.type) || (block_utype & addr.subtype) || (block_scope & addr.scope) || + (block_itype & addr.iidtype)) { + if (response_f) + puts("REJECT"); + + continue; + } + } + + if (block_duplicate_f && is_ip6_in_hashed_list(&hlist, &(addr.ip6))) { + if (response_f) + puts("REJECT"); + + continue; + } + else if (block_duplicate_preflen_f || print_unique_preflen_f) { + dummyipv6 = addr.ip6; + sanitize_ipv6_prefix(&dummyipv6, dpreflen); + + if (is_ip6_in_hashed_list(&hlist, &dummyipv6)) { + if (response_f) + puts("REJECT"); + + continue; + } + } + + accepted_f = 0; + + if (naccept) { + if (match_ipv6(accept, acceptlen, naccept, &(addr.ip6))) + accepted_f = TRUE; + } + + if (!accepted_f && (accept_type || accept_scope || accept_itype || accept_utype)) { + if ((accept_type & addr.type) || (accept_utype & addr.subtype) || (accept_scope & addr.scope) || + (accept_itype & addr.iidtype)) + accepted_f = TRUE; + } + + if (acceptfilters_f && !accepted_f) { + if (response_f) + puts("REJECT"); + + continue; + } + /* + If we got here, and block_duplicate_f is TRUE, then this address is unique, and we must add it to + the hashed list. + */ + if (block_duplicate_f) { + if (add_hashed_host_entry(&hlist, &(addr.ip6)) == NULL) { + puts( + "Not enough memory (or hit internal artificial limit) when storing IPv6 address in memory"); + exit(EXIT_FAILURE); + } + } + else if (block_duplicate_preflen_f || print_unique_preflen_f) { + dummyipv6 = addr.ip6; + sanitize_ipv6_prefix(&dummyipv6, dpreflen); + + if (add_hashed_host_entry(&hlist, &dummyipv6) == NULL) { + puts( + "Not enough memory (or hit internal artificial limit) when storing IPv6 address in memory"); + exit(EXIT_FAILURE); + } + } + + if (filter_f && response_f) { + puts("ACCEPT"); + continue; + } + + if (stats_f) { + stat_ipv6_address(&addr, &stats); + } + else if (decode_f) { + print_dec_address_script(&addr); + } + else if (reverse_f) { + print_ipv6_address_rev(&(addr.ip6)); + } + else if (pattern_f) { + /* XXX */ + /* Analyze address pattern */ + if (caddr >= MAX_ADDR_PATTERN) { + puts("Too many addresses for pattern analysis. Filter them out in smaller subsets, and retry"); + exit(EXIT_FAILURE); + } + + *(ptable + caddr) = addr.ip6; + + /* + puts("Direcciones hasta ahora"); + for(i=0; i<=caddr; i++){ + if(inet_ntof(AF_INET6, ptable+caddr, pv6addr, + sizeof(pv6addr)) == NULL){ puts("inet_ntof(): Error converting IPv6 address to fixed presentation + format"); exit(EXIT_FAILURE); + } + + printf("Address #%u: %s\n", i, pv6addr); + } + + puts(""); + */ + /* Initialize counters for this address to 0 */ + for (i = 0; i < 16; i++) { + *(pcounter + (caddr * 16) + i) = 0; + } + + /* Compute differences in bytes */ + for (naddr = 0; naddr < caddr; naddr++) { + for (j = 0; j < 4; j++) { + for (k = 0; k < 4; k++) { + + /*printf("Comparo: %08x con %08x\n", (ntohl((ptable+naddr)->s6_addr32[j]) & + * (0xff000000>>(k*8))) , (ntohl((ptable+caddr)->s6_addr32[j]) & + * (0xff000000>>(k*8))));*/ + if ((ntohl((ptable + naddr)->s6_addr32[j]) & (0xff000000 >> (k * 8))) != + (ntohl((ptable + caddr)->s6_addr32[j]) & (0xff000000 >> (k * 8)))) { + /* If the bytes were different, increment counters for both addresses */ + (*(pcounter + (naddr * 16) + j * 4 + k))++; + (*(pcounter + (caddr * 16) + j * 4 + k))++; + } + } + } + } + + caddr++; + } + else { + if (print_unique_preflen_f) { + sanitize_ipv6_prefix(&(addr.ip6), dpreflen); + snprintf(prefstr, sizeof(prefstr), "/%u", (unsigned int)dpreflen); + } + else { + prefstr[0] = 0; /* zero-terminate the prefix string, since we don't need to print a prefix */ + } + + if (fixed_f) { + if (inet_ntof(AF_INET6, &(addr.ip6), pv6addr, sizeof(pv6addr)) == NULL) { + puts("inet_ntof(): Error converting IPv6 address to fixed presentation format"); + exit(EXIT_FAILURE); + } + } + else { + if (inet_ntop(AF_INET6, &(addr.ip6), pv6addr, sizeof(pv6addr)) == NULL) { + puts("inet_ntop(): Error converting IPv6 address to fixed format"); + exit(EXIT_FAILURE); + } + } + + printf("%s%s\n", pv6addr, prefstr); + } + } + } + + if (stats_f) { + print_stats(&stats); + } + + else if (pattern_f) { + pthres = ((unsigned long)caddr * (100 - pratio)) / 100; + + for (i = 0; i < caddr; i++) { + flag_f = 0; + + for (j = pstart; j <= pend; j++) { + if (*(pcounter + i * 16 + j) <= pthres) { + flag_f = 1; + } + } + + /* + If flag is set to 1, we identified some pattern -- the search space can be reduced + We just need to avoid specifying the same range twice + */ + + duplicate_f = 0; + + if (flag_f == 1) { + /* We go around comparing the current address with al the previous ones */ + for (j = 0; (j < i) && !duplicate_f; j++) { + for (k = pstart; k <= pend; k++) { + /* In order for prefix to be duplicate: + Both counters must be below threshold and be equal, or both must be or threshold + */ + + if (*(pcounter + i * 16 + k) <= pthres) { + if (*(pcounter + j * 16 + k) > pthres) { + break; + } + else if ((ntohl((ptable + i)->s6_addr32[k / 4]) & (0xff000000 >> ((k % 4) * 8))) != + (ntohl((ptable + j)->s6_addr32[k / 4]) & (0xff000000 >> ((k % 4) * 8)))) { + break; + } + } + else if (*(pcounter + j * 16 + k) <= pthres) { + break; + } + } + + if (k > pend) { + duplicate_f = 1; + } + } + + if (!duplicate_f) { + /* The address in 'i' is a unique range */ + for (k = 0; k < 16; k++) { + if (*(pcounter + i * 16 + k) <= pthres) { + /* (ntohl((ptable+i)->s6_addr32[k/4]) & (0xff000000>>((k%4)*8))) >> ( (3 - (k%4)) * 8) + */ + printf("%02x%s", + ((ntohl((ptable + i)->s6_addr32[k / 4]) & (0xff000000 >> ((k % 4) * 8))) >> + ((3 - (k % 4)) * 8)), + (k < 15) ? ";" : "\n"); + } + else { + printf("0x00-0xff%s", (k < 15) ? ";" : "\n"); + } + } + } + } + } + + /* + for(i=0; i < caddr; i++){ + for(j=0; j<16; j++){ + if(j==0){ + printf("A%08x: ", i); + } + else if(j==8){ + printf("\n "); + } + + + printf("%08x ", *(pcounter + i * 16 + j)); + + if(j==15){ + printf("\n\n"); + } + } + } + */ + + puts(""); + for (i = 0; i < caddr; i++) { + for (j = 0; j < 16; j++) { + if (j == 0) { + printf("A%08x: ", i); + } + else if (j == 8) { + printf("\n "); + } + + printf("%08x ", *(pcounter + i * 16 + j)); + + if (j == 15) { + printf("\n\n"); + } + } + } + } + } + else { + if (filter_f || decode_f) + decode_ipv6_address(&addr); + + if (nblock) { + if (match_ipv6(block, blocklen, nblock, &(addr.ip6))) { + if (response_f) + puts("REJECT"); + + exit(EXIT_SUCCESS); + } + } + + if (block_type || block_scope || block_itype || block_utype) { + if ((block_type & addr.type) || (block_utype & addr.subtype) || (block_scope & addr.scope) || + (block_itype & addr.iidtype)) { + if (response_f) + puts("REJECT"); + + exit(EXIT_SUCCESS); + } + } + + accepted_f = FALSE; + + if (naccept) { + if (match_ipv6(accept, acceptlen, naccept, &(addr.ip6))) + accepted_f = TRUE; + } + + if (!accepted_f && (accept_type || accept_scope || accept_itype || accept_utype)) { + if ((accept_type & addr.type) || (accept_utype & addr.subtype) || (accept_scope & addr.scope) || + (accept_itype & addr.iidtype)) + accepted_f = TRUE; + } + + if (acceptfilters_f && !accepted_f) { + if (response_f) + puts("REJECT"); + + exit(EXIT_SUCCESS); + } + + if (filter_f && accepted_f) { + puts("ACCEPT"); + exit(EXIT_SUCCESS); + } + + if (print_unique_preflen_f) { + sanitize_ipv6_prefix(&(addr.ip6), dpreflen); + snprintf(prefstr, sizeof(prefstr), "/%u", (unsigned int)dpreflen); + } + else { + prefstr[0] = 0; /* zero-terminate the prefix string, since we don't need to print a prefix */ + } + + if (decode_f) { + print_dec_address_script(&addr); + } + else if (reverse_f) { + if (print_ipv6_address_rev(&(addr.ip6)) != EXIT_SUCCESS) + exit(EXIT_FAILURE); + } + else if (fixed_f) { + if (inet_ntof(AF_INET6, &(addr.ip6), pv6addr, sizeof(pv6addr)) == NULL) { + puts("inet_ntof(): Error converting IPv6 address to fixed presentation format"); + exit(EXIT_FAILURE); + } + + printf("%s%s\n", pv6addr, prefstr); + } + else { + if (inet_ntop(AF_INET6, &(addr.ip6), pv6addr, sizeof(pv6addr)) == NULL) { + puts("inet_ntop(): Error converting IPv6 address to fixed format"); + exit(EXIT_FAILURE); + } + + printf("%s%s\n", pv6addr, prefstr); + } + } + + exit(EXIT_SUCCESS); } - - /* * Function: stat_ipv6_address() * * Incorporate address in IPv6 address statistics */ -void stat_ipv6_address(struct decode6 *addr, struct stats6 *stats){ - (stats->total)++; - - switch(addr->type){ - case IPV6_UNSPEC: - (stats->ipv6unspecified)++; - break; - - case IPV6_MULTICAST: - (stats->ipv6multicast)++; - - switch(addr->subtype){ - case MCAST_PERMANENT: - (stats->mcastpermanent)++; - break; +void stat_ipv6_address(struct decode6 *addr, struct stats6 *stats) { + (stats->total)++; - case MCAST_NONPERMANENT: - (stats->mcastnonpermanent)++; - break; + switch (addr->type) { + case IPV6_UNSPEC: + (stats->ipv6unspecified)++; + break; - case MCAST_INVALID: - (stats->mcastinvalid)++; - break; + case IPV6_MULTICAST: + (stats->ipv6multicast)++; - case MCAST_UNICASTBASED: - (stats->mcastunicastbased)++; - break; - - case MCAST_EMBEDRP: - (stats->mcastembedrp)++; - break; - - case MCAST_UNKNOWN: - (stats->mcastunknown)++; - break; - } - - if(addr->subtype != MCAST_UNKNOWN){ - switch(addr->scope){ - case SCOPE_RESERVED: - (stats->mscopereserved)++; - break; - - case SCOPE_INTERFACE: - (stats->mscopeinterface)++; - break; - - case SCOPE_LINK: - (stats->mnscopelink)++; - break; - - case SCOPE_ADMIN: - (stats->mscopeadmin)++; - break; - - case SCOPE_SITE: - (stats->mscopesite)++; - break; - - case SCOPE_ORGANIZATION: - (stats->mscopeorganization)++; - break; - - case SCOPE_GLOBAL: - (stats->mscopeglobal)++; - break; - - case SCOPE_UNASSIGNED: - (stats->mscopeunassigned)++; - break; - } - } - - break; - - case IPV6_UNICAST: - (stats->ipv6unicast)++; - - switch(addr->subtype){ - case UCAST_LOOPBACK: - (stats->ucastloopback)++; - break; - - case UCAST_V4MAPPED: - (stats->ucastv4mapped)++; - break; - - case UCAST_V4COMPAT: - (stats->ucastv4compat)++; - break; - - case UCAST_LINKLOCAL: - (stats->ucastlinklocal)++; - break; - - case UCAST_SITELOCAL: - (stats->ucastsitelocal)++; - break; - - case UCAST_UNIQUELOCAL: - (stats->ucastuniquelocal)++; - break; - - case UCAST_6TO4: - (stats->ucast6to4)++; - break; - - case UCAST_TEREDO: - (stats->ucastteredo)++; - break; - - case UCAST_GLOBAL: - (stats->ucastglobal)++; - break; - } - - - /* XXX: We used to leave out some address types. Now we include all - if(addr->subtype==UCAST_GLOBAL || addr->subtype==UCAST_V4MAPPED || addr->subtype==UCAST_V4COMPAT || \ - addr->subtype==UCAST_LINKLOCAL || addr->subtype==UCAST_SITELOCAL || addr->subtype==UCAST_UNIQUELOCAL ||\ - addr->subtype == UCAST_6TO4){ - */ - - switch(addr->iidtype){ - case IID_MACDERIVED: - (stats->iidmacderived)++; - break; - - case IID_ISATAP: - (stats->iidisatap)++; - break; - - case IID_EMBEDDEDIPV4: - switch(addr->iidsubtype){ - case IID_EMBEDDEDIPV4_32: - (stats->iidembeddedipv4_32)++; - break; - - case IID_EMBEDDEDIPV4_64: - (stats->iidembeddedipv4_64)++; - break; - } - break; - - case IID_EMBEDDEDPORT: - switch(addr->iidsubtype){ - case IID_EMBEDDEDPORT: - (stats->iidembeddedportfwd)++; - break; - - case IID_EMBEDDEDPORTREV: - (stats->iidembeddedportrev)++; - break; - } - - break; - - case IID_TEREDO: - (stats->iidteredo)++; - break; - - case IID_PATTERN_BYTES: - (stats->iidpatternbytes)++; - break; - - case IID_LOWBYTE: - (stats->iidlowbyte)++; - break; - - case IID_RANDOM: - (stats->iidrandom)++; - break; - } - - break; - - } + switch (addr->subtype) { + case MCAST_PERMANENT: + (stats->mcastpermanent)++; + break; + case MCAST_NONPERMANENT: + (stats->mcastnonpermanent)++; + break; + + case MCAST_INVALID: + (stats->mcastinvalid)++; + break; + + case MCAST_UNICASTBASED: + (stats->mcastunicastbased)++; + break; + + case MCAST_EMBEDRP: + (stats->mcastembedrp)++; + break; + + case MCAST_UNKNOWN: + (stats->mcastunknown)++; + break; + } + + if (addr->subtype != MCAST_UNKNOWN) { + switch (addr->scope) { + case SCOPE_RESERVED: + (stats->mscopereserved)++; + break; + + case SCOPE_INTERFACE: + (stats->mscopeinterface)++; + break; + + case SCOPE_LINK: + (stats->mnscopelink)++; + break; + + case SCOPE_ADMIN: + (stats->mscopeadmin)++; + break; + + case SCOPE_SITE: + (stats->mscopesite)++; + break; + + case SCOPE_ORGANIZATION: + (stats->mscopeorganization)++; + break; + + case SCOPE_GLOBAL: + (stats->mscopeglobal)++; + break; + + case SCOPE_UNASSIGNED: + (stats->mscopeunassigned)++; + break; + } + } + + break; + + case IPV6_UNICAST: + (stats->ipv6unicast)++; + + switch (addr->subtype) { + case UCAST_LOOPBACK: + (stats->ucastloopback)++; + break; + + case UCAST_V4MAPPED: + (stats->ucastv4mapped)++; + break; + + case UCAST_V4COMPAT: + (stats->ucastv4compat)++; + break; + + case UCAST_LINKLOCAL: + (stats->ucastlinklocal)++; + break; + + case UCAST_SITELOCAL: + (stats->ucastsitelocal)++; + break; + + case UCAST_UNIQUELOCAL: + (stats->ucastuniquelocal)++; + break; + + case UCAST_6TO4: + (stats->ucast6to4)++; + break; + + case UCAST_TEREDO: + (stats->ucastteredo)++; + break; + + case UCAST_GLOBAL: + (stats->ucastglobal)++; + break; + } + + /* XXX: We used to leave out some address types. Now we include all + if(addr->subtype==UCAST_GLOBAL || addr->subtype==UCAST_V4MAPPED || addr->subtype==UCAST_V4COMPAT || \ + addr->subtype==UCAST_LINKLOCAL || addr->subtype==UCAST_SITELOCAL || addr->subtype==UCAST_UNIQUELOCAL ||\ + addr->subtype == UCAST_6TO4){ + */ + + switch (addr->iidtype) { + case IID_MACDERIVED: + (stats->iidmacderived)++; + break; + + case IID_ISATAP: + (stats->iidisatap)++; + break; + + case IID_EMBEDDEDIPV4: + switch (addr->iidsubtype) { + case IID_EMBEDDEDIPV4_32: + (stats->iidembeddedipv4_32)++; + break; + + case IID_EMBEDDEDIPV4_64: + (stats->iidembeddedipv4_64)++; + break; + } + break; + + case IID_EMBEDDEDPORT: + switch (addr->iidsubtype) { + case IID_EMBEDDEDPORT: + (stats->iidembeddedportfwd)++; + break; + + case IID_EMBEDDEDPORTREV: + (stats->iidembeddedportrev)++; + break; + } + + break; + + case IID_TEREDO: + (stats->iidteredo)++; + break; + + case IID_PATTERN_BYTES: + (stats->iidpatternbytes)++; + break; + + case IID_LOWBYTE: + (stats->iidlowbyte)++; + break; + + case IID_RANDOM: + (stats->iidrandom)++; + break; + } + + break; + } } - /* * Function: print_dec_address_script() * * Print the IPv6 address decode obtained by decode_ipv6_address */ -void print_dec_address_script(struct decode6 *addr){ - unsigned int r; - - char *nullstring=""; - char *unspecified="unspecified"; - char iidsubtypebuffer[9]; - char *ipv6unspec="unspecified"; - char *ipv6multicast="multicast"; - char *ipv6unicast="unicast"; - - char *ucastloopback="loopback"; - char *ucastv4mapped="ipv4-mapped"; - char *ucastv4compat="ipv4-compatible"; - char *ucastlinklocal="link-local"; - char *ucastsitelocal="site-local"; - char *ucastuniquelocal="unique-local"; - char *ucast6to4="6to4"; - char *ucastteredo="teredo"; - char *ucastglobal="global"; - - char *mcastpermanent="permanent"; - char *mcastnonpermanent="non-permanent"; - char *mcastinvalid="invalid"; - char *mcastunicastbased="unicast-based"; - char *mcastembedrp="embedded-rp"; - char *mcastunknown="unknown"; - - char *iidmacderived="ieee-derived"; - char *iidisatap="isatap"; - char *iidmbeddedipv4="embedded-ipv4"; - char *iidembeddedport="embedded-port"; - char *iidembeddedportfwd="port-fwd"; - char *iidembeddedportrev="port-rev"; - char *iidlowbyte="low-byte"; - char *iidembeddedipv4_32="embedded-ipv4-32"; - char *iidembeddedipv4_64="embedded-ipv4-64"; - char *iidpatternbytes="pattern-bytes"; - char *iidrandom="randomized"; - char *iidteredo="teredo"; - char *iidteredorfc4380="rfc4380"; - char *iidteredorfc5991="rfc5991"; - char *iidteredounknown="unknown"; - - char *scopereserved="reserved"; - char *scopeinterface="interface"; - char *scopelink="link"; - char *scopeadmin="admin"; - char *scopesite="site"; - char *scopeorganization="organization"; - char *scopeglobal="global"; - char *scopeunassigned="unassigned"; - char *scopeunspecified="unspecified"; - - char *type, *subtype, *scope, *iidtype, *iidsubtype; - - type= nullstring; - subtype= nullstring; - iidtype= nullstring; - iidsubtype= nullstring; - - switch(addr->type){ - case IPV6_UNSPEC: - type= ipv6unspec; - subtype= unspecified; - iidtype= unspecified; - iidsubtype=unspecified; - break; - - case IPV6_UNICAST: - type= ipv6unicast; - iidtype= unspecified; - iidsubtype=unspecified; - - switch(addr->subtype){ - case UCAST_LOOPBACK: - subtype= ucastloopback; - iidtype= iidlowbyte; - break; - - case UCAST_GLOBAL: - subtype= ucastglobal; - break; - - case UCAST_V4MAPPED: - subtype= ucastv4mapped; - break; - - case UCAST_V4COMPAT: - subtype= ucastv4compat; - break; - - case UCAST_LINKLOCAL: - subtype= ucastlinklocal; - break; - - case UCAST_SITELOCAL: - subtype= ucastsitelocal; - break; - - case UCAST_UNIQUELOCAL: - subtype= ucastuniquelocal; - break; - - case UCAST_6TO4: - subtype= ucast6to4; - break; - - case UCAST_TEREDO: - subtype= ucastteredo; - break; - } - - - if(addr->subtype == UCAST_GLOBAL || addr->subtype == UCAST_V4MAPPED || addr->subtype == UCAST_V4COMPAT || \ - addr->subtype == UCAST_LINKLOCAL || addr->subtype == UCAST_SITELOCAL || addr->subtype == UCAST_UNIQUELOCAL ||\ - addr->subtype == UCAST_6TO4 || addr->subtype == UCAST_TEREDO){ - - switch(addr->iidtype){ - case IID_MACDERIVED: - iidtype= iidmacderived; - iidsubtype= iidsubtypebuffer; - - r=snprintf(iidsubtypebuffer, sizeof(iidsubtypebuffer), "%02x-%02x-%02x", (addr->iidsubtype >> 16 & 0xff), - (addr->iidsubtype >> 8 & 0xff), (addr->iidsubtype & 0xff)); - - if(r == 8) - iidsubtype= iidsubtypebuffer; - - break; - - case IID_ISATAP: - iidtype= iidisatap; - break; - - case IID_EMBEDDEDIPV4: - iidtype= iidmbeddedipv4; - switch(addr->iidsubtype){ - case IID_EMBEDDEDIPV4_32: - iidsubtype= iidembeddedipv4_32; - break; - - case IID_EMBEDDEDIPV4_64: - iidsubtype= iidembeddedipv4_64; - break; - } - - break; - - case IID_EMBEDDEDPORT: - iidtype= iidembeddedport; - - switch(addr->iidsubtype){ - case IID_EMBEDDEDPORT: - iidsubtype= iidembeddedportfwd; - break; - - case IID_EMBEDDEDPORTREV: - iidsubtype= iidembeddedportrev; - break; - } - - break; - - case IID_LOWBYTE: - iidtype= iidlowbyte; - break; +void print_dec_address_script(struct decode6 *addr) { + unsigned int r; + + char *nullstring = ""; + char *unspecified = "unspecified"; + char iidsubtypebuffer[9]; + char *ipv6unspec = "unspecified"; + char *ipv6multicast = "multicast"; + char *ipv6unicast = "unicast"; + + char *ucastloopback = "loopback"; + char *ucastv4mapped = "ipv4-mapped"; + char *ucastv4compat = "ipv4-compatible"; + char *ucastlinklocal = "link-local"; + char *ucastsitelocal = "site-local"; + char *ucastuniquelocal = "unique-local"; + char *ucast6to4 = "6to4"; + char *ucastteredo = "teredo"; + char *ucastglobal = "global"; + + char *mcastpermanent = "permanent"; + char *mcastnonpermanent = "non-permanent"; + char *mcastinvalid = "invalid"; + char *mcastunicastbased = "unicast-based"; + char *mcastembedrp = "embedded-rp"; + char *mcastunknown = "unknown"; + + char *iidmacderived = "ieee-derived"; + char *iidisatap = "isatap"; + char *iidmbeddedipv4 = "embedded-ipv4"; + char *iidembeddedport = "embedded-port"; + char *iidembeddedportfwd = "port-fwd"; + char *iidembeddedportrev = "port-rev"; + char *iidlowbyte = "low-byte"; + char *iidembeddedipv4_32 = "embedded-ipv4-32"; + char *iidembeddedipv4_64 = "embedded-ipv4-64"; + char *iidpatternbytes = "pattern-bytes"; + char *iidrandom = "randomized"; + char *iidteredo = "teredo"; + char *iidteredorfc4380 = "rfc4380"; + char *iidteredorfc5991 = "rfc5991"; + char *iidteredounknown = "unknown"; + + char *scopereserved = "reserved"; + char *scopeinterface = "interface"; + char *scopelink = "link"; + char *scopeadmin = "admin"; + char *scopesite = "site"; + char *scopeorganization = "organization"; + char *scopeglobal = "global"; + char *scopeunassigned = "unassigned"; + char *scopeunspecified = "unspecified"; + + char *type, *subtype, *scope, *iidtype, *iidsubtype; + + type = nullstring; + subtype = nullstring; + iidtype = nullstring; + iidsubtype = nullstring; + + switch (addr->type) { + case IPV6_UNSPEC: + type = ipv6unspec; + subtype = unspecified; + iidtype = unspecified; + iidsubtype = unspecified; + break; + + case IPV6_UNICAST: + type = ipv6unicast; + iidtype = unspecified; + iidsubtype = unspecified; + + switch (addr->subtype) { + case UCAST_LOOPBACK: + subtype = ucastloopback; + iidtype = iidlowbyte; + break; + + case UCAST_GLOBAL: + subtype = ucastglobal; + break; + + case UCAST_V4MAPPED: + subtype = ucastv4mapped; + break; + + case UCAST_V4COMPAT: + subtype = ucastv4compat; + break; + + case UCAST_LINKLOCAL: + subtype = ucastlinklocal; + break; + + case UCAST_SITELOCAL: + subtype = ucastsitelocal; + break; + + case UCAST_UNIQUELOCAL: + subtype = ucastuniquelocal; + break; + + case UCAST_6TO4: + subtype = ucast6to4; + break; + + case UCAST_TEREDO: + subtype = ucastteredo; + break; + } + + if (addr->subtype == UCAST_GLOBAL || addr->subtype == UCAST_V4MAPPED || addr->subtype == UCAST_V4COMPAT || + addr->subtype == UCAST_LINKLOCAL || addr->subtype == UCAST_SITELOCAL || + addr->subtype == UCAST_UNIQUELOCAL || addr->subtype == UCAST_6TO4 || addr->subtype == UCAST_TEREDO) { + + switch (addr->iidtype) { + case IID_MACDERIVED: + iidtype = iidmacderived; + iidsubtype = iidsubtypebuffer; + + r = snprintf(iidsubtypebuffer, sizeof(iidsubtypebuffer), "%02x-%02x-%02x", + (addr->iidsubtype >> 16 & 0xff), (addr->iidsubtype >> 8 & 0xff), + (addr->iidsubtype & 0xff)); + + if (r == 8) + iidsubtype = iidsubtypebuffer; + + break; + + case IID_ISATAP: + iidtype = iidisatap; + break; + + case IID_EMBEDDEDIPV4: + iidtype = iidmbeddedipv4; + switch (addr->iidsubtype) { + case IID_EMBEDDEDIPV4_32: + iidsubtype = iidembeddedipv4_32; + break; + + case IID_EMBEDDEDIPV4_64: + iidsubtype = iidembeddedipv4_64; + break; + } + + break; + + case IID_EMBEDDEDPORT: + iidtype = iidembeddedport; + + switch (addr->iidsubtype) { + case IID_EMBEDDEDPORT: + iidsubtype = iidembeddedportfwd; + break; + + case IID_EMBEDDEDPORTREV: + iidsubtype = iidembeddedportrev; + break; + } + + break; + + case IID_LOWBYTE: + iidtype = iidlowbyte; + break; + + case IID_PATTERN_BYTES: + iidtype = iidpatternbytes; + break; + + case IID_RANDOM: + iidtype = iidrandom; + break; + + case IID_TEREDO: + iidtype = iidteredo; + + switch (addr->iidsubtype) { + case IID_TEREDO_RFC4380: + iidsubtype = iidteredorfc4380; + break; - case IID_PATTERN_BYTES: - iidtype= iidpatternbytes; - break; + case IID_TEREDO_RFC5991: + iidsubtype = iidteredorfc5991; + break; - case IID_RANDOM: - iidtype= iidrandom; - break; + case IID_TEREDO_UNKNOWN: + iidsubtype = iidteredounknown; + break; + } + + break; + } + } + + break; + + case IPV6_MULTICAST: + type = ipv6multicast; + iidtype = unspecified; + iidsubtype = unspecified; + switch (addr->subtype) { + case MCAST_PERMANENT: + subtype = mcastpermanent; + break; + + case MCAST_NONPERMANENT: + subtype = mcastnonpermanent; + break; - case IID_TEREDO: - iidtype= iidteredo; + case MCAST_INVALID: + subtype = mcastinvalid; + break; - switch(addr->iidsubtype){ - case IID_TEREDO_RFC4380: - iidsubtype= iidteredorfc4380; - break; + case MCAST_UNICASTBASED: + subtype = mcastunicastbased; + break; - case IID_TEREDO_RFC5991: - iidsubtype= iidteredorfc5991; - break; + case MCAST_EMBEDRP: + subtype = mcastembedrp; + break; - case IID_TEREDO_UNKNOWN: - iidsubtype= iidteredounknown; - break; - } + case MCAST_UNKNOWN: + subtype = mcastunknown; + break; + } + } + + switch (addr->scope) { + case SCOPE_RESERVED: + scope = scopereserved; + break; + + case SCOPE_INTERFACE: + scope = scopeinterface; + break; - break; - } - } + case SCOPE_LINK: + scope = scopelink; + break; - break; + case SCOPE_ADMIN: + scope = scopeadmin; + break; - case IPV6_MULTICAST: - type= ipv6multicast; - iidtype= unspecified; - iidsubtype= unspecified; + case SCOPE_SITE: + scope = scopesite; + break; - switch(addr->subtype){ - case MCAST_PERMANENT: - subtype= mcastpermanent; - break; + case SCOPE_ORGANIZATION: + scope = scopeorganization; + break; - case MCAST_NONPERMANENT: - subtype= mcastnonpermanent; - break; + case SCOPE_GLOBAL: + scope = scopeglobal; + break; - case MCAST_INVALID: - subtype= mcastinvalid; - break; + case SCOPE_UNSPECIFIED: + scope = scopeunspecified; + break; - case MCAST_UNICASTBASED: - subtype= mcastunicastbased; - break; - - case MCAST_EMBEDRP: - subtype= mcastembedrp; - break; - - case MCAST_UNKNOWN: - subtype= mcastunknown; - break; - } - } - - - switch(addr->scope){ - case SCOPE_RESERVED: - scope= scopereserved; - break; - - case SCOPE_INTERFACE: - scope= scopeinterface; - break; - - case SCOPE_LINK: - scope= scopelink; - break; - - case SCOPE_ADMIN: - scope= scopeadmin; - break; - - case SCOPE_SITE: - scope= scopesite; - break; - - case SCOPE_ORGANIZATION: - scope= scopeorganization; - break; - - case SCOPE_GLOBAL: - scope= scopeglobal; - break; - - case SCOPE_UNSPECIFIED: - scope= scopeunspecified; - break; - - default: - scope= scopeunassigned; - break; - } - - printf("%s=%s=%s=%s=%s\n", type, subtype, scope, iidtype, iidsubtype); + default: + scope = scopeunassigned; + break; + } + + printf("%s=%s=%s=%s=%s\n", type, subtype, scope, iidtype, iidsubtype); } - /* * Function: usage() * * Prints the syntax of the addr6 tool */ -void usage(void){ - puts("usage: addr6 (-i | -a) [-c | -d | -r | -s | -q] [-v] [-h]"); -} - +void usage(void) { puts("usage: addr6 (-i | -a) [-c | -d | -r | -s | -q] [-v] [-h]"); } /* * Function: print_help() @@ -1602,250 +1613,247 @@ void usage(void){ * Prints help information for the scan6 tool */ -void print_help(void){ - puts(SI6_TOOLKIT); - puts( "addr6: An IPv6 address analysis and conversion tool\n"); - usage(); - - puts("\nOPTIONS:\n" - " --address, -a IPv6 address to be decoded\n" - " --gen-addr, -A Generate a randmized address for the specified prefix\n" - " --stdin, -i Read IPv6 addresses from stdin (standard input)\n" - " --print-fixed, -f Print addresses in expanded/fixed format\n" - " --print-canonic, -c Print IPv6 addresses in canonic form\n" - " --print-reverse, -r Print reversed IPv6 address\n" - " --print-decode, -d Decode IPv6 addresses\n" - " --print-stats, -s Print statistics about IPv6 addresses\n" - " --print-response, -R Print result of address filters\n" - " --print-pattern, -x Analyze addresses pattern\n" - " --print-uni-preflen, -P Print unique prefixes of a specified length\n" - " --block-dup, -q Discard duplicate IPv6 addresses\n" - " --block-dup-preflen, -p Discard duplicate prefixes of specified length\n" - " --accept, -j Accept IPv6 addresses from specified IPv6 prefix\n" - " --accept-type, -b Accept IPv6 addresses of specified type\n" - " --accept-scope, -k Accept IPv6 addresses of specified scope\n" - " --accept-utype, -w Accept IPv6 unicast addresses of specified type\n" - " --accept-iid, -g Accept IPv6 addresses with IIDs of specified type\n" - " --block, -J Block IPv6 addresses from specified IPv6 prefix\n" - " --block-type, -B Block IPv6 addresses of specified type\n" - " --block-scope, -K Block IPv6 addresses of specified scope\n" - " --block-utype, -W Block IPv6 unicast addresses of specified type\n" - " --block-iid, -G Block IPv6 addresses with IIDs of specified type\n" - " --verbose, -v Be verbose\n" - " --help, -h Print help for the addr6 tool\n" - "\n" - " Programmed by Fernando Gont for SI6 Networks \n" - " Please send any bug reports to \n" - ); +void print_help(void) { + puts(SI6_TOOLKIT); + puts("addr6: An IPv6 address analysis and conversion tool\n"); + usage(); + + puts("\nOPTIONS:\n" + " --address, -a IPv6 address to be decoded\n" + " --gen-addr, -A Generate a randmized address for the specified prefix\n" + " --stdin, -i Read IPv6 addresses from stdin (standard input)\n" + " --print-fixed, -f Print addresses in expanded/fixed format\n" + " --print-canonic, -c Print IPv6 addresses in canonic form\n" + " --print-reverse, -r Print reversed IPv6 address\n" + " --print-decode, -d Decode IPv6 addresses\n" + " --print-stats, -s Print statistics about IPv6 addresses\n" + " --print-response, -R Print result of address filters\n" + " --print-pattern, -x Analyze addresses pattern\n" + " --print-uni-preflen, -P Print unique prefixes of a specified length\n" + " --block-dup, -q Discard duplicate IPv6 addresses\n" + " --block-dup-preflen, -p Discard duplicate prefixes of specified length\n" + " --accept, -j Accept IPv6 addresses from specified IPv6 prefix\n" + " --accept-type, -b Accept IPv6 addresses of specified type\n" + " --accept-scope, -k Accept IPv6 addresses of specified scope\n" + " --accept-utype, -w Accept IPv6 unicast addresses of specified type\n" + " --accept-iid, -g Accept IPv6 addresses with IIDs of specified type\n" + " --block, -J Block IPv6 addresses from specified IPv6 prefix\n" + " --block-type, -B Block IPv6 addresses of specified type\n" + " --block-scope, -K Block IPv6 addresses of specified scope\n" + " --block-utype, -W Block IPv6 unicast addresses of specified type\n" + " --block-iid, -G Block IPv6 addresses with IIDs of specified type\n" + " --verbose, -v Be verbose\n" + " --help, -h Print help for the addr6 tool\n" + "\n" + " Programmed by Fernando Gont for SI6 Networks \n" + " Please send any bug reports to \n"); } - /* * Function: init_host_list() * * Initilizes a host_list structure */ -int init_host_list(struct hashed_host_list *hlist){ - unsigned int i; +int init_host_list(struct hashed_host_list *hlist) { + unsigned int i; - memset(hlist, 0, sizeof(struct hashed_host_list)); + memset(hlist, 0, sizeof(struct hashed_host_list)); - if( (hlist->host = malloc(MAX_LIST_ENTRIES * sizeof(struct hashed_host_entry *))) == NULL){ - return(0); - } + if ((hlist->host = malloc(MAX_LIST_ENTRIES * sizeof(struct hashed_host_entry *))) == NULL) { + return (0); + } - for(i=0; i < MAX_LIST_ENTRIES; i++) - hlist->host[i]= NULL; + for (i = 0; i < MAX_LIST_ENTRIES; i++) + hlist->host[i] = NULL; - hlist->nhosts= 0; - hlist->maxhosts= MAX_HOST_ENTRIES; - hlist->key_l= random(); - hlist->key_h= random(); - return(1); + hlist->nhosts = 0; + hlist->maxhosts = MAX_HOST_ENTRIES; + hlist->key_l = random(); + hlist->key_h = random(); + return (1); } - /* * Function: key() * * Compute a key for accessing the hash-table of a hashed_host_list structure */ -uint16_t key(struct hashed_host_list *hlist, struct in6_addr *ipv6){ - return( ((hlist->key_l ^ (uint16_t)(ntohl(ipv6->s6_addr32[0]) >> 16) ^ (uint16_t)(ntohl(ipv6->s6_addr32[3]) & 0x0000ffff)) \ - ^ (hlist->key_h ^ (uint16_t)(ntohl(ipv6->s6_addr32[0]) >> 16) ^ (uint16_t)(ipv6->s6_addr32[3] >> 16))) % MAX_LIST_ENTRIES); +uint16_t key(struct hashed_host_list *hlist, struct in6_addr *ipv6) { + return (((hlist->key_l ^ (uint16_t)(ntohl(ipv6->s6_addr32[0]) >> 16) ^ + (uint16_t)(ntohl(ipv6->s6_addr32[3]) & 0x0000ffff)) ^ + (hlist->key_h ^ (uint16_t)(ntohl(ipv6->s6_addr32[0]) >> 16) ^ (uint16_t)(ipv6->s6_addr32[3] >> 16))) % + MAX_LIST_ENTRIES); } - /* * Function: add_hashed_host_entry() * * Add a hashed_host_entry structure to the hash table */ -struct hashed_host_entry *add_hashed_host_entry(struct hashed_host_list *hlist, struct in6_addr *ipv6){ - struct hashed_host_entry *hentry, *ptr; - uint16_t hkey; +struct hashed_host_entry *add_hashed_host_entry(struct hashed_host_list *hlist, struct in6_addr *ipv6) { + struct hashed_host_entry *hentry, *ptr; + uint16_t hkey; - hkey= key(hlist, ipv6); + hkey = key(hlist, ipv6); - if(hlist->nhosts >= hlist->maxhosts){ - return(NULL); - } + if (hlist->nhosts >= hlist->maxhosts) { + return (NULL); + } - if( (hentry= malloc(sizeof(struct hashed_host_entry))) == NULL){ - return(NULL); - } + if ((hentry = malloc(sizeof(struct hashed_host_entry))) == NULL) { + return (NULL); + } - memset(hentry, 0, sizeof(struct hashed_host_entry)); - hentry->ip6 = *ipv6; - hentry->next= NULL; + memset(hentry, 0, sizeof(struct hashed_host_entry)); + hentry->ip6 = *ipv6; + hentry->next = NULL; - if(hlist->host[hkey] == NULL){ - /* First node in chain */ - hlist->host[hkey]= hentry; - hentry->prev= NULL; - } - else{ - /* Find last node in list */ - for(ptr=hlist->host[hkey]; ptr->next != NULL; ptr= ptr->next); + if (hlist->host[hkey] == NULL) { + /* First node in chain */ + hlist->host[hkey] = hentry; + hentry->prev = NULL; + } + else { + /* Find last node in list */ + for (ptr = hlist->host[hkey]; ptr->next != NULL; ptr = ptr->next) + ; - hentry->prev= ptr; - ptr->next= hentry; - } + hentry->prev = ptr; + ptr->next = hentry; + } - (hlist->nhosts)++; + (hlist->nhosts)++; - return(hentry); + return (hentry); } - /* * Function: is_ip6_in_hashed_list() * * Checks whether an IPv6 address is present in a host list. */ -unsigned int is_ip6_in_hashed_list(struct hashed_host_list *hlist, struct in6_addr *target){ - uint16_t ckey; - struct hashed_host_entry *chentry; +unsigned int is_ip6_in_hashed_list(struct hashed_host_list *hlist, struct in6_addr *target) { + uint16_t ckey; + struct hashed_host_entry *chentry; - ckey= key(hlist, target); + ckey = key(hlist, target); - for(chentry= hlist->host[ckey]; chentry != NULL; chentry=chentry->next) - if( is_eq_in6_addr(target, &(chentry->ip6)) ) - return 1; + for (chentry = hlist->host[ckey]; chentry != NULL; chentry = chentry->next) + if (is_eq_in6_addr(target, &(chentry->ip6))) + return 1; - return 0; + return 0; } - - /* * Function: print_stats() * * Prints IPv6 address statistics */ -void print_stats(struct stats6 *stats){ - unsigned int totaliids=0; - puts("\n** IPv6 General Address Analysis **\n"); - printf("Total IPv6 addresses: %lu\n", stats->total); - - if(stats->total){ - printf("Unicast: %11lu (%6.2f%%)\tMulticast: %11lu (%6.2f%%)\n", stats->ipv6unicast, \ - ((float)(stats->ipv6unicast)/stats->total) * 100, stats->ipv6multicast, ((float)(stats->ipv6multicast)/stats->total) * 100); - printf("Unspec.: %11lu (%6.2f%%)\n\n", stats->ipv6unspecified, ((float)(stats->ipv6unspecified)/stats->total) * 100); - } - - if(stats->ipv6unicast){ - puts("** IPv6 Unicast Addresses **\n"); - printf("Loopback: %11lu (%6.2f%%)\tIPv4-mapped: %11lu (%6.2f%%)\n",\ - stats->ucastloopback, ((float)(stats->ucastloopback)/stats->ipv6unicast) * 100, stats->ucastv4mapped, \ - ((float)(stats->ucastv4mapped)/stats->ipv6unicast) * 100); - - printf("IPv4-compat.: %11lu (%6.2f%%)\tLink-local: %11lu (%6.2f%%)\n", stats->ucastv4compat, \ - ((float)(stats->ucastv4compat)/stats->ipv6unicast) * 100, stats->ucastlinklocal, \ - ((float)(stats->ucastlinklocal)/stats->ipv6unicast) * 100); - - printf("Site-local: %11lu (%6.2f%%)\tUnique-local: %11lu (%6.2f%%)\n", stats->ucastsitelocal, \ - ((float)(stats->ucastsitelocal)/stats->ipv6unicast) * 100, stats->ucastuniquelocal, \ - ((float)(stats->ucastuniquelocal)/stats->ipv6unicast) * 100); - - printf("6to4: %11lu (%6.2f%%)\tTeredo: %11lu (%6.2f%%)\n", stats->ucast6to4, \ - ((float)(stats->ucast6to4)/stats->ipv6unicast) * 100, stats->ucastteredo, \ - ((float)(stats->ucastteredo)/stats->ipv6unicast) * 100); - - printf("Global: %11lu (%6.2f%%)\n\n", stats->ucastglobal, ((float)(stats->ucastglobal)/stats->ipv6unicast) * 100); - } - - /* - XXX: We usedto exclude some of the unicast address types. Now we use all - totaliids= stats->ucastglobal + stats->ucastlinklocal + stats->ucastsitelocal + stats->ucastuniquelocal + \ - stats->ucast6to4; - */ - - totaliids= stats->ipv6unicast; - - if(totaliids){ - puts("+ IPv6 Unicast Interface Identifiers +\n"); - - printf("Total IIDs analyzed: %u\n", totaliids); - printf("IEEE-based: %11lu (%6.2f%%)\tLow-byte: %11lu (%6.2f%%)\n",\ - stats->iidmacderived, ((float)(stats->iidmacderived)/totaliids) * 100, stats->iidlowbyte, - ((float)(stats->iidlowbyte)/totaliids) * 100); - - printf("Embed-IPv4: %11lu (%6.2f%%)\tEmbed-IPv4 (64): %11lu (%6.2f%%)\n", stats->iidembeddedipv4_32, \ - ((float)(stats->iidembeddedipv4_32)/totaliids) * 100, stats->iidembeddedipv4_64, \ - ((float)(stats->iidembeddedipv4_64)/totaliids) * 100); - - printf("Embed-port: %11lu (%6.2f%%)\tEmbed-port (r): %11lu (%6.2f%%)\n", stats->iidembeddedport, \ - ((float)(stats->iidembeddedport)/totaliids) * 100, stats->iidembeddedportrev, \ - ((float)(stats->iidembeddedportrev)/totaliids) * 100); - - printf("ISATAP: %11lu (%6.2f%%)\tTeredo: %11lu (%6.2f%%)\n", stats->iidisatap, \ - ((float)(stats->iidisatap)/totaliids) * 100, stats->iidteredo, \ - ((float)(stats->iidteredo)/totaliids) * 100); - - - printf("Randomized: %11lu (%6.2f%%)\tByte-pattern: %11lu (%6.2f%%)\n\n", stats->iidrandom, \ - ((float)(stats->iidrandom)/totaliids) * 100, stats->iidpatternbytes, \ - ((float)(stats->iidpatternbytes)/totaliids) * 100); - } - - if(stats->ipv6multicast){ - puts("** IPv6 Multicast Addresses **\n"); - puts("+ Multicast Address Types +"); - printf("Permanent: %11lu (%.2f%%)\tNon-permanent %11lu (%.2f%%)\n",\ - stats->mcastpermanent, ((float)(stats->mcastpermanent)/stats->ipv6multicast) * 100, stats->mcastnonpermanent, \ - ((float)(stats->mcastnonpermanent)/stats->ipv6multicast) * 100); - - printf("Invalid: %11lu (%.2f%%)\tUnicast-based: %11lu (%.2f%%)\n", stats->mcastinvalid, \ - ((float)(stats->mcastinvalid)/stats->ipv6multicast) * 100, stats->mcastunicastbased, \ - ((float)(stats->mcastunicastbased)/stats->ipv6multicast) * 100); - - printf("Embedded-RP: %11lu (%.2f%%)\tUnknown: %11lu (%.2f%%)\n\n", stats->mcastembedrp, \ - ((float)(stats->mcastembedrp)/stats->ipv6multicast) * 100, stats->mcastunknown, \ - ((float)(stats->mcastunknown)/stats->ipv6multicast) * 100); - - puts("+ Multicast Address Scopes +"); - - printf("Reserved: %11lu (%.2f%%)\tInterface: %11lu (%.2f%%)\n",\ - stats->mscopereserved, ((float)(stats->mscopereserved)/stats->ipv6multicast) * 100, stats->mscopeinterface, \ - ((float)(stats->mscopeinterface)/stats->ipv6multicast) * 100); - - printf("Link: %11lu (%.2f%%)\tAdmin: %11lu (%.2f%%)\n", stats->mnscopelink, \ - ((float)(stats->mnscopelink)/stats->ipv6multicast) * 100, stats->mscopeadmin, \ - ((float)(stats->mscopeadmin)/stats->ipv6multicast) * 100); - - printf("Site: %11lu (%.2f%%)\tOrganization: %11lu (%.2f%%)\n", stats->mscopesite, \ - ((float)(stats->mscopesite)/stats->ipv6multicast) * 100, stats->mscopeorganization, \ - ((float)(stats->mscopeorganization)/stats->ipv6multicast) * 100); - - printf("Global: %11lu (%.2f%%)\tUnassigned: %11lu (%.2f%%)\n\n", stats->mscopeadmin, \ - ((float)(stats->mscopeadmin)/stats->ipv6multicast) * 100, stats->mscopesite, \ - ((float)(stats->mscopesite)/stats->ipv6multicast) * 100); - } +void print_stats(struct stats6 *stats) { + unsigned int totaliids = 0; + puts("\n** IPv6 General Address Analysis **\n"); + printf("Total IPv6 addresses: %lu\n", stats->total); + + if (stats->total) { + printf("Unicast: %11lu (%6.2f%%)\tMulticast: %11lu (%6.2f%%)\n", stats->ipv6unicast, + ((float)(stats->ipv6unicast) / stats->total) * 100, stats->ipv6multicast, + ((float)(stats->ipv6multicast) / stats->total) * 100); + printf("Unspec.: %11lu (%6.2f%%)\n\n", stats->ipv6unspecified, + ((float)(stats->ipv6unspecified) / stats->total) * 100); + } + + if (stats->ipv6unicast) { + puts("** IPv6 Unicast Addresses **\n"); + printf("Loopback: %11lu (%6.2f%%)\tIPv4-mapped: %11lu (%6.2f%%)\n", stats->ucastloopback, + ((float)(stats->ucastloopback) / stats->ipv6unicast) * 100, stats->ucastv4mapped, + ((float)(stats->ucastv4mapped) / stats->ipv6unicast) * 100); + + printf("IPv4-compat.: %11lu (%6.2f%%)\tLink-local: %11lu (%6.2f%%)\n", stats->ucastv4compat, + ((float)(stats->ucastv4compat) / stats->ipv6unicast) * 100, stats->ucastlinklocal, + ((float)(stats->ucastlinklocal) / stats->ipv6unicast) * 100); + + printf("Site-local: %11lu (%6.2f%%)\tUnique-local: %11lu (%6.2f%%)\n", stats->ucastsitelocal, + ((float)(stats->ucastsitelocal) / stats->ipv6unicast) * 100, stats->ucastuniquelocal, + ((float)(stats->ucastuniquelocal) / stats->ipv6unicast) * 100); + + printf("6to4: %11lu (%6.2f%%)\tTeredo: %11lu (%6.2f%%)\n", stats->ucast6to4, + ((float)(stats->ucast6to4) / stats->ipv6unicast) * 100, stats->ucastteredo, + ((float)(stats->ucastteredo) / stats->ipv6unicast) * 100); + + printf("Global: %11lu (%6.2f%%)\n\n", stats->ucastglobal, + ((float)(stats->ucastglobal) / stats->ipv6unicast) * 100); + } + + /* + XXX: We usedto exclude some of the unicast address types. Now we use all + totaliids= stats->ucastglobal + stats->ucastlinklocal + stats->ucastsitelocal + stats->ucastuniquelocal + \ + stats->ucast6to4; + */ + + totaliids = stats->ipv6unicast; + + if (totaliids) { + puts("+ IPv6 Unicast Interface Identifiers +\n"); + + printf("Total IIDs analyzed: %u\n", totaliids); + printf("IEEE-based: %11lu (%6.2f%%)\tLow-byte: %11lu (%6.2f%%)\n", stats->iidmacderived, + ((float)(stats->iidmacderived) / totaliids) * 100, stats->iidlowbyte, + ((float)(stats->iidlowbyte) / totaliids) * 100); + + printf("Embed-IPv4: %11lu (%6.2f%%)\tEmbed-IPv4 (64): %11lu (%6.2f%%)\n", stats->iidembeddedipv4_32, + ((float)(stats->iidembeddedipv4_32) / totaliids) * 100, stats->iidembeddedipv4_64, + ((float)(stats->iidembeddedipv4_64) / totaliids) * 100); + + printf("Embed-port: %11lu (%6.2f%%)\tEmbed-port (r): %11lu (%6.2f%%)\n", stats->iidembeddedport, + ((float)(stats->iidembeddedport) / totaliids) * 100, stats->iidembeddedportrev, + ((float)(stats->iidembeddedportrev) / totaliids) * 100); + + printf("ISATAP: %11lu (%6.2f%%)\tTeredo: %11lu (%6.2f%%)\n", stats->iidisatap, + ((float)(stats->iidisatap) / totaliids) * 100, stats->iidteredo, + ((float)(stats->iidteredo) / totaliids) * 100); + + printf("Randomized: %11lu (%6.2f%%)\tByte-pattern: %11lu (%6.2f%%)\n\n", stats->iidrandom, + ((float)(stats->iidrandom) / totaliids) * 100, stats->iidpatternbytes, + ((float)(stats->iidpatternbytes) / totaliids) * 100); + } + + if (stats->ipv6multicast) { + puts("** IPv6 Multicast Addresses **\n"); + puts("+ Multicast Address Types +"); + printf("Permanent: %11lu (%.2f%%)\tNon-permanent %11lu (%.2f%%)\n", stats->mcastpermanent, + ((float)(stats->mcastpermanent) / stats->ipv6multicast) * 100, stats->mcastnonpermanent, + ((float)(stats->mcastnonpermanent) / stats->ipv6multicast) * 100); + + printf("Invalid: %11lu (%.2f%%)\tUnicast-based: %11lu (%.2f%%)\n", stats->mcastinvalid, + ((float)(stats->mcastinvalid) / stats->ipv6multicast) * 100, stats->mcastunicastbased, + ((float)(stats->mcastunicastbased) / stats->ipv6multicast) * 100); + + printf("Embedded-RP: %11lu (%.2f%%)\tUnknown: %11lu (%.2f%%)\n\n", stats->mcastembedrp, + ((float)(stats->mcastembedrp) / stats->ipv6multicast) * 100, stats->mcastunknown, + ((float)(stats->mcastunknown) / stats->ipv6multicast) * 100); + + puts("+ Multicast Address Scopes +"); + + printf("Reserved: %11lu (%.2f%%)\tInterface: %11lu (%.2f%%)\n", stats->mscopereserved, + ((float)(stats->mscopereserved) / stats->ipv6multicast) * 100, stats->mscopeinterface, + ((float)(stats->mscopeinterface) / stats->ipv6multicast) * 100); + + printf("Link: %11lu (%.2f%%)\tAdmin: %11lu (%.2f%%)\n", stats->mnscopelink, + ((float)(stats->mnscopelink) / stats->ipv6multicast) * 100, stats->mscopeadmin, + ((float)(stats->mscopeadmin) / stats->ipv6multicast) * 100); + + printf("Site: %11lu (%.2f%%)\tOrganization: %11lu (%.2f%%)\n", stats->mscopesite, + ((float)(stats->mscopesite) / stats->ipv6multicast) * 100, stats->mscopeorganization, + ((float)(stats->mscopeorganization) / stats->ipv6multicast) * 100); + + printf("Global: %11lu (%.2f%%)\tUnassigned: %11lu (%.2f%%)\n\n", stats->mscopeadmin, + ((float)(stats->mscopeadmin) / stats->ipv6multicast) * 100, stats->mscopesite, + ((float)(stats->mscopesite) / stats->ipv6multicast) * 100); + } } - diff --git a/tools/addr6.h b/tools/addr6.h index 6f7269e..852dcb3 100644 --- a/tools/addr6.h +++ b/tools/addr6.h @@ -1,76 +1,72 @@ -#define MAX_LINE_SIZE 250 -#define MAX_TYPE_SIZE 25 -#define MAX_LIST_ENTRIES 65535 -#define MAX_HOST_ENTRIES 4000000000 -#define MAX_ADDR_PATTERN 10000000 -#define MAX_ADDR_FILTERS MAX_ADDR_PATTERN/100 +#define MAX_LINE_SIZE 250 +#define MAX_TYPE_SIZE 25 +#define MAX_LIST_ENTRIES 65535 +#define MAX_HOST_ENTRIES 4000000000 +#define MAX_ADDR_PATTERN 10000000 +#define MAX_ADDR_FILTERS MAX_ADDR_PATTERN / 100 /* Filter Constants */ -#define MAX_BLOCK 50 -#define MAX_ACCEPT 50 +#define MAX_BLOCK 50 +#define MAX_ACCEPT 50 - -struct hashed_host_entry{ - struct in6_addr ip6; - struct hashed_host_entry *next; - struct hashed_host_entry *prev; +struct hashed_host_entry { + struct in6_addr ip6; + struct hashed_host_entry *next; + struct hashed_host_entry *prev; }; -struct hashed_host_list{ - struct hashed_host_entry **host; /* Double-linked list of host entries */ - unsigned long nhosts; /* Current number of host entries */ - unsigned long maxhosts; /* Maximum number of host entries */ - uint16_t key_l; /* Low-order word of the hash key */ - uint16_t key_h; /* High-order word of the hash key */ +struct hashed_host_list { + struct hashed_host_entry **host; /* Double-linked list of host entries */ + unsigned long nhosts; /* Current number of host entries */ + unsigned long maxhosts; /* Maximum number of host entries */ + uint16_t key_l; /* Low-order word of the hash key */ + uint16_t key_h; /* High-order word of the hash key */ }; +struct stats6 { + unsigned long total; + unsigned long ipv6unspecified; + unsigned long ipv6multicast; + unsigned long ipv6unicast; -struct stats6{ - unsigned long total; - unsigned long ipv6unspecified; - unsigned long ipv6multicast; - unsigned long ipv6unicast; - - unsigned long ucastloopback; - unsigned long ucastv4mapped; - unsigned long ucastv4compat; - unsigned long ucastlinklocal; - unsigned long ucastsitelocal; - unsigned long ucastuniquelocal; - unsigned long ucast6to4; - unsigned long ucastteredo; - unsigned long ucastglobal; + unsigned long ucastloopback; + unsigned long ucastv4mapped; + unsigned long ucastv4compat; + unsigned long ucastlinklocal; + unsigned long ucastsitelocal; + unsigned long ucastuniquelocal; + unsigned long ucast6to4; + unsigned long ucastteredo; + unsigned long ucastglobal; - unsigned long mcastpermanent; - unsigned long mcastnonpermanent; - unsigned long mcastinvalid; - unsigned long mcastunicastbased; - unsigned long mcastembedrp; - unsigned long mcastunknown; + unsigned long mcastpermanent; + unsigned long mcastnonpermanent; + unsigned long mcastinvalid; + unsigned long mcastunicastbased; + unsigned long mcastembedrp; + unsigned long mcastunknown; - unsigned long iidmacderived; - unsigned long iidisatap; - unsigned long iidmbeddedipv4; /* This one is currently unused */ - unsigned long iidembeddedipv4_32; - unsigned long iidembeddedipv4_64; - unsigned long iidembeddedport; - unsigned long iidembeddedportfwd; - unsigned long iidembeddedportrev; - unsigned long iidlowbyte; - unsigned long iidpatternbytes; - unsigned long iidrandom; - unsigned long iidteredo; + unsigned long iidmacderived; + unsigned long iidisatap; + unsigned long iidmbeddedipv4; /* This one is currently unused */ + unsigned long iidembeddedipv4_32; + unsigned long iidembeddedipv4_64; + unsigned long iidembeddedport; + unsigned long iidembeddedportfwd; + unsigned long iidembeddedportrev; + unsigned long iidlowbyte; + unsigned long iidpatternbytes; + unsigned long iidrandom; + unsigned long iidteredo; - unsigned long mscopereserved; - unsigned long mscopeinterface; - unsigned long mnscopelink; - unsigned long mscopeadmin; - unsigned long mscopesite; - unsigned long mscopeorganization; - unsigned long mscopeglobal; - unsigned long mscopeunassigned; - unsigned long mscopeunspecified; + unsigned long mscopereserved; + unsigned long mscopeinterface; + unsigned long mnscopelink; + unsigned long mscopeadmin; + unsigned long mscopesite; + unsigned long mscopeorganization; + unsigned long mscopeglobal; + unsigned long mscopeunassigned; + unsigned long mscopeunspecified; }; - - diff --git a/tools/flow6.c b/tools/flow6.c index 5c3bbdf..cc62d52 100644 --- a/tools/flow6.c +++ b/tools/flow6.c @@ -19,866 +19,849 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - * + * * Build with: make flow6 - * + * * It requires that the libpcap library be installed on your system. * * Please send any bug reports to Fernando Gont */ -#include #include #include #include +#include -#include #include -#include +#include +#include #include +#include +#include #include #include -#include -#include -#include -#include #include -#include #include -#include +#include #include +#include +#include #include -#include +#include +#include #include "flow6.h" #include "ipv6toolkit.h" #include "libipv6.h" - /* Function prototypes */ -void print_attack_info(void); -void usage(void); -void print_help(void); -int send_fid_probe(void); -int predict_flow_id(uint32_t *, unsigned int, uint32_t *, unsigned int); - +void print_attack_info(void); +void usage(void); +void print_help(void); +int send_fid_probe(void); +int predict_flow_id(uint32_t *, unsigned int, uint32_t *, unsigned int); /* Used for router discovery */ -struct iface_data idata; -struct in6_addr randprefix; -unsigned char randpreflen; +struct iface_data idata; +struct in6_addr randprefix; +unsigned char randpreflen; /* Data structures for packets read from the wire */ -struct pcap_pkthdr *pkthdr; -const u_char *pktdata; -unsigned char *pkt_end, *pkt_ptr; -struct ether_header *pkt_ether; -struct ip6_hdr *pkt_ipv6; -struct tcp_hdr *pkt_tcp; -struct udp_hdr *pkt_udp; -struct icmp6_hdr *pkt_icmp6; +struct pcap_pkthdr *pkthdr; +const u_char *pktdata; +unsigned char *pkt_end, *pkt_ptr; +struct ether_header *pkt_ether; +struct ip6_hdr *pkt_ipv6; +struct tcp_hdr *pkt_tcp; +struct udp_hdr *pkt_udp; +struct icmp6_hdr *pkt_icmp6; struct nd_neighbor_solicit *pkt_ns; -struct in6_addr *pkt_ipv6addr; -unsigned int pktbytes; - - -bpf_u_int32 my_netmask; -bpf_u_int32 my_ip; -struct bpf_program pcap_filter; -char dev[64], errbuf[PCAP_ERRBUF_SIZE]; -unsigned char buffer[65556], buffrh[MIN_IPV6_HLEN + MIN_TCP_HLEN]; -unsigned char *v6buffer, *ptr, *startofprefixes; -char *pref; -char iface[IFACE_LENGTH]; - -struct ip6_hdr *ipv6; -struct icmp6_hdr *icmp6; - -struct ether_header *ethernet; -struct nd_opt_tlla *tllaopt; -struct ether_addr linkaddr[MAX_TLLA_OPTION]; -unsigned int nlinkaddr=0, linkaddrs; - -char *lasts, *rpref; -char *charptr; - -int nw; -unsigned long ul_res, ul_val; -unsigned int i, j, startrand; -unsigned int skip; -unsigned int frags, nfrags, nsleep; -unsigned char srcpreflen; - -uint16_t mask, ip6length; -uint8_t hoplimit; - -char plinkaddr[ETHER_ADDR_PLEN]; -char psrcaddr[INET6_ADDRSTRLEN], pdstaddr[INET6_ADDRSTRLEN], pv6addr[INET6_ADDRSTRLEN]; -unsigned char localaddr_f=0; -unsigned char srcprefix_f=0, hoplimit_f=0, flowidp_f=0, dstport_f=0, protocol_f=0; +struct in6_addr *pkt_ipv6addr; +unsigned int pktbytes; + +bpf_u_int32 my_netmask; +bpf_u_int32 my_ip; +struct bpf_program pcap_filter; +char dev[64], errbuf[PCAP_ERRBUF_SIZE]; +unsigned char buffer[65556], buffrh[MIN_IPV6_HLEN + MIN_TCP_HLEN]; +unsigned char *v6buffer, *ptr, *startofprefixes; +char *pref; +char iface[IFACE_LENGTH]; + +struct ip6_hdr *ipv6; +struct icmp6_hdr *icmp6; + +struct ether_header *ethernet; +struct nd_opt_tlla *tllaopt; +struct ether_addr linkaddr[MAX_TLLA_OPTION]; +unsigned int nlinkaddr = 0, linkaddrs; + +char *lasts, *rpref; +char *charptr; + +int nw; +unsigned long ul_res, ul_val; +unsigned int i, j, startrand; +unsigned int skip; +unsigned int frags, nfrags, nsleep; +unsigned char srcpreflen; + +uint16_t mask, ip6length; +uint8_t hoplimit; + +char plinkaddr[ETHER_ADDR_PLEN]; +char psrcaddr[INET6_ADDRSTRLEN], pdstaddr[INET6_ADDRSTRLEN], pv6addr[INET6_ADDRSTRLEN]; +unsigned char localaddr_f = 0; +unsigned char srcprefix_f = 0, hoplimit_f = 0, flowidp_f = 0, dstport_f = 0, protocol_f = 0; /* Support for Extension Headers */ -unsigned int dstopthdrs, dstoptuhdrs, hbhopthdrs; -char hbhopthdr_f=0, dstoptuhdr_f=0, dstopthdr_f=0; -unsigned char *dstopthdr[MAX_DST_OPT_HDR], *dstoptuhdr[MAX_DST_OPT_U_HDR]; -unsigned char *hbhopthdr[MAX_HBH_OPT_HDR]; -unsigned int dstopthdrlen[MAX_DST_OPT_HDR], dstoptuhdrlen[MAX_DST_OPT_U_HDR]; -unsigned int hbhopthdrlen[MAX_HBH_OPT_HDR], m, pad; - -struct ip6_frag *fh; -struct ip6_hdr *fipv6; -unsigned char fragh_f=0; - -unsigned char *fragpart, *ptrend, *ptrhdr, *ptrhdrend; -unsigned int hdrlen, ndstopthdr=0, nhbhopthdr=0, ndstoptuhdr=0; -unsigned int nfrags, fragsize; -unsigned char *prev_nh, *startoffragment; - +unsigned int dstopthdrs, dstoptuhdrs, hbhopthdrs; +char hbhopthdr_f = 0, dstoptuhdr_f = 0, dstopthdr_f = 0; +unsigned char *dstopthdr[MAX_DST_OPT_HDR], *dstoptuhdr[MAX_DST_OPT_U_HDR]; +unsigned char *hbhopthdr[MAX_HBH_OPT_HDR]; +unsigned int dstopthdrlen[MAX_DST_OPT_HDR], dstoptuhdrlen[MAX_DST_OPT_U_HDR]; +unsigned int hbhopthdrlen[MAX_HBH_OPT_HDR], m, pad; + +struct ip6_frag *fh; +struct ip6_hdr *fipv6; +unsigned char fragh_f = 0; + +unsigned char *fragpart, *ptrend, *ptrhdr, *ptrhdrend; +unsigned int hdrlen, ndstopthdr = 0, nhbhopthdr = 0, ndstoptuhdr = 0; +unsigned int nfrags, fragsize; +unsigned char *prev_nh, *startoffragment; /* For the sampling of Flow Label values */ -uint16_t baseport, lastport, dstport, tcpwin, addr_sig, addr_key; -uint32_t tcpseq; -uint8_t protocol; - - -int main(int argc, char **argv){ - extern char *optarg; - fd_set sset, rset; - struct timeval timeout; - int r, sel; - time_t curtime, start, lastfrag1=0; - struct target_ipv6 targetipv6; - - /* Arrays for storing the Flow ID samples */ - uint32_t test1[NSAMPLES], test2[NSAMPLES]; - unsigned int ntest1=0, ntest2=0; - unsigned char testtype; - - static struct option longopts[] = { - {"interface", required_argument, 0, 'i'}, - {"src-addr", required_argument, 0, 's'}, - {"dst-addr", required_argument, 0, 'd'}, - {"hop-limit", required_argument, 0, 'A'}, - {"link-src-addr", required_argument, 0, 'S'}, - {"link-dst-addr", required_argument, 0, 'D'}, - {"protocol", required_argument, 0, 'P'}, - {"dst-port", no_argument, 0, 'p'}, - {"flow-label-policy", no_argument, 0, 'W'}, - {"verbose", no_argument, 0, 'v'}, - {"help", no_argument, 0, 'h'}, - {0, 0, 0, 0 } - }; - - const char shortopts[]= "i:s:d:A:S:D:P:p:Wvh"; - - char option; - - if(argc<=1){ - usage(); - exit(EXIT_FAILURE); - } - - - srandom(time(NULL)); - hoplimit=64+random()%180; - - if(init_iface_data(&idata) == FAILURE){ - puts("Error initializing internal data structure"); - exit(EXIT_FAILURE); - } - - while((r=getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { - option= r; - - switch(option) { - - case 'i': /* Interface */ - strncpy(idata.iface, optarg, IFACE_LENGTH); - idata.iface[IFACE_LENGTH-1]=0; - idata.ifindex= if_nametoindex(idata.iface); - idata.iface_f=TRUE; - break; - - case 's': /* IPv6 Source Address */ - if((charptr = strtok_r(optarg, "/", &lasts)) == NULL){ - puts("Error in Source Address"); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, charptr, &(idata.srcaddr)) <= 0){ - puts("inet_pton(): Source Address not valid"); - exit(EXIT_FAILURE); - } - - idata.srcaddr_f = 1; - - if((charptr = strtok_r(NULL, " ", &lasts)) != NULL){ - srcpreflen = atoi(charptr); - - if(srcpreflen>128){ - puts("Prefix length error in IPv6 Source Address"); - exit(EXIT_FAILURE); - } - - sanitize_ipv6_prefix(&(idata.srcaddr), srcpreflen); - srcprefix_f=1; - } - - break; - - case 'd': /* IPv6 Destination Address */ - strncpy( targetipv6.name, optarg, NI_MAXHOST); - targetipv6.name[NI_MAXHOST-1]= 0; - targetipv6.flags= AI_CANONNAME; - - if( (r=get_ipv6_target(&targetipv6)) != 0){ - - if(r < 0){ - printf("Unknown Destination: %s\n", gai_strerror(targetipv6.res)); - } - else{ - puts("Unknown Destination: No IPv6 address found for specified destination"); - } - - exit(EXIT_FAILURE); - } - - idata.dstaddr= targetipv6.ip6; - idata.dstaddr_f = 1; - break; - - case 'A': /* Hop Limit */ - hoplimit= atoi(optarg); - hoplimit_f=1; - break; - - case 'S': /* Source Ethernet address */ - if(ether_pton(optarg, &(idata.hsrcaddr), sizeof(idata.hsrcaddr)) == 0){ - puts("Error in Source link-layer address."); - exit(EXIT_FAILURE); - } - - idata.hsrcaddr_f = 1; - break; - - case 'D': /* Destination Ethernet Address */ - if(ether_pton(optarg, &(idata.hdstaddr), sizeof(idata.hdstaddr)) == 0){ - puts("Error in Source link-layer address."); - exit(EXIT_FAILURE); - } - - idata.hdstaddr_f = 1; - break; - - case 'P': /* Protocol */ - if(strncmp(optarg, "tcp", MAX_STRING_SIZE) == 0 || \ - strncmp(optarg, "TCP", MAX_STRING_SIZE) == 0){ - protocol= IPPROTO_TCP; - } - else if(strncmp(optarg, "udp", MAX_STRING_SIZE) == 0 || \ - strncmp(optarg, "UDP", MAX_STRING_SIZE) == 0){ - protocol= IPPROTO_UDP; - } - else{ - puts("Unknown protocol type (valid types: 'tcp', 'udp')"); - exit(EXIT_FAILURE); - } - - protocol_f= 1; - break; - - case 'p': /* Destination port */ - dstport= atoi(optarg); - dstport_f=1; - break; - - case 'W': /* Assess the Flow Label generation policy of the target */ - flowidp_f= 1; - break; - - case 'v': /* Be verbose */ - idata.verbose_f++; - break; - - case 'h': /* Help */ - print_help(); - - exit(EXIT_FAILURE); - break; - - default: - usage(); - exit(EXIT_FAILURE); - break; - - } /* switch */ - } /* while(getopt) */ - - if(geteuid()) { - puts("flow6 needs root privileges to run."); - exit(EXIT_FAILURE); - } - - if(!idata.iface_f){ - if(idata.dstaddr_f && IN6_IS_ADDR_LINKLOCAL(&(idata.dstaddr))){ - puts("Must specify a network interface for link-local destinations"); - exit(EXIT_FAILURE); - } - } - - if(load_dst_and_pcap(&idata, LOAD_SRC_NXT_HOP) == FAILURE){ - puts("Error while learning Source Address and Next Hop"); - exit(EXIT_FAILURE); - } - - release_privileges(); - - if( !fragh_f && dstoptuhdr_f){ - puts("Dst. Options Header (Unfragmentable Part) set, but Fragmentation not specified"); - exit(EXIT_FAILURE); - } - - if(idata.verbose_f){ - print_attack_info(); - } - - if(!idata.dstaddr_f){ - puts("Error: Nothing to send! (Destination Address left unspecified)"); - exit(EXIT_FAILURE); - } - - /* Assess the Flow ID generation policy */ - if(flowidp_f){ - if(dstport_f && !protocol_f){ - puts("Error: Must specify a protocol if the port number is specified"); - exit(EXIT_FAILURE); - } - - if(!protocol_f){ - protocol= IPPROTO_TCP; - dstport= 80; - } - else if(!dstport_f){ - if(protocol == IPPROTO_TCP) - dstport= 80; - else - dstport= 53; - } - - puts("Identifying the 'Flow ID' generation policy of the target node...."); - - if(protocol == IPPROTO_TCP){ - tcpwin= ((uint16_t) random() + 1500) & (uint16_t)0x7f00; - tcpseq= random(); - baseport= 50000+ random()%10000; - lastport= baseport; - } - - /* - Set filter for receiving Neighbor Solicitations, and TCP segments - */ - if(pcap_compile(idata.pfd, &pcap_filter, PCAP_NSTCP_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1){ - printf("pcap_compile(): %s", pcap_geterr(idata.pfd)); - exit(EXIT_FAILURE); - } - - if(pcap_setfilter(idata.pfd, &pcap_filter) == -1){ - printf("pcap_setfilter(): %s", pcap_geterr(idata.pfd)); - exit(EXIT_FAILURE); - } - - pcap_freecode(&pcap_filter); - - FD_ZERO(&sset); - FD_SET(idata.fd, &sset); - start= time(NULL); - lastfrag1=0; - ntest1=0; - ntest2=0; - testtype= FIXED_ORIGIN; - - if(srcprefix_f){ - randprefix= idata.srcaddr; - randpreflen=srcpreflen; - } - else{ - randprefix= idata.srcaddr; - randpreflen=64; - sanitize_ipv6_prefix(&randprefix, randpreflen); - } - - while(1){ - curtime=time(NULL); - - if( testtype==FIXED_ORIGIN && ((curtime - start) >= ID_ASSESS_TIMEOUT || ntest1 >= NSAMPLES)){ - testtype= MULTI_ORIGIN; - addr_sig= random(); - addr_key= random(); - start= curtime; - continue; - } - else if( testtype==MULTI_ORIGIN && ((curtime - start) >= ID_ASSESS_TIMEOUT || ntest2 >= NSAMPLES)){ - break; - } - - if((curtime - lastfrag1) >= 1){ - if(testtype == FIXED_ORIGIN){ - for(i=0; i>16) ^ addr_key)); - - if(send_neighbor_solicit(&idata, &(idata.dstaddr)) == -1){ - puts("Error while sending Neighbor Solicitation"); - exit(EXIT_FAILURE); - } - - if(send_fid_probe() == -1){ - puts("Error while sending packet"); - exit(EXIT_FAILURE); - } - - lastport++; - } - } - - lastfrag1=curtime; - continue; - } - - rset= sset; +uint16_t baseport, lastport, dstport, tcpwin, addr_sig, addr_key; +uint32_t tcpseq; +uint8_t protocol; + +int main(int argc, char **argv) { + extern char *optarg; + fd_set sset, rset; + struct timeval timeout; + int r, sel; + time_t curtime, start, lastfrag1 = 0; + struct target_ipv6 targetipv6; + + /* Arrays for storing the Flow ID samples */ + uint32_t test1[NSAMPLES], test2[NSAMPLES]; + unsigned int ntest1 = 0, ntest2 = 0; + unsigned char testtype; + + static struct option longopts[] = {{"interface", required_argument, 0, 'i'}, + {"src-addr", required_argument, 0, 's'}, + {"dst-addr", required_argument, 0, 'd'}, + {"hop-limit", required_argument, 0, 'A'}, + {"link-src-addr", required_argument, 0, 'S'}, + {"link-dst-addr", required_argument, 0, 'D'}, + {"protocol", required_argument, 0, 'P'}, + {"dst-port", no_argument, 0, 'p'}, + {"flow-label-policy", no_argument, 0, 'W'}, + {"verbose", no_argument, 0, 'v'}, + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0}}; + + const char shortopts[] = "i:s:d:A:S:D:P:p:Wvh"; + + char option; + + if (argc <= 1) { + usage(); + exit(EXIT_FAILURE); + } + + srandom(time(NULL)); + hoplimit = 64 + random() % 180; + + if (init_iface_data(&idata) == FAILURE) { + puts("Error initializing internal data structure"); + exit(EXIT_FAILURE); + } + + while ((r = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { + option = r; + + switch (option) { + + case 'i': /* Interface */ + strncpy(idata.iface, optarg, IFACE_LENGTH); + idata.iface[IFACE_LENGTH - 1] = 0; + idata.ifindex = if_nametoindex(idata.iface); + idata.iface_f = TRUE; + break; + + case 's': /* IPv6 Source Address */ + if ((charptr = strtok_r(optarg, "/", &lasts)) == NULL) { + puts("Error in Source Address"); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, charptr, &(idata.srcaddr)) <= 0) { + puts("inet_pton(): Source Address not valid"); + exit(EXIT_FAILURE); + } + + idata.srcaddr_f = 1; + + if ((charptr = strtok_r(NULL, " ", &lasts)) != NULL) { + srcpreflen = atoi(charptr); + + if (srcpreflen > 128) { + puts("Prefix length error in IPv6 Source Address"); + exit(EXIT_FAILURE); + } + + sanitize_ipv6_prefix(&(idata.srcaddr), srcpreflen); + srcprefix_f = 1; + } + + break; + + case 'd': /* IPv6 Destination Address */ + strncpy(targetipv6.name, optarg, NI_MAXHOST); + targetipv6.name[NI_MAXHOST - 1] = 0; + targetipv6.flags = AI_CANONNAME; + + if ((r = get_ipv6_target(&targetipv6)) != 0) { + + if (r < 0) { + printf("Unknown Destination: %s\n", gai_strerror(targetipv6.res)); + } + else { + puts("Unknown Destination: No IPv6 address found for specified destination"); + } + + exit(EXIT_FAILURE); + } + + idata.dstaddr = targetipv6.ip6; + idata.dstaddr_f = 1; + break; + + case 'A': /* Hop Limit */ + hoplimit = atoi(optarg); + hoplimit_f = 1; + break; + + case 'S': /* Source Ethernet address */ + if (ether_pton(optarg, &(idata.hsrcaddr), sizeof(idata.hsrcaddr)) == 0) { + puts("Error in Source link-layer address."); + exit(EXIT_FAILURE); + } + + idata.hsrcaddr_f = 1; + break; + + case 'D': /* Destination Ethernet Address */ + if (ether_pton(optarg, &(idata.hdstaddr), sizeof(idata.hdstaddr)) == 0) { + puts("Error in Source link-layer address."); + exit(EXIT_FAILURE); + } + + idata.hdstaddr_f = 1; + break; + + case 'P': /* Protocol */ + if (strncmp(optarg, "tcp", MAX_STRING_SIZE) == 0 || strncmp(optarg, "TCP", MAX_STRING_SIZE) == 0) { + protocol = IPPROTO_TCP; + } + else if (strncmp(optarg, "udp", MAX_STRING_SIZE) == 0 || strncmp(optarg, "UDP", MAX_STRING_SIZE) == 0) { + protocol = IPPROTO_UDP; + } + else { + puts("Unknown protocol type (valid types: 'tcp', 'udp')"); + exit(EXIT_FAILURE); + } + + protocol_f = 1; + break; + + case 'p': /* Destination port */ + dstport = atoi(optarg); + dstport_f = 1; + break; + + case 'W': /* Assess the Flow Label generation policy of the target */ + flowidp_f = 1; + break; + + case 'v': /* Be verbose */ + idata.verbose_f++; + break; + + case 'h': /* Help */ + print_help(); + + exit(EXIT_FAILURE); + break; + + default: + usage(); + exit(EXIT_FAILURE); + break; + + } /* switch */ + } /* while(getopt) */ + + if (geteuid()) { + puts("flow6 needs root privileges to run."); + exit(EXIT_FAILURE); + } + + if (!idata.iface_f) { + if (idata.dstaddr_f && IN6_IS_ADDR_LINKLOCAL(&(idata.dstaddr))) { + puts("Must specify a network interface for link-local destinations"); + exit(EXIT_FAILURE); + } + } + + if (load_dst_and_pcap(&idata, LOAD_SRC_NXT_HOP) == FAILURE) { + puts("Error while learning Source Address and Next Hop"); + exit(EXIT_FAILURE); + } + + release_privileges(); + + if (!fragh_f && dstoptuhdr_f) { + puts("Dst. Options Header (Unfragmentable Part) set, but Fragmentation not specified"); + exit(EXIT_FAILURE); + } + + if (idata.verbose_f) { + print_attack_info(); + } + + if (!idata.dstaddr_f) { + puts("Error: Nothing to send! (Destination Address left unspecified)"); + exit(EXIT_FAILURE); + } + + /* Assess the Flow ID generation policy */ + if (flowidp_f) { + if (dstport_f && !protocol_f) { + puts("Error: Must specify a protocol if the port number is specified"); + exit(EXIT_FAILURE); + } + + if (!protocol_f) { + protocol = IPPROTO_TCP; + dstport = 80; + } + else if (!dstport_f) { + if (protocol == IPPROTO_TCP) + dstport = 80; + else + dstport = 53; + } + + puts("Identifying the 'Flow ID' generation policy of the target node...."); + + if (protocol == IPPROTO_TCP) { + tcpwin = ((uint16_t)random() + 1500) & (uint16_t)0x7f00; + tcpseq = random(); + baseport = 50000 + random() % 10000; + lastport = baseport; + } + + /* + Set filter for receiving Neighbor Solicitations, and TCP segments + */ + if (pcap_compile(idata.pfd, &pcap_filter, PCAP_NSTCP_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1) { + printf("pcap_compile(): %s", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } + + if (pcap_setfilter(idata.pfd, &pcap_filter) == -1) { + printf("pcap_setfilter(): %s", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } + + pcap_freecode(&pcap_filter); + + FD_ZERO(&sset); + FD_SET(idata.fd, &sset); + start = time(NULL); + lastfrag1 = 0; + ntest1 = 0; + ntest2 = 0; + testtype = FIXED_ORIGIN; + + if (srcprefix_f) { + randprefix = idata.srcaddr; + randpreflen = srcpreflen; + } + else { + randprefix = idata.srcaddr; + randpreflen = 64; + sanitize_ipv6_prefix(&randprefix, randpreflen); + } + + while (1) { + curtime = time(NULL); + + if (testtype == FIXED_ORIGIN && ((curtime - start) >= ID_ASSESS_TIMEOUT || ntest1 >= NSAMPLES)) { + testtype = MULTI_ORIGIN; + addr_sig = random(); + addr_key = random(); + start = curtime; + continue; + } + else if (testtype == MULTI_ORIGIN && ((curtime - start) >= ID_ASSESS_TIMEOUT || ntest2 >= NSAMPLES)) { + break; + } + + if ((curtime - lastfrag1) >= 1) { + if (testtype == FIXED_ORIGIN) { + for (i = 0; i < NSAMPLES; i++) { + if (send_fid_probe() == -1) { + puts("Error while sending packet"); + exit(EXIT_FAILURE); + } + + lastport++; + } + } + else { + for (i = 0; i < NSAMPLES; i++) { + randomize_ipv6_addr(&(idata.srcaddr), &randprefix, randpreflen); + + /* + * Two words of the Source IPv6 Address are specially encoded such that we only respond + * to Neighbor Solicitations that target those addresses, and accept ICMPv6 Echo Replies + * only if they are destined to those addresses + */ + idata.srcaddr.s6_addr32[2] = htonl((ntohl(idata.srcaddr.s6_addr32[2]) & 0xffff0000) | addr_sig); + idata.srcaddr.s6_addr32[3] = + htonl((ntohl(idata.srcaddr.s6_addr32[3]) & 0xffff0000) | + ((uint16_t)(ntohl(idata.srcaddr.s6_addr32[3]) >> 16) ^ addr_key)); + + if (send_neighbor_solicit(&idata, &(idata.dstaddr)) == -1) { + puts("Error while sending Neighbor Solicitation"); + exit(EXIT_FAILURE); + } + + if (send_fid_probe() == -1) { + puts("Error while sending packet"); + exit(EXIT_FAILURE); + } + + lastport++; + } + } + + lastfrag1 = curtime; + continue; + } + + rset = sset; #if !defined(sun) && !defined(__sun) - timeout.tv_usec=0; - timeout.tv_sec= 1; + timeout.tv_usec = 0; + timeout.tv_sec = 1; #else - timeout.tv_usec=10000; - timeout.tv_sec= 0; + timeout.tv_usec = 10000; + timeout.tv_sec = 0; #endif - if((sel=select(idata.fd+1, &rset, NULL, NULL, &timeout)) == -1){ - if(errno == EINTR){ - continue; - } - else{ - puts("Error in select()"); - exit(EXIT_FAILURE); - } - } + if ((sel = select(idata.fd + 1, &rset, NULL, NULL, &timeout)) == -1) { + if (errno == EINTR) { + continue; + } + else { + puts("Error in select()"); + exit(EXIT_FAILURE); + } + } #if defined(sun) || defined(__sun) - if(TRUE){ + if (TRUE) { #else - if(sel && FD_ISSET(idata.fd, &rset)){ + if (sel && FD_ISSET(idata.fd, &rset)) { #endif - /* Read a packet (Echo Reply, or Neighbor Solicitation) */ - if((r=pcap_next_ex(idata.pfd, &pkthdr, &pktdata)) == -1){ - printf("pcap_next_ex(): %s", pcap_geterr(idata.pfd)); - exit(EXIT_FAILURE); - } - else if(r == 1 && pktdata != NULL){ - pkt_ether = (struct ether_header *) pktdata; - pkt_ipv6 = (struct ip6_hdr *)((char *) pkt_ether + idata.linkhsize); - pkt_icmp6 = (struct icmp6_hdr *) ((char *) pkt_ipv6 + sizeof(struct ip6_hdr)); - pkt_end = (unsigned char *) pktdata + pkthdr->caplen; - - if( (pkt_end - pktdata) < (idata.linkhsize + MIN_IPV6_HLEN)) - continue; - - if(pkt_ipv6->ip6_nxt == IPPROTO_ICMPV6 && pkt_icmp6->icmp6_type == ND_NEIGHBOR_SOLICIT){ - pkt_ns= (struct nd_neighbor_solicit *) pkt_icmp6; - - if( (pkt_end - (unsigned char *) pkt_ns) < sizeof(struct nd_neighbor_solicit)) - continue; - /* - If the addresses that we're using are not actually configured on the local system - (i.e., they are "spoofed", we must check whether it is a Neighbor Solicitation for - one of our addresses, and respond with a Neighbor Advertisement. Otherwise, the kernel - will take care of that. - */ - if(testtype==FIXED_ORIGIN){ - if(!localaddr_f && is_eq_in6_addr(&(pkt_ns->nd_ns_target), &(idata.srcaddr))){ - if(send_neighbor_advert(&idata, idata.pfd, pktdata) == -1){ - puts("Error sending Neighbor Advertisement"); - exit(EXIT_FAILURE); - } - } - } - else if(idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK)){ - if( (ntohl(pkt_ns->nd_ns_target.s6_addr32[2]) & 0x0000ffff) != addr_sig || \ - (ntohl(pkt_ns->nd_ns_target.s6_addr32[3]) & 0x0000ffff) != ( (ntohl(pkt_ns->nd_ns_target.s6_addr32[3])>>16) ^ addr_key)){ - continue; - } - - if(send_neighbor_advert(&idata, idata.pfd, pktdata) == -1){ - puts("Error sending Neighbor Advertisement"); - exit(EXIT_FAILURE); - } - } - } - else if(pkt_ipv6->ip6_nxt == protocol){ - - /* Perform TCP-specific validation checks */ - if(protocol == IPPROTO_TCP){ - if( (pkt_end - (unsigned char *) pkt_ipv6) < \ - (sizeof(struct ip6_hdr) + sizeof(struct tcp_hdr))) - continue; - - pkt_tcp= (struct tcp_hdr *) ((unsigned char *)pkt_ipv6 + sizeof(struct ip6_hdr)); - - /* - * The TCP Destination Port must correspond to one of the ports that we have used as - * TCP Source Port - */ - if(ntohs(pkt_tcp->th_dport) < baseport || ntohs(pkt_tcp->th_dport) > lastport) - continue; - - /* The Source Port must be that to which we're sending our TCP segments */ - if(ntohs(pkt_tcp->th_sport) != dstport) - continue; - - /* The TCP Acknowledgement Number must ack our SYN */ - if(ntohl(pkt_tcp->th_ack) != tcpseq+1) - continue; - - /* We sample Flow ID's only on SYN/ACKs */ - if( (pkt_tcp->th_flags & ~TH_SYN) == 0 || (pkt_tcp->th_flags & TH_ACK) == 0) - continue; - - /* The TCP checksum must be valid */ - if(in_chksum(pkt_ipv6, pkt_tcp, pkt_end-((unsigned char *)pkt_tcp), IPPROTO_TCP) != 0) - continue; - } - /* Perform UDP-specific validation checks */ - else if(protocol == IPPROTO_UDP){ - if( (pkt_end - (unsigned char *) pkt_ipv6) < \ - (sizeof(struct ip6_hdr) + sizeof(struct udp_hdr))) - continue; - - pkt_udp= (struct udp_hdr *) ((unsigned char *)pkt_ipv6 + sizeof(struct ip6_hdr)); - - /* - * The UDP Destination Port must correspond to one of the ports that we have used as - * the UDP Source Port - */ - if(ntohs(pkt_udp->uh_dport) < baseport || ntohs(pkt_udp->uh_dport) > lastport) - continue; - - /* The Source Port must be that to which we're sending our UDP datagrams */ - if(ntohs(pkt_udp->uh_sport) != dstport) - continue; - - /* The UDP checksum must be valid */ - if(in_chksum(pkt_ipv6, pkt_udp, pkt_end-((unsigned char *)pkt_udp), IPPROTO_UDP) != 0) - continue; - } - - if(testtype==FIXED_ORIGIN){ - if(!is_eq_in6_addr(&(pkt_ipv6->ip6_dst), &(idata.srcaddr))){ - continue; - } - - if(ntest1 >= NSAMPLES) - continue; - - test1[ntest1]= ntohl(pkt_ipv6->ip6_flow) & 0x000fffff; - ntest1++; - } - else{ - if( (ntohl(pkt_ipv6->ip6_dst.s6_addr32[2]) & 0x0000ffff) != addr_sig || \ - (ntohl(pkt_ipv6->ip6_dst.s6_addr32[3]) & 0x0000ffff) != ( (ntohl(pkt_ipv6->ip6_dst.s6_addr32[3])>>16) ^ addr_key)){ - continue; - } - - if(ntest2 >= NSAMPLES) - continue; - - test2[ntest2]= ntohl(pkt_ipv6->ip6_flow) & 0x000fffff; - ntest2++; - } - } - } - } - } - - if(idata.verbose_f > 1){ - printf("Sampled %u Flow Labels from single-origin probes\n", ntest1); - - for(i=0; icaplen; + + if ((pkt_end - pktdata) < (idata.linkhsize + MIN_IPV6_HLEN)) + continue; + + if (pkt_ipv6->ip6_nxt == IPPROTO_ICMPV6 && pkt_icmp6->icmp6_type == ND_NEIGHBOR_SOLICIT) { + pkt_ns = (struct nd_neighbor_solicit *)pkt_icmp6; + + if ((pkt_end - (unsigned char *)pkt_ns) < sizeof(struct nd_neighbor_solicit)) + continue; + /* + If the addresses that we're using are not actually configured on the local system + (i.e., they are "spoofed", we must check whether it is a Neighbor Solicitation for + one of our addresses, and respond with a Neighbor Advertisement. Otherwise, the kernel + will take care of that. + */ + if (testtype == FIXED_ORIGIN) { + if (!localaddr_f && is_eq_in6_addr(&(pkt_ns->nd_ns_target), &(idata.srcaddr))) { + if (send_neighbor_advert(&idata, idata.pfd, pktdata) == -1) { + puts("Error sending Neighbor Advertisement"); + exit(EXIT_FAILURE); + } + } + } + else if (idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK)) { + if ((ntohl(pkt_ns->nd_ns_target.s6_addr32[2]) & 0x0000ffff) != addr_sig || + (ntohl(pkt_ns->nd_ns_target.s6_addr32[3]) & 0x0000ffff) != + ((ntohl(pkt_ns->nd_ns_target.s6_addr32[3]) >> 16) ^ addr_key)) { + continue; + } + + if (send_neighbor_advert(&idata, idata.pfd, pktdata) == -1) { + puts("Error sending Neighbor Advertisement"); + exit(EXIT_FAILURE); + } + } + } + else if (pkt_ipv6->ip6_nxt == protocol) { + + /* Perform TCP-specific validation checks */ + if (protocol == IPPROTO_TCP) { + if ((pkt_end - (unsigned char *)pkt_ipv6) < + (sizeof(struct ip6_hdr) + sizeof(struct tcp_hdr))) + continue; + + pkt_tcp = (struct tcp_hdr *)((unsigned char *)pkt_ipv6 + sizeof(struct ip6_hdr)); + + /* + * The TCP Destination Port must correspond to one of the ports that we have used as + * TCP Source Port + */ + if (ntohs(pkt_tcp->th_dport) < baseport || ntohs(pkt_tcp->th_dport) > lastport) + continue; + + /* The Source Port must be that to which we're sending our TCP segments */ + if (ntohs(pkt_tcp->th_sport) != dstport) + continue; + + /* The TCP Acknowledgement Number must ack our SYN */ + if (ntohl(pkt_tcp->th_ack) != tcpseq + 1) + continue; + + /* We sample Flow ID's only on SYN/ACKs */ + if ((pkt_tcp->th_flags & ~TH_SYN) == 0 || (pkt_tcp->th_flags & TH_ACK) == 0) + continue; + + /* The TCP checksum must be valid */ + if (in_chksum(pkt_ipv6, pkt_tcp, pkt_end - ((unsigned char *)pkt_tcp), IPPROTO_TCP) != 0) + continue; + } + /* Perform UDP-specific validation checks */ + else if (protocol == IPPROTO_UDP) { + if ((pkt_end - (unsigned char *)pkt_ipv6) < + (sizeof(struct ip6_hdr) + sizeof(struct udp_hdr))) + continue; + + pkt_udp = (struct udp_hdr *)((unsigned char *)pkt_ipv6 + sizeof(struct ip6_hdr)); + + /* + * The UDP Destination Port must correspond to one of the ports that we have used as + * the UDP Source Port + */ + if (ntohs(pkt_udp->uh_dport) < baseport || ntohs(pkt_udp->uh_dport) > lastport) + continue; + + /* The Source Port must be that to which we're sending our UDP datagrams */ + if (ntohs(pkt_udp->uh_sport) != dstport) + continue; + + /* The UDP checksum must be valid */ + if (in_chksum(pkt_ipv6, pkt_udp, pkt_end - ((unsigned char *)pkt_udp), IPPROTO_UDP) != 0) + continue; + } + + if (testtype == FIXED_ORIGIN) { + if (!is_eq_in6_addr(&(pkt_ipv6->ip6_dst), &(idata.srcaddr))) { + continue; + } + + if (ntest1 >= NSAMPLES) + continue; + + test1[ntest1] = ntohl(pkt_ipv6->ip6_flow) & 0x000fffff; + ntest1++; + } + else { + if ((ntohl(pkt_ipv6->ip6_dst.s6_addr32[2]) & 0x0000ffff) != addr_sig || + (ntohl(pkt_ipv6->ip6_dst.s6_addr32[3]) & 0x0000ffff) != + ((ntohl(pkt_ipv6->ip6_dst.s6_addr32[3]) >> 16) ^ addr_key)) { + continue; + } + + if (ntest2 >= NSAMPLES) + continue; + + test2[ntest2] = ntohl(pkt_ipv6->ip6_flow) & 0x000fffff; + ntest2++; + } + } + } + } + } + + if (idata.verbose_f > 1) { + printf("Sampled %u Flow Labels from single-origin probes\n", ntest1); + + for (i = 0; i < ntest1; i++) + printf("#%02u: %05x\n", (i + 1), test1[i]); + + printf("\nSampled %u Flow Labels from multi-origin probes\n", ntest2); + + for (i = 0; i < ntest2; i++) + printf("#%02u: %05x\n", (i + 1), test2[i]); + + puts(""); + } + + if (ntest1 < 10 || ntest2 < 10) { + puts("Error: Didn't receive enough response packets"); + exit(EXIT_FAILURE); + } + + if (predict_flow_id(test1, ntest1, test2, ntest2) == -1) { + puts("Error in predict_flow_id()"); + exit(EXIT_FAILURE); + } + + exit(EXIT_SUCCESS); + } + + exit(EXIT_SUCCESS); } - /* * Function: send_fid_probe() * * Send a TCP segment or UDP datagram used for sampling the Flow Label * values sent by the target */ -int send_fid_probe(void){ - struct ether_header *ethernet; - struct dlt_null *dlt_null; - struct ip6_hdr *ipv6; - struct tcp_hdr *tcp; - struct udp_hdr *udp; - unsigned char *ptr; - - ethernet= (struct ether_header *) buffer; - dlt_null= (struct dlt_null *) buffer; - v6buffer = buffer + idata.linkhsize; - ipv6 = (struct ip6_hdr *) v6buffer; - - if(idata.type == DLT_EN10MB){ - ethernet->ether_type = htons(ETHERTYPE_IPV6); - - if( !(idata.flags & IFACE_LOOPBACK)){ - ethernet->src = idata.hsrcaddr; - ethernet->dst = idata.hdstaddr; - } - } - else if(idata.type == DLT_NULL){ - dlt_null->family= PF_INET6; - } -#if defined (__OpenBSD__) - else if(idata.type == DLT_LOOP){ - dlt_null->family= htonl(PF_INET6); - } +int send_fid_probe(void) { + struct ether_header *ethernet; + struct dlt_null *dlt_null; + struct ip6_hdr *ipv6; + struct tcp_hdr *tcp; + struct udp_hdr *udp; + unsigned char *ptr; + + ethernet = (struct ether_header *)buffer; + dlt_null = (struct dlt_null *)buffer; + v6buffer = buffer + idata.linkhsize; + ipv6 = (struct ip6_hdr *)v6buffer; + + if (idata.type == DLT_EN10MB) { + ethernet->ether_type = htons(ETHERTYPE_IPV6); + + if (!(idata.flags & IFACE_LOOPBACK)) { + ethernet->src = idata.hsrcaddr; + ethernet->dst = idata.hdstaddr; + } + } + else if (idata.type == DLT_NULL) { + dlt_null->family = PF_INET6; + } +#if defined(__OpenBSD__) + else if (idata.type == DLT_LOOP) { + dlt_null->family = htonl(PF_INET6); + } #endif - ipv6->ip6_flow=0; - ipv6->ip6_vfc= 0x60; - ipv6->ip6_hlim= hoplimit; - ipv6->ip6_src= idata.srcaddr; - ipv6->ip6_dst= idata.dstaddr; - ipv6->ip6_nxt= protocol; - - if(protocol == IPPROTO_TCP){ - tcp= (struct tcp_hdr *) ( (unsigned char *) ipv6 + sizeof(struct ip6_hdr)); - ptr= (unsigned char *) tcp + sizeof(struct tcp_hdr); - memset(tcp, 0, sizeof(struct tcp_hdr)); - tcp->th_sport= htons(lastport); - tcp->th_dport= htons(dstport); - tcp->th_seq = htonl(tcpseq); - tcp->th_ack= htonl(0); - tcp->th_flags= TH_SYN;; - tcp->th_urp= htons(0); - tcp->th_win= htons(tcpwin); - tcp->th_off= sizeof(struct tcp_hdr) >> 2; - ipv6->ip6_plen= htons(ptr - (unsigned char *) tcp); - tcp->th_sum = in_chksum(ipv6, tcp, (ptr - (unsigned char *) tcp), IPPROTO_TCP); - } - else{ - udp= (struct udp_hdr *) ( (unsigned char *) ipv6 + sizeof(struct ip6_hdr)); - ptr= (unsigned char *) udp + sizeof(struct udp_hdr); - memset(udp, 0, sizeof(struct udp_hdr)); - udp->uh_sport= htons(lastport); - udp->uh_dport= htons(dstport); - ipv6->ip6_plen= htons(ptr - (unsigned char *) udp); - udp->uh_sum = in_chksum(ipv6, udp, (ptr - (unsigned char *) udp), IPPROTO_TCP); - } - - if((nw=pcap_inject(idata.pfd, buffer, ptr - buffer)) == -1){ - if(idata.verbose_f) - printf("pcap_inject(): %s\n", pcap_geterr(idata.pfd)); - - return(-1); - } - - if(nw != (ptr- buffer)){ - if(idata.verbose_f) - printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, (LUI) (ptr-buffer)); - - return(-1); - } - - return(0); + ipv6->ip6_flow = 0; + ipv6->ip6_vfc = 0x60; + ipv6->ip6_hlim = hoplimit; + ipv6->ip6_src = idata.srcaddr; + ipv6->ip6_dst = idata.dstaddr; + ipv6->ip6_nxt = protocol; + + if (protocol == IPPROTO_TCP) { + tcp = (struct tcp_hdr *)((unsigned char *)ipv6 + sizeof(struct ip6_hdr)); + ptr = (unsigned char *)tcp + sizeof(struct tcp_hdr); + memset(tcp, 0, sizeof(struct tcp_hdr)); + tcp->th_sport = htons(lastport); + tcp->th_dport = htons(dstport); + tcp->th_seq = htonl(tcpseq); + tcp->th_ack = htonl(0); + tcp->th_flags = TH_SYN; + ; + tcp->th_urp = htons(0); + tcp->th_win = htons(tcpwin); + tcp->th_off = sizeof(struct tcp_hdr) >> 2; + ipv6->ip6_plen = htons(ptr - (unsigned char *)tcp); + tcp->th_sum = in_chksum(ipv6, tcp, (ptr - (unsigned char *)tcp), IPPROTO_TCP); + } + else { + udp = (struct udp_hdr *)((unsigned char *)ipv6 + sizeof(struct ip6_hdr)); + ptr = (unsigned char *)udp + sizeof(struct udp_hdr); + memset(udp, 0, sizeof(struct udp_hdr)); + udp->uh_sport = htons(lastport); + udp->uh_dport = htons(dstport); + ipv6->ip6_plen = htons(ptr - (unsigned char *)udp); + udp->uh_sum = in_chksum(ipv6, udp, (ptr - (unsigned char *)udp), IPPROTO_TCP); + } + + if ((nw = pcap_inject(idata.pfd, buffer, ptr - buffer)) == -1) { + if (idata.verbose_f) + printf("pcap_inject(): %s\n", pcap_geterr(idata.pfd)); + + return (-1); + } + + if (nw != (ptr - buffer)) { + if (idata.verbose_f) + printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, (LUI)(ptr - buffer)); + + return (-1); + } + + return (0); } - /* * Function: usage() * * Prints the syntax of the flow6 tool */ -void usage(void){ - puts("usage: flow6 -d DST_ADDR [-i INTERFACE] [-S LINK_SRC_ADDR] [-D LINK-DST-ADDR]\n" - " [-s SRC_ADDR[/LEN]] [-A HOP_LIMIT] [-P PROTOCOL] [-p PORT]\n" - " [-W] [-v] [-h]"); +void usage(void) { + puts("usage: flow6 -d DST_ADDR [-i INTERFACE] [-S LINK_SRC_ADDR] [-D LINK-DST-ADDR]\n" + " [-s SRC_ADDR[/LEN]] [-A HOP_LIMIT] [-P PROTOCOL] [-p PORT]\n" + " [-W] [-v] [-h]"); } - /* * Function: print_help() * * Prints help information for the flow6 tool */ -void print_help(void){ - puts(SI6_TOOLKIT); - puts("flow6: Security assessment tool for the IPv6 Flow Label field\n"); - usage(); - - puts("\nOPTIONS:\n" - " --interface, -i Network interface\n" - " --link-src-addr, -S Link-layer Destination Address\n" - " --link-dst-addr, -D Link-layer Source Address\n" - " --src-addr, -s IPv6 Source Address\n" - " --dst-addr, -d IPv6 Destination Address\n" - " --hop-limit, -A IPv6 Hop Limit\n" - " --protocol, -P IPv6 Payload protocol (valid: TCP, UDP)\n" - " --dst-port, -p Transport Protocol Destination Port\n" - " --flow-label-policy, -W Assess the Flow Label generation policy\n" - " --help, -h Print help for the flow6 tool\n" - " --verbose, -v Be verbose\n" - "\n" - "Programmed by Fernando Gont on behalf of SI6 Networks \n" - "Please send any bug reports to \n" - ); +void print_help(void) { + puts(SI6_TOOLKIT); + puts("flow6: Security assessment tool for the IPv6 Flow Label field\n"); + usage(); + + puts("\nOPTIONS:\n" + " --interface, -i Network interface\n" + " --link-src-addr, -S Link-layer Destination Address\n" + " --link-dst-addr, -D Link-layer Source Address\n" + " --src-addr, -s IPv6 Source Address\n" + " --dst-addr, -d IPv6 Destination Address\n" + " --hop-limit, -A IPv6 Hop Limit\n" + " --protocol, -P IPv6 Payload protocol (valid: TCP, UDP)\n" + " --dst-port, -p Transport Protocol Destination Port\n" + " --flow-label-policy, -W Assess the Flow Label generation policy\n" + " --help, -h Print help for the flow6 tool\n" + " --verbose, -v Be verbose\n" + "\n" + "Programmed by Fernando Gont on behalf of SI6 Networks \n" + "Please send any bug reports to \n"); } - - - /* * Function: print_attack_info() * * Prints attack details (when the verbose ("-v") option is specified). */ - -void print_attack_info(void){ - if(ether_ntop(&(idata.hsrcaddr), plinkaddr, sizeof(plinkaddr)) == 0){ - puts("ether_ntop(): Error converting address"); - exit(EXIT_FAILURE); - } - printf("Ethernet Source Address: %s%s\n", plinkaddr, (!idata.hsrcaddr_f)?" (automatically selected)":""); +void print_attack_info(void) { + if (ether_ntop(&(idata.hsrcaddr), plinkaddr, sizeof(plinkaddr)) == 0) { + puts("ether_ntop(): Error converting address"); + exit(EXIT_FAILURE); + } - /* - Ethernet Destination Address only used if a IPv6 Destination Address or an - Ethernet Destination Address were specified. - */ - if(ether_ntop(&(idata.hdstaddr), plinkaddr, sizeof(plinkaddr)) == 0){ - puts("ether_ntop(): Error converting address"); - exit(EXIT_FAILURE); - } + printf("Ethernet Source Address: %s%s\n", plinkaddr, (!idata.hsrcaddr_f) ? " (automatically selected)" : ""); - printf("Ethernet Destination Address: %s%s\n", plinkaddr, (!idata.hdstaddr_f)?" (automatically selected)":""); + /* + Ethernet Destination Address only used if a IPv6 Destination Address or an + Ethernet Destination Address were specified. + */ + if (ether_ntop(&(idata.hdstaddr), plinkaddr, sizeof(plinkaddr)) == 0) { + puts("ether_ntop(): Error converting address"); + exit(EXIT_FAILURE); + } - if(inet_ntop(AF_INET6, &(idata.srcaddr), psrcaddr, sizeof(psrcaddr)) == NULL){ - puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); - exit(EXIT_FAILURE); - } + printf("Ethernet Destination Address: %s%s\n", plinkaddr, (!idata.hdstaddr_f) ? " (automatically selected)" : ""); - if(idata.dstaddr_f){ - printf("IPv6 Source Address: %s%s\n", psrcaddr, ((!idata.srcaddr_f)?" (automatically selected)":"")); - } + if (inet_ntop(AF_INET6, &(idata.srcaddr), psrcaddr, sizeof(psrcaddr)) == NULL) { + puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); + exit(EXIT_FAILURE); + } - if(inet_ntop(AF_INET6, &(idata.dstaddr), pdstaddr, sizeof(pdstaddr)) == NULL){ - puts("inet_ntop(): Error converting IPv6 Destination Address to presentation format"); - exit(EXIT_FAILURE); - } + if (idata.dstaddr_f) { + printf("IPv6 Source Address: %s%s\n", psrcaddr, ((!idata.srcaddr_f) ? " (automatically selected)" : "")); + } - printf("IPv6 Destination Address: %s\n", pdstaddr); + if (inet_ntop(AF_INET6, &(idata.dstaddr), pdstaddr, sizeof(pdstaddr)) == NULL) { + puts("inet_ntop(): Error converting IPv6 Destination Address to presentation format"); + exit(EXIT_FAILURE); + } - printf("IPv6 Hop Limit: %u%s\n", hoplimit, (hoplimit_f)?"":" (randomized)"); - - printf("Protocol: %s\tDestination Port: %u\n", (protocol==IPPROTO_TCP)?"TCP":"UDP", dstport); -} + printf("IPv6 Destination Address: %s\n", pdstaddr); + printf("IPv6 Hop Limit: %u%s\n", hoplimit, (hoplimit_f) ? "" : " (randomized)"); + printf("Protocol: %s\tDestination Port: %u\n", (protocol == IPPROTO_TCP) ? "TCP" : "UDP", dstport); +} /* * Function: predict_flow_id() * * Identifies and prints the Flow Label generation policy -*/ -int predict_flow_id(uint32_t *s1, unsigned int n1, uint32_t *s2, unsigned int n2){ - uint32_t diff1_avg, diff2_avg; - double diff1_sdev, diff2_sdev; - - if(inc_sdev(s1, n1, &diff1_avg, &diff1_sdev) == -1){ - if(idata.verbose_f) - puts("Error while allocating memory in inc_sdev()"); - - return(-1); - } - - if(inc_sdev(s2, n2, &diff2_avg, &diff2_sdev) == -1){ - if(idata.verbose_f) - puts("Error while allocating memory in inc_sdev()"); - - return(-1); - } - - if(diff1_sdev == 0 && diff1_avg == 0){ - if(diff2_sdev == 0 && diff2_avg == 0){ - printf("Flow Label policy: Global (predictable) constant labels, set to %05lu\n", (LUI) s1[0]); - } - else{ - printf("Flow Label policy: Per-destination constant labels with increments of %lu (sdev: %f)\n", \ - (LUI) diff2_avg, diff2_sdev); - } - } - - else if(diff1_sdev <= 100){ - if(diff2_sdev <= 100){ - printf("Flow Label policy: Global (predictable) labels with increments of %lu (sdev: %f)\n", \ - (LUI) diff1_avg, diff1_sdev); - } - else{ - printf("Flow Label policy: Per-destination labels with increments of %lu (sdev: %f)\n", \ - (LUI) diff1_avg, diff1_sdev); - printf(" Global policy: Avg. inc.: %lu, sdev: %f\n", (LUI) diff2_avg, diff2_sdev); - } - } - else{ - puts("Flow Label policy: Randomized labels"); - printf(" Per-destination: Avg. inc.: %lu, sdev: %f\n" - " Global: Avg. inc.: %lu, sdev: %f\n", \ - (LUI) diff1_avg, diff1_sdev, (LUI) diff2_avg, diff2_sdev); - } - - return(0); + */ +int predict_flow_id(uint32_t *s1, unsigned int n1, uint32_t *s2, unsigned int n2) { + uint32_t diff1_avg, diff2_avg; + double diff1_sdev, diff2_sdev; + + if (inc_sdev(s1, n1, &diff1_avg, &diff1_sdev) == -1) { + if (idata.verbose_f) + puts("Error while allocating memory in inc_sdev()"); + + return (-1); + } + + if (inc_sdev(s2, n2, &diff2_avg, &diff2_sdev) == -1) { + if (idata.verbose_f) + puts("Error while allocating memory in inc_sdev()"); + + return (-1); + } + + if (diff1_sdev == 0 && diff1_avg == 0) { + if (diff2_sdev == 0 && diff2_avg == 0) { + printf("Flow Label policy: Global (predictable) constant labels, set to %05lu\n", (LUI)s1[0]); + } + else { + printf("Flow Label policy: Per-destination constant labels with increments of %lu (sdev: %f)\n", + (LUI)diff2_avg, diff2_sdev); + } + } + + else if (diff1_sdev <= 100) { + if (diff2_sdev <= 100) { + printf("Flow Label policy: Global (predictable) labels with increments of %lu (sdev: %f)\n", (LUI)diff1_avg, + diff1_sdev); + } + else { + printf("Flow Label policy: Per-destination labels with increments of %lu (sdev: %f)\n", (LUI)diff1_avg, + diff1_sdev); + printf(" Global policy: Avg. inc.: %lu, sdev: %f\n", (LUI)diff2_avg, diff2_sdev); + } + } + else { + puts("Flow Label policy: Randomized labels"); + printf(" Per-destination: Avg. inc.: %lu, sdev: %f\n" + " Global: Avg. inc.: %lu, sdev: %f\n", + (LUI)diff1_avg, diff1_sdev, (LUI)diff2_avg, diff2_sdev); + } + + return (0); } - - diff --git a/tools/flow6.h b/tools/flow6.h index 11ed611..3bc685a 100644 --- a/tools/flow6.h +++ b/tools/flow6.h @@ -3,7 +3,4 @@ * */ -#define QUERY_TIMEOUT 65 - - - +#define QUERY_TIMEOUT 65 diff --git a/tools/frag6.c b/tools/frag6.c index ad024c1..79742bf 100644 --- a/tools/frag6.c +++ b/tools/frag6.c @@ -19,40 +19,39 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - * + * * Build with: make frag6 - * + * * It requires that the libpcap library be installed on your system. * * Please send any bug reports to Fernando Gont */ - -#include #include -#include #include +#include +#include -#include #include -#include -#include #include -#include #include +#include +#include +#include +#include #include -#include -#include -#include #include -#include #include -#include +#include +#include +#include #include +#include +#include #include -#include -#include +#include +#include #include "frag6.h" #include "ipv6toolkit.h" @@ -61,2326 +60,2320 @@ #define DEBUG /* Function prototypes */ -int predict_frag_id(uint32_t *, unsigned int, uint32_t *, unsigned int); -void print_attack_info(struct iface_data *); -void print_help(void); -void print_icmp6_echo(struct iface_data *, struct pcap_pkthdr *, const u_char *); -void print_icmp6_timed(struct iface_data *, struct pcap_pkthdr *, const u_char *); -void process_icmp6_echo(struct iface_data *, struct pcap_pkthdr *, const u_char *, unsigned char *, unsigned int *); -void process_icmp6_timed(struct iface_data *, struct pcap_pkthdr *, const u_char *, unsigned char *); -int send_fid_probe(struct iface_data *); -int send_fragment(struct iface_data *, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int); -int send_fragment2(struct iface_data *, uint16_t, unsigned int, unsigned int, unsigned int, unsigned int, char *); -int test_frag_pattern(unsigned char *, unsigned int, char *); -void usage(void); -int valid_icmp6_response(struct iface_data *, struct pcap_pkthdr *, const u_char *); -int valid_icmp6_response2(struct iface_data *, struct pcap_pkthdr *, const u_char *, unsigned int); +int predict_frag_id(uint32_t *, unsigned int, uint32_t *, unsigned int); +void print_attack_info(struct iface_data *); +void print_help(void); +void print_icmp6_echo(struct iface_data *, struct pcap_pkthdr *, const u_char *); +void print_icmp6_timed(struct iface_data *, struct pcap_pkthdr *, const u_char *); +void process_icmp6_echo(struct iface_data *, struct pcap_pkthdr *, const u_char *, unsigned char *, unsigned int *); +void process_icmp6_timed(struct iface_data *, struct pcap_pkthdr *, const u_char *, unsigned char *); +int send_fid_probe(struct iface_data *); +int send_fragment(struct iface_data *, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int); +int send_fragment2(struct iface_data *, uint16_t, unsigned int, unsigned int, unsigned int, unsigned int, char *); +int test_frag_pattern(unsigned char *, unsigned int, char *); +void usage(void); +int valid_icmp6_response(struct iface_data *, struct pcap_pkthdr *, const u_char *); +int valid_icmp6_response2(struct iface_data *, struct pcap_pkthdr *, const u_char *, unsigned int); /* Used for router discovery */ -struct iface_data idata; -struct in6_addr randprefix; -unsigned char randpreflen; +struct iface_data idata; +struct in6_addr randprefix; +unsigned char randpreflen; /* Data structures for packets read from the wire */ -struct pcap_pkthdr *pkthdr; -const u_char *pktdata; -unsigned char *pkt_end, *pkt_ptr; -struct ether_header *pkt_ether; -struct ip6_hdr *pkt_ipv6; -struct ip6_frag *pkt_fh; -struct icmp6_hdr *pkt_icmp6; +struct pcap_pkthdr *pkthdr; +const u_char *pktdata; +unsigned char *pkt_end, *pkt_ptr; +struct ether_header *pkt_ether; +struct ip6_hdr *pkt_ipv6; +struct ip6_frag *pkt_fh; +struct icmp6_hdr *pkt_icmp6; struct nd_neighbor_solicit *pkt_ns; -struct in6_addr *pkt_ipv6addr; -unsigned int pktbytes; - - -bpf_u_int32 my_netmask; -bpf_u_int32 my_ip; -struct bpf_program pcap_filter; -char dev[64], errbuf[PCAP_ERRBUF_SIZE]; -unsigned char buffer[65556], buffrh[MIN_IPV6_HLEN + MIN_TCP_HLEN]; -unsigned char *v6buffer, *ptr, *startofprefixes; -char *pref; - -struct ip6_hdr *ipv6; -struct icmp6_hdr *icmp6; - -struct ether_header *ethernet; -struct dlt_null *dlt_null; -struct nd_opt_tlla *tllaopt; - -struct ether_addr linkaddr[MAX_TLLA_OPTION]; -unsigned int nlinkaddr=0, linkaddrs; - -char *lasts, *rpref; -char *charptr; - -int nw; -unsigned long ul_res, ul_val; -unsigned int i, j, startrand; -unsigned int skip; -unsigned int frags, nfrags, nsleep; -uint16_t mask, ip6length; -uint8_t hoplimit; - -char plinkaddr[ETHER_ADDR_PLEN]; -char psrcaddr[INET6_ADDRSTRLEN], pdstaddr[INET6_ADDRSTRLEN], pv6addr[INET6_ADDRSTRLEN]; -unsigned char verbose_f=0; -unsigned char floodf_f=0; -unsigned char loop_f=0, sleep_f=0, localaddr_f=0, tstamp_f=1, pod_f=0, gotresp_f= FALSE; -unsigned char srcprefix_f=0, hoplimit_f=0, ip6length_f=0, icmp6psize_f=0; -unsigned char fsize_f=0, forder_f=0, foffset_f=0, fid_f=0, fragp_f=0, fragidp_f=0, resp_f=1; - -uint32_t fsize, foffset, fid, id; -unsigned int forder, overlap, minfragsize; +struct in6_addr *pkt_ipv6addr; +unsigned int pktbytes; + +bpf_u_int32 my_netmask; +bpf_u_int32 my_ip; +struct bpf_program pcap_filter; +char dev[64], errbuf[PCAP_ERRBUF_SIZE]; +unsigned char buffer[65556], buffrh[MIN_IPV6_HLEN + MIN_TCP_HLEN]; +unsigned char *v6buffer, *ptr, *startofprefixes; +char *pref; + +struct ip6_hdr *ipv6; +struct icmp6_hdr *icmp6; + +struct ether_header *ethernet; +struct dlt_null *dlt_null; +struct nd_opt_tlla *tllaopt; + +struct ether_addr linkaddr[MAX_TLLA_OPTION]; +unsigned int nlinkaddr = 0, linkaddrs; + +char *lasts, *rpref; +char *charptr; + +int nw; +unsigned long ul_res, ul_val; +unsigned int i, j, startrand; +unsigned int skip; +unsigned int frags, nfrags, nsleep; +uint16_t mask, ip6length; +uint8_t hoplimit; + +char plinkaddr[ETHER_ADDR_PLEN]; +char psrcaddr[INET6_ADDRSTRLEN], pdstaddr[INET6_ADDRSTRLEN], pv6addr[INET6_ADDRSTRLEN]; +unsigned char verbose_f = 0; +unsigned char floodf_f = 0; +unsigned char loop_f = 0, sleep_f = 0, localaddr_f = 0, tstamp_f = 1, pod_f = 0, gotresp_f = FALSE; +unsigned char srcprefix_f = 0, hoplimit_f = 0, ip6length_f = 0, icmp6psize_f = 0; +unsigned char fsize_f = 0, forder_f = 0, foffset_f = 0, fid_f = 0, fragp_f = 0, fragidp_f = 0, resp_f = 1; + +uint32_t fsize, foffset, fid, id; +unsigned int forder, overlap, minfragsize; /* Support for Extension Headers */ -unsigned int dstopthdrs, dstoptuhdrs, hbhopthdrs; -char hbhopthdr_f=0, dstoptuhdr_f=0, dstopthdr_f=0; -unsigned char *dstopthdr[MAX_DST_OPT_HDR], *dstoptuhdr[MAX_DST_OPT_U_HDR]; -unsigned char *hbhopthdr[MAX_HBH_OPT_HDR]; -unsigned int dstopthdrlen[MAX_DST_OPT_HDR], dstoptuhdrlen[MAX_DST_OPT_U_HDR]; -unsigned int hbhopthdrlen[MAX_HBH_OPT_HDR], m, pad; +unsigned int dstopthdrs, dstoptuhdrs, hbhopthdrs; +char hbhopthdr_f = 0, dstoptuhdr_f = 0, dstopthdr_f = 0; +unsigned char *dstopthdr[MAX_DST_OPT_HDR], *dstoptuhdr[MAX_DST_OPT_U_HDR]; +unsigned char *hbhopthdr[MAX_HBH_OPT_HDR]; +unsigned int dstopthdrlen[MAX_DST_OPT_HDR], dstoptuhdrlen[MAX_DST_OPT_U_HDR]; +unsigned int hbhopthdrlen[MAX_HBH_OPT_HDR], m, pad; -struct ip6_frag *fh; -struct ip6_hdr *fipv6; - -unsigned char *fragpart, *ptrend, *ptrhdr, *ptrhdrend; -unsigned int hdrlen, ndstopthdr=0, nhbhopthdr=0, ndstoptuhdr=0; -unsigned int nfrags, fragsize; -unsigned char *prev_nh, *startoffragment; +struct ip6_frag *fh; +struct ip6_hdr *fipv6; +unsigned char *fragpart, *ptrend, *ptrhdr, *ptrhdrend; +unsigned int hdrlen, ndstopthdr = 0, nhbhopthdr = 0, ndstoptuhdr = 0; +unsigned int nfrags, fragsize; +unsigned char *prev_nh, *startoffragment; /* Basic data blocks used for detecting the fragment reassembly policy. They contain the same words * in different order, thus resulting in the same checksum */ -#define FRAG_BLOCK_SIZE 8 -char block1[8]={'a', 'a', 'b', 'b', 'c', 'c', 'd', 'd'}; -char block2[8]={'b', 'b', 'a', 'a', 'c', 'c', 'd', 'd'}; -char block3[8]={'c', 'c', 'a', 'a', 'b', 'b', 'd', 'd'}; -char block4[8]={'d', 'd', 'a', 'a', 'b', 'b', 'c', 'c'}; -char block5[8]={'d', 'd', 'c', 'c', 'b', 'b', 'a', 'a'}; -char block6[8]={'c', 'c', 'd', 'd', 'b', 'b', 'a', 'a'}; -char block7[8]={'b', 'b', 'd', 'd', 'c', 'c', 'a', 'a'}; -char block8[8]={'a', 'a', 'd', 'd', 'c', 'c', 'b', 'b'}; - +#define FRAG_BLOCK_SIZE 8 +char block1[8] = {'a', 'a', 'b', 'b', 'c', 'c', 'd', 'd'}; +char block2[8] = {'b', 'b', 'a', 'a', 'c', 'c', 'd', 'd'}; +char block3[8] = {'c', 'c', 'a', 'a', 'b', 'b', 'd', 'd'}; +char block4[8] = {'d', 'd', 'a', 'a', 'b', 'b', 'c', 'c'}; +char block5[8] = {'d', 'd', 'c', 'c', 'b', 'b', 'a', 'a'}; +char block6[8] = {'c', 'c', 'd', 'd', 'b', 'b', 'a', 'a'}; +char block7[8] = {'b', 'b', 'd', 'd', 'c', 'c', 'a', 'a'}; +char block8[8] = {'a', 'a', 'd', 'd', 'c', 'c', 'b', 'b'}; /* For the sampling of Fragment Identification values */ -uint16_t addr_sig, addr_key; -uint32_t icmp6_sig; - -int main(int argc, char **argv){ - extern char *optarg; - char *endptr; /* Used by strtoul() */ - fd_set sset, rset; - struct timeval timeout; - struct target_ipv6 targetipv6; - int r, sel; - time_t curtime, start, lastfrag=0, lastfrag1=0, lastfrag2=0; - time_t lastfrag3=0, lastfrag4=0, lastfrag5=0; - struct timeval curtimet, startt, lastfrag1t; - unsigned int responses=0, maxsizedchunk; - - /* Array for storing the Fragment reassembly policy test results */ - unsigned char test[5]; - - /* Arrays for storing the Fragment ID samples */ - uint32_t test1[NSAMPLES], test2[NSAMPLES]; - unsigned int ntest1=0, ntest2=0; - unsigned char testtype; - - static struct option longopts[] = { - {"interface", required_argument, 0, 'i'}, - {"link-src-addr", required_argument, 0, 'S'}, - {"link-dst-addr", required_argument, 0, 'D'}, - {"src-addr", required_argument, 0, 's'}, - {"dst-addr", required_argument, 0, 'd'}, - {"hop-limit", required_argument, 0, 'A'}, - {"dst-opt-hdr", required_argument, 0, 'u'}, - {"dst-opt-u-hdr", required_argument, 0, 'U'}, - {"hbh-opt-hdr", required_argument, 0, 'H'}, - {"frag-size", required_argument, 0, 'P'}, - {"frag-type", required_argument, 0, 'O'}, - {"frag-offset", required_argument, 0, 'o'}, - {"frag-id", required_argument, 0, 'I'}, - {"no-timestamp", no_argument, 0, 'T'}, - {"no-responses", no_argument, 0, 'n'}, - {"frag-reass-policy", no_argument, 0, 'p'}, - {"frag-id-policy", no_argument, 0, 'W'}, - {"pod-attack", no_argument, 0, 'X'}, - {"flood-frags", required_argument, 0, 'F'}, - {"loop", no_argument, 0, 'l'}, - {"sleep", required_argument, 0, 'z'}, - {"verbose", no_argument, 0, 'v'}, - {"help", no_argument, 0, 'h'}, - {0, 0, 0, 0 } - }; - - const char shortopts[]= "i:S:D:s:d:A:u:U:H:P:O:o:I:TnpWXF:lz:vh"; - - char option; - - if(argc<=1){ - usage(); - exit(EXIT_FAILURE); - } - - - srandom(time(NULL)); - hoplimit=64+random()%180; - init_iface_data(&idata); - - while((r=getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { - option= r; - - switch(option) { - case 'i': /* Interface */ - strncpy(idata.iface, optarg, IFACE_LENGTH); - idata.iface[IFACE_LENGTH-1]=0; - idata.ifindex= if_nametoindex(idata.iface); - idata.iface_f=TRUE; - break; - - case 's': /* IPv6 Source Address */ - if((charptr = strtok_r(optarg, "/", &lasts)) == NULL){ - puts("Error in Source Address"); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, charptr, &(idata.srcaddr)) <= 0){ - puts("inet_pton(): Source Address not valid"); - exit(EXIT_FAILURE); - } - - idata.srcaddr_f = 1; - - if((charptr = strtok_r(NULL, " ", &lasts)) != NULL){ - idata.srcpreflen = atoi(charptr); - - if(idata.srcpreflen>128){ - puts("Prefix length error in IPv6 Source Address"); - exit(EXIT_FAILURE); - } - - sanitize_ipv6_prefix(&(idata.srcaddr), idata.srcpreflen); - idata.srcprefix_f=1; - } - - break; - - case 'd': /* IPv6 Destination Address */ - strncpy( targetipv6.name, optarg, NI_MAXHOST); - targetipv6.name[NI_MAXHOST-1]= 0; - targetipv6.flags= AI_CANONNAME; - - if( (r=get_ipv6_target(&targetipv6)) != 0){ - - if(r < 0){ - printf("Unknown Destination: %s\n", gai_strerror(targetipv6.res)); - } - else{ - puts("Unknown Destination: No IPv6 address found for specified destination"); - } - - exit(EXIT_FAILURE); - } - - idata.dstaddr= targetipv6.ip6; - idata.dstaddr_f = 1; - break; - - case 'A': /* Hop Limit */ - hoplimit= atoi(optarg); - hoplimit_f=1; - break; - - case 'u': /* Destinations Options Header */ - if(ndstopthdr >= MAX_DST_OPT_HDR){ - puts("Too many Destination Options Headers"); - exit(EXIT_FAILURE); - } - - hdrlen= atoi(optarg); - - if(hdrlen < 8){ - puts("Bad length in Destination Options Header"); - exit(EXIT_FAILURE); - } - - hdrlen = ((hdrlen+7)/8) * 8; - dstopthdrlen[ndstopthdr]= hdrlen; - - if( (dstopthdr[ndstopthdr]= malloc(hdrlen)) == NULL){ - puts("Not enough memory for Destination Options Header"); - exit(EXIT_FAILURE); - } - - ptrhdr= dstopthdr[ndstopthdr] + 2; - ptrhdrend= dstopthdr[ndstopthdr] + hdrlen; - - while( ptrhdr < ptrhdrend){ - - if( (ptrhdrend-ptrhdr)>257) - pad= 257; - else - pad= ptrhdrend-ptrhdr; - - if(!insert_pad_opt(ptrhdr, ptrhdrend, pad)){ - puts("Destination Options Header Too Big"); - exit(EXIT_FAILURE); - } - - ptrhdr= ptrhdr + pad; - } - - *(dstopthdr[ndstopthdr]+1)= (hdrlen/8)-1; - ndstopthdr++; - dstopthdr_f=1; - break; - - case 'U': /* Destination Options Header (Unfragmentable Part) */ - if(ndstoptuhdr >= MAX_DST_OPT_U_HDR){ - puts("Too many Destination Options Headers (Unfragmentable Part)"); - exit(EXIT_FAILURE); - } - - hdrlen= atoi(optarg); - - if(hdrlen < 8){ - puts("Bad length in Destination Options Header (Unfragmentable Part)"); - exit(EXIT_FAILURE); - } - - hdrlen = ((hdrlen+7)/8) * 8; - dstoptuhdrlen[ndstoptuhdr]= hdrlen; - - if( (dstoptuhdr[ndstoptuhdr]= malloc(hdrlen)) == NULL){ - puts("Not enough memory for Destination Options Header (Unfragmentable Part)"); - exit(EXIT_FAILURE); - } - - ptrhdr= dstoptuhdr[ndstoptuhdr]+2; - ptrhdrend= dstoptuhdr[ndstoptuhdr] + hdrlen; - - while( ptrhdr < ptrhdrend){ - - if( (ptrhdrend-ptrhdr)>257) - pad= 257; - else - pad= ptrhdrend-ptrhdr; - - if(!insert_pad_opt(ptrhdr, ptrhdrend, pad)){ - puts("Destination Options Header (Unfragmentable Part) Too Big"); - exit(EXIT_FAILURE); - } - - ptrhdr = ptrhdr + pad; - } - - *(dstoptuhdr[ndstoptuhdr]+1)= (hdrlen/8) - 1; - ndstoptuhdr++; - dstoptuhdr_f=1; - break; - - case 'H': /* Hop-by-Hop Options Header */ - if(nhbhopthdr >= MAX_HBH_OPT_HDR){ - puts("Too many Hop-by-Hop Options Headers"); - exit(EXIT_FAILURE); - } - - hdrlen= atoi(optarg); - - if(hdrlen < 8){ - puts("Bad length in Hop-by-Hop Options Header"); - exit(EXIT_FAILURE); - } - - hdrlen = ((hdrlen+7)/8) * 8; - hbhopthdrlen[nhbhopthdr]= hdrlen; - - if( (hbhopthdr[nhbhopthdr]= malloc(hdrlen)) == NULL){ - puts("Not enough memory for Hop-by-Hop Options Header"); - exit(EXIT_FAILURE); - } - - ptrhdr= hbhopthdr[nhbhopthdr] + 2; - ptrhdrend= hbhopthdr[nhbhopthdr] + hdrlen; - - - while( ptrhdr < ptrhdrend){ - - if( (ptrhdrend-ptrhdr)>257) - pad= 257; - else - pad= ptrhdrend-ptrhdr; - - if(!insert_pad_opt(ptrhdr, ptrhdrend, pad)){ - puts("Hop-by-Hop Options Header Too Big"); - exit(EXIT_FAILURE); - } - - ptrhdr = ptrhdr + pad; - } - - *(hbhopthdr[nhbhopthdr]+1)= (hdrlen/8) - 1; - nhbhopthdr++; - hbhopthdr_f=1; - break; - - case 'S': /* Source Ethernet address */ - if(ether_pton(optarg, &(idata.hsrcaddr), sizeof(idata.hsrcaddr)) == 0){ - puts("Error in Source link-layer address."); - exit(EXIT_FAILURE); - } - - idata.hsrcaddr_f = 1; - break; - - case 'D': /* Destination Ethernet Address */ - if(ether_pton(optarg, &(idata.hdstaddr), sizeof(idata.hdstaddr)) == 0){ - puts("Error in Source link-layer address."); - exit(EXIT_FAILURE); - } - - idata.hdstaddr_f = 1; - break; - - case 'P': /* Fragment Size*/ - fsize= atoi(optarg); - fsize_f= 1; - break; - - case 'O': /* Fragment Type */ - if(strncmp(optarg, "first", MAX_STRING_SIZE) == 0){ - forder= FIRST_FRAGMENT; - forder_f=1; - } - else if(strncmp(optarg, "last", MAX_STRING_SIZE) == 0){ - forder= LAST_FRAGMENT; - forder_f=1; - } - else if(strncmp(optarg, "middle", MAX_STRING_SIZE) == 0){ - forder= MIDDLE_FRAGMENT; - forder_f=1; - } - else if(strncmp(optarg, "atomic", MAX_STRING_SIZE) == 0){ - forder= ATOMIC_FRAGMENT; - forder_f=1; - } - else{ - puts("Unknown fragment order (valid order types: 'first', 'last', 'middle')"); - exit(EXIT_FAILURE); - } - - break; - - case 'o': /* Fragment Offset */ - if((ul_res = strtoul(optarg, &endptr, 0)) == ULONG_MAX){ - perror("Error in 'Fragment Offset' parameter"); - exit(EXIT_FAILURE); - } - - if(endptr != optarg){ - foffset = ul_res; - foffset_f=1; - } - - break; - - case 'I': /* Fragment Identification */ - if((ul_res = strtoul(optarg, &endptr, 0)) == ULONG_MAX){ - perror("Error in 'Fragment Identification' parameter"); - exit(EXIT_FAILURE); - } - - if(endptr != optarg){ - fid = ul_res; - fid_f=1; - } - - break; - - case 'T': /* Do not include timestamp in fragment */ - tstamp_f=0; - break; - - case 'n': /* Do not show responses */ - resp_f=0; - break; - - case 'p': /* Assess the fragment reassembly policy of the target */ - fragp_f= 1; - break; - - case 'W': /* Assess the fragment id generation policy of the target */ - fragidp_f= 1; - break; - - case 'F': /* Flood target with fragments */ - nfrags= atoi(optarg); - if(nfrags == 0){ - puts("Invalid number of fragments in option -F"); - exit(EXIT_FAILURE); - } - - floodf_f= 1; - break; - - case 'X': - pod_f=1; - break; - - case 'l': /* "Loop mode */ - loop_f = 1; - break; - - case 'z': /* Sleep option */ - nsleep=atoi(optarg); - if(nsleep==0){ - puts("Invalid number of seconds in '-z' option"); - exit(EXIT_FAILURE); - } - - sleep_f=1; - break; - - case 'v': /* Be verbose */ - idata.verbose_f++; - break; - - case 'h': /* Help */ - print_help(); - - exit(EXIT_FAILURE); - break; - - default: - usage(); - exit(EXIT_FAILURE); - break; - - } /* switch */ - } /* while(getopt) */ - - verbose_f= idata.verbose_f; - - if(geteuid()) { - puts("frag6 needs root privileges to run."); - exit(EXIT_FAILURE); - } - - if(!idata.iface_f){ - if(idata.dstaddr_f && IN6_IS_ADDR_LINKLOCAL(&(idata.dstaddr))){ - puts("Must specify a network interface for link-local destinations"); - exit(EXIT_FAILURE); - } - } - - if(load_dst_and_pcap(&idata, LOAD_SRC_NXT_HOP) == FAILURE){ - puts("Error while learning Source Address and Next Hop"); - exit(EXIT_FAILURE); - } - - release_privileges(); - - if((idata.ip6_local_flag && idata.ip6_global_flag) && !idata.srcaddr_f) - localaddr_f=1; - - if(!sleep_f) - nsleep=QUERY_TIMEOUT; - - - idata.max_packet_size = MAX_IPV6_PAYLOAD + MIN_IPV6_HLEN; - - if(idata.verbose_f){ - print_attack_info(&idata); - } - - if(!idata.dstaddr_f){ - puts("Error: Nothing to send! (Destination Address left unspecified)"); - exit(EXIT_FAILURE); - } - - if(!floodf_f) - nfrags=1; - - if(!forder_f) - forder= MIDDLE_FRAGMENT; - - /* Assess the Fragment Reassembly policy */ - if(fragp_f){ - puts("Identifying fragment reassembly policy of the target node...."); - - /* - Set filter for receiving Neighbor Solicitations, ICMPv6 Echo Responses, and ICMPv6 Time Exceeded - */ - if(pcap_compile(idata.pfd, &pcap_filter, PCAP_ICMPV6_NSECHOEXCEEDED_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1){ - printf("pcap_compile(): %s\n", pcap_geterr(idata.pfd)); - exit(EXIT_FAILURE); - } - - if(pcap_setfilter(idata.pfd, &pcap_filter) == -1){ - printf("pcap_setfilter(): %s\n", pcap_geterr(idata.pfd)); - exit(EXIT_FAILURE); - } - - pcap_freecode(&pcap_filter); - - /* Initialize the table of results for the different tests */ - for(i=0; i<5; i++) - test[i]= TIMED_OUT; - - /* - These two variables select the fragment "overlap" size for the tests, and the minimum fragment size. - They are currently hardcoded, but will be configurable in future revisions of the tool. - */ - overlap=8; - minfragsize= 8*10; - - /* - Since the current version of the tool does not reassemble response packets, we need to prevent - response packets from employing fragmentation. The maximum-sized packets that we send is composed - of a 4*minfragsize payload plus IPv6 and ICMPv6 headers -- hence the check bellow. - */ - if(minfragsize > ((idata.mtu - sizeof(struct ip6_hdr) - sizeof(struct icmp6_hdr))/4)){ - puts("Error: minimum fragment size is too large"); - exit(EXIT_FAILURE); - } - - if(overlap < 8 || (overlap%8) != 0 || overlap >= minfragsize){ - puts("Error: Incorrect 'overlap' value"); - exit(EXIT_FAILURE); - } - - FD_ZERO(&sset); - FD_SET(idata.fd, &sset); - start= time(NULL); - - /* - This "schedules" the sending of probes for different types of packets. At most two probes - will be sent for each packet type. Probe #1 will be sent now, and resent after QUERY_TIMEOUT/2 - seconds. Probe #2 will be sent in 1 second, and resent after QUERY_TIMEOUT/2 seconds... etc. - This means that starting now, we send one probe for each packet type, one per second (to avoid - congesting the network). And we resend the probes in after QUERY_TIMEOUT/2 seconds (hence we - have QUERY_TIMEOUT/2 to wait for the responses of such probes). - */ - lastfrag1= start - QUERY_TIMEOUT/2; - lastfrag2= start - QUERY_TIMEOUT/2 + 1; - lastfrag3= start - QUERY_TIMEOUT/2 + 2; - lastfrag4= start - QUERY_TIMEOUT/2 + 3; - lastfrag5= start - QUERY_TIMEOUT/2 + 4; - responses=0; - - while(1){ - curtime=time(NULL); - - /* - If we have already the timeout value, or already have results for each of the five tests, - exit the loop - */ - if((curtime - start) >= QUERY_TIMEOUT || responses >= 5){ - break; - } - - if((curtime - lastfrag1) >= QUERY_TIMEOUT/2 && (test[0]== TIMED_OUT || test[0]==TIME_EXCEEDED)){ - if(idata.verbose_f) - puts("Sending Fragments for Test #1...."); - - id= random(); - - if(send_fragment2(&idata, sizeof(struct icmp6_hdr)+minfragsize*2-overlap, id, 0, minfragsize, \ - FIRST_FRAGMENT, block1) == -1){ - } - - if(send_fragment2(&idata, 0, id, sizeof(struct icmp6_hdr)+minfragsize-overlap, minfragsize, \ - LAST_FRAGMENT, block6) == -1){ - } - - lastfrag1=curtime; - continue; - } - - if((curtime - lastfrag2) >= QUERY_TIMEOUT/2 && (test[1]== TIMED_OUT || test[1]==TIME_EXCEEDED)){ - if(idata.verbose_f) - puts("Sending Fragments for Test #2...."); - - id= random(); - - if(send_fragment2(&idata, sizeof(struct icmp6_hdr)+minfragsize * 3-overlap, id, 0, minfragsize, \ - FIRST_FRAGMENT, block2) == -1){ - } - - if(send_fragment2(&idata, 0, id, sizeof(struct icmp6_hdr)+minfragsize * 2-overlap, minfragsize, \ - LAST_FRAGMENT, block6) == -1){ - } - - if(send_fragment2(&idata, 0, id, sizeof(struct icmp6_hdr)+minfragsize-overlap, minfragsize, \ - MIDDLE_FRAGMENT, block7) == -1){ - } - - lastfrag2=curtime; - continue; - } - - if((curtime - lastfrag3) >= QUERY_TIMEOUT/2 && (test[2]== TIMED_OUT || test[2]==TIME_EXCEEDED)){ - if(idata.verbose_f) - puts("Sending Fragments for Test #3...."); - - id= random(); - - if(send_fragment2(&idata, sizeof(struct icmp6_hdr)+minfragsize * 3-overlap, id, 0, minfragsize, \ - FIRST_FRAGMENT, block3) == -1){ - } - - if(send_fragment2(&idata, 0, id, sizeof(struct icmp6_hdr)+minfragsize * 2-overlap, minfragsize, \ - LAST_FRAGMENT, block6) == -1){ - } - - if(send_fragment2(&idata, 0, id, sizeof(struct icmp6_hdr)+minfragsize, minfragsize, MIDDLE_FRAGMENT, \ - block7) == -1){ - } - - lastfrag3=curtime; - continue; - } - - - if((curtime - lastfrag4) >= QUERY_TIMEOUT/2 && (test[3]== TIMED_OUT || test[3]==TIME_EXCEEDED)){ - if(idata.verbose_f) - puts("Sending Fragments for Test #4...."); +uint16_t addr_sig, addr_key; +uint32_t icmp6_sig; + +int main(int argc, char **argv) { + extern char *optarg; + char *endptr; /* Used by strtoul() */ + fd_set sset, rset; + struct timeval timeout; + struct target_ipv6 targetipv6; + int r, sel; + time_t curtime, start, lastfrag = 0, lastfrag1 = 0, lastfrag2 = 0; + time_t lastfrag3 = 0, lastfrag4 = 0, lastfrag5 = 0; + struct timeval curtimet, startt, lastfrag1t; + unsigned int responses = 0, maxsizedchunk; + + /* Array for storing the Fragment reassembly policy test results */ + unsigned char test[5]; + + /* Arrays for storing the Fragment ID samples */ + uint32_t test1[NSAMPLES], test2[NSAMPLES]; + unsigned int ntest1 = 0, ntest2 = 0; + unsigned char testtype; + + static struct option longopts[] = {{"interface", required_argument, 0, 'i'}, + {"link-src-addr", required_argument, 0, 'S'}, + {"link-dst-addr", required_argument, 0, 'D'}, + {"src-addr", required_argument, 0, 's'}, + {"dst-addr", required_argument, 0, 'd'}, + {"hop-limit", required_argument, 0, 'A'}, + {"dst-opt-hdr", required_argument, 0, 'u'}, + {"dst-opt-u-hdr", required_argument, 0, 'U'}, + {"hbh-opt-hdr", required_argument, 0, 'H'}, + {"frag-size", required_argument, 0, 'P'}, + {"frag-type", required_argument, 0, 'O'}, + {"frag-offset", required_argument, 0, 'o'}, + {"frag-id", required_argument, 0, 'I'}, + {"no-timestamp", no_argument, 0, 'T'}, + {"no-responses", no_argument, 0, 'n'}, + {"frag-reass-policy", no_argument, 0, 'p'}, + {"frag-id-policy", no_argument, 0, 'W'}, + {"pod-attack", no_argument, 0, 'X'}, + {"flood-frags", required_argument, 0, 'F'}, + {"loop", no_argument, 0, 'l'}, + {"sleep", required_argument, 0, 'z'}, + {"verbose", no_argument, 0, 'v'}, + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0}}; + + const char shortopts[] = "i:S:D:s:d:A:u:U:H:P:O:o:I:TnpWXF:lz:vh"; + + char option; + + if (argc <= 1) { + usage(); + exit(EXIT_FAILURE); + } + + srandom(time(NULL)); + hoplimit = 64 + random() % 180; + init_iface_data(&idata); + + while ((r = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { + option = r; + + switch (option) { + case 'i': /* Interface */ + strncpy(idata.iface, optarg, IFACE_LENGTH); + idata.iface[IFACE_LENGTH - 1] = 0; + idata.ifindex = if_nametoindex(idata.iface); + idata.iface_f = TRUE; + break; + + case 's': /* IPv6 Source Address */ + if ((charptr = strtok_r(optarg, "/", &lasts)) == NULL) { + puts("Error in Source Address"); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, charptr, &(idata.srcaddr)) <= 0) { + puts("inet_pton(): Source Address not valid"); + exit(EXIT_FAILURE); + } + + idata.srcaddr_f = 1; + + if ((charptr = strtok_r(NULL, " ", &lasts)) != NULL) { + idata.srcpreflen = atoi(charptr); + + if (idata.srcpreflen > 128) { + puts("Prefix length error in IPv6 Source Address"); + exit(EXIT_FAILURE); + } + + sanitize_ipv6_prefix(&(idata.srcaddr), idata.srcpreflen); + idata.srcprefix_f = 1; + } + + break; + + case 'd': /* IPv6 Destination Address */ + strncpy(targetipv6.name, optarg, NI_MAXHOST); + targetipv6.name[NI_MAXHOST - 1] = 0; + targetipv6.flags = AI_CANONNAME; + + if ((r = get_ipv6_target(&targetipv6)) != 0) { + + if (r < 0) { + printf("Unknown Destination: %s\n", gai_strerror(targetipv6.res)); + } + else { + puts("Unknown Destination: No IPv6 address found for specified destination"); + } + + exit(EXIT_FAILURE); + } + + idata.dstaddr = targetipv6.ip6; + idata.dstaddr_f = 1; + break; + + case 'A': /* Hop Limit */ + hoplimit = atoi(optarg); + hoplimit_f = 1; + break; + + case 'u': /* Destinations Options Header */ + if (ndstopthdr >= MAX_DST_OPT_HDR) { + puts("Too many Destination Options Headers"); + exit(EXIT_FAILURE); + } + + hdrlen = atoi(optarg); + + if (hdrlen < 8) { + puts("Bad length in Destination Options Header"); + exit(EXIT_FAILURE); + } + + hdrlen = ((hdrlen + 7) / 8) * 8; + dstopthdrlen[ndstopthdr] = hdrlen; + + if ((dstopthdr[ndstopthdr] = malloc(hdrlen)) == NULL) { + puts("Not enough memory for Destination Options Header"); + exit(EXIT_FAILURE); + } - id= random(); + ptrhdr = dstopthdr[ndstopthdr] + 2; + ptrhdrend = dstopthdr[ndstopthdr] + hdrlen; - if(send_fragment2(&idata, sizeof(struct icmp6_hdr)+minfragsize *4, id, 0, minfragsize, FIRST_FRAGMENT, \ - block4) == -1){ - } + while (ptrhdr < ptrhdrend) { + + if ((ptrhdrend - ptrhdr) > 257) + pad = 257; + else + pad = ptrhdrend - ptrhdr; + + if (!insert_pad_opt(ptrhdr, ptrhdrend, pad)) { + puts("Destination Options Header Too Big"); + exit(EXIT_FAILURE); + } + + ptrhdr = ptrhdr + pad; + } + + *(dstopthdr[ndstopthdr] + 1) = (hdrlen / 8) - 1; + ndstopthdr++; + dstopthdr_f = 1; + break; + + case 'U': /* Destination Options Header (Unfragmentable Part) */ + if (ndstoptuhdr >= MAX_DST_OPT_U_HDR) { + puts("Too many Destination Options Headers (Unfragmentable Part)"); + exit(EXIT_FAILURE); + } - if(send_fragment2(&idata, 0, id, sizeof(struct icmp6_hdr)+minfragsize * 2, minfragsize, MIDDLE_FRAGMENT, \ - block6) == -1){ - } + hdrlen = atoi(optarg); - if(send_fragment2(&idata, 0, id, sizeof(struct icmp6_hdr)+minfragsize, minfragsize *3, LAST_FRAGMENT, \ - block7) == -1){ - } + if (hdrlen < 8) { + puts("Bad length in Destination Options Header (Unfragmentable Part)"); + exit(EXIT_FAILURE); + } - lastfrag4=curtime; - continue; - } + hdrlen = ((hdrlen + 7) / 8) * 8; + dstoptuhdrlen[ndstoptuhdr] = hdrlen; + + if ((dstoptuhdr[ndstoptuhdr] = malloc(hdrlen)) == NULL) { + puts("Not enough memory for Destination Options Header (Unfragmentable Part)"); + exit(EXIT_FAILURE); + } + + ptrhdr = dstoptuhdr[ndstoptuhdr] + 2; + ptrhdrend = dstoptuhdr[ndstoptuhdr] + hdrlen; + + while (ptrhdr < ptrhdrend) { + + if ((ptrhdrend - ptrhdr) > 257) + pad = 257; + else + pad = ptrhdrend - ptrhdr; + + if (!insert_pad_opt(ptrhdr, ptrhdrend, pad)) { + puts("Destination Options Header (Unfragmentable Part) Too Big"); + exit(EXIT_FAILURE); + } + + ptrhdr = ptrhdr + pad; + } + + *(dstoptuhdr[ndstoptuhdr] + 1) = (hdrlen / 8) - 1; + ndstoptuhdr++; + dstoptuhdr_f = 1; + break; + + case 'H': /* Hop-by-Hop Options Header */ + if (nhbhopthdr >= MAX_HBH_OPT_HDR) { + puts("Too many Hop-by-Hop Options Headers"); + exit(EXIT_FAILURE); + } + + hdrlen = atoi(optarg); + + if (hdrlen < 8) { + puts("Bad length in Hop-by-Hop Options Header"); + exit(EXIT_FAILURE); + } + + hdrlen = ((hdrlen + 7) / 8) * 8; + hbhopthdrlen[nhbhopthdr] = hdrlen; + + if ((hbhopthdr[nhbhopthdr] = malloc(hdrlen)) == NULL) { + puts("Not enough memory for Hop-by-Hop Options Header"); + exit(EXIT_FAILURE); + } + + ptrhdr = hbhopthdr[nhbhopthdr] + 2; + ptrhdrend = hbhopthdr[nhbhopthdr] + hdrlen; + + while (ptrhdr < ptrhdrend) { + + if ((ptrhdrend - ptrhdr) > 257) + pad = 257; + else + pad = ptrhdrend - ptrhdr; + + if (!insert_pad_opt(ptrhdr, ptrhdrend, pad)) { + puts("Hop-by-Hop Options Header Too Big"); + exit(EXIT_FAILURE); + } + + ptrhdr = ptrhdr + pad; + } + + *(hbhopthdr[nhbhopthdr] + 1) = (hdrlen / 8) - 1; + nhbhopthdr++; + hbhopthdr_f = 1; + break; + + case 'S': /* Source Ethernet address */ + if (ether_pton(optarg, &(idata.hsrcaddr), sizeof(idata.hsrcaddr)) == 0) { + puts("Error in Source link-layer address."); + exit(EXIT_FAILURE); + } + + idata.hsrcaddr_f = 1; + break; + + case 'D': /* Destination Ethernet Address */ + if (ether_pton(optarg, &(idata.hdstaddr), sizeof(idata.hdstaddr)) == 0) { + puts("Error in Source link-layer address."); + exit(EXIT_FAILURE); + } + + idata.hdstaddr_f = 1; + break; + + case 'P': /* Fragment Size*/ + fsize = atoi(optarg); + fsize_f = 1; + break; + + case 'O': /* Fragment Type */ + if (strncmp(optarg, "first", MAX_STRING_SIZE) == 0) { + forder = FIRST_FRAGMENT; + forder_f = 1; + } + else if (strncmp(optarg, "last", MAX_STRING_SIZE) == 0) { + forder = LAST_FRAGMENT; + forder_f = 1; + } + else if (strncmp(optarg, "middle", MAX_STRING_SIZE) == 0) { + forder = MIDDLE_FRAGMENT; + forder_f = 1; + } + else if (strncmp(optarg, "atomic", MAX_STRING_SIZE) == 0) { + forder = ATOMIC_FRAGMENT; + forder_f = 1; + } + else { + puts("Unknown fragment order (valid order types: 'first', 'last', 'middle')"); + exit(EXIT_FAILURE); + } + + break; + + case 'o': /* Fragment Offset */ + if ((ul_res = strtoul(optarg, &endptr, 0)) == ULONG_MAX) { + perror("Error in 'Fragment Offset' parameter"); + exit(EXIT_FAILURE); + } + + if (endptr != optarg) { + foffset = ul_res; + foffset_f = 1; + } + + break; + + case 'I': /* Fragment Identification */ + if ((ul_res = strtoul(optarg, &endptr, 0)) == ULONG_MAX) { + perror("Error in 'Fragment Identification' parameter"); + exit(EXIT_FAILURE); + } + + if (endptr != optarg) { + fid = ul_res; + fid_f = 1; + } + + break; + + case 'T': /* Do not include timestamp in fragment */ + tstamp_f = 0; + break; + + case 'n': /* Do not show responses */ + resp_f = 0; + break; + + case 'p': /* Assess the fragment reassembly policy of the target */ + fragp_f = 1; + break; + + case 'W': /* Assess the fragment id generation policy of the target */ + fragidp_f = 1; + break; + + case 'F': /* Flood target with fragments */ + nfrags = atoi(optarg); + if (nfrags == 0) { + puts("Invalid number of fragments in option -F"); + exit(EXIT_FAILURE); + } + + floodf_f = 1; + break; + + case 'X': + pod_f = 1; + break; + + case 'l': /* "Loop mode */ + loop_f = 1; + break; + + case 'z': /* Sleep option */ + nsleep = atoi(optarg); + if (nsleep == 0) { + puts("Invalid number of seconds in '-z' option"); + exit(EXIT_FAILURE); + } + + sleep_f = 1; + break; + + case 'v': /* Be verbose */ + idata.verbose_f++; + break; + + case 'h': /* Help */ + print_help(); + + exit(EXIT_FAILURE); + break; + + default: + usage(); + exit(EXIT_FAILURE); + break; + + } /* switch */ + } /* while(getopt) */ + + verbose_f = idata.verbose_f; + + if (geteuid()) { + puts("frag6 needs root privileges to run."); + exit(EXIT_FAILURE); + } + + if (!idata.iface_f) { + if (idata.dstaddr_f && IN6_IS_ADDR_LINKLOCAL(&(idata.dstaddr))) { + puts("Must specify a network interface for link-local destinations"); + exit(EXIT_FAILURE); + } + } + + if (load_dst_and_pcap(&idata, LOAD_SRC_NXT_HOP) == FAILURE) { + puts("Error while learning Source Address and Next Hop"); + exit(EXIT_FAILURE); + } + + release_privileges(); + + if ((idata.ip6_local_flag && idata.ip6_global_flag) && !idata.srcaddr_f) + localaddr_f = 1; + + if (!sleep_f) + nsleep = QUERY_TIMEOUT; + + idata.max_packet_size = MAX_IPV6_PAYLOAD + MIN_IPV6_HLEN; + + if (idata.verbose_f) { + print_attack_info(&idata); + } + + if (!idata.dstaddr_f) { + puts("Error: Nothing to send! (Destination Address left unspecified)"); + exit(EXIT_FAILURE); + } + + if (!floodf_f) + nfrags = 1; + + if (!forder_f) + forder = MIDDLE_FRAGMENT; + + /* Assess the Fragment Reassembly policy */ + if (fragp_f) { + puts("Identifying fragment reassembly policy of the target node...."); + + /* + Set filter for receiving Neighbor Solicitations, ICMPv6 Echo Responses, and ICMPv6 Time Exceeded + */ + if (pcap_compile(idata.pfd, &pcap_filter, PCAP_ICMPV6_NSECHOEXCEEDED_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == + -1) { + printf("pcap_compile(): %s\n", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } + + if (pcap_setfilter(idata.pfd, &pcap_filter) == -1) { + printf("pcap_setfilter(): %s\n", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } + + pcap_freecode(&pcap_filter); + + /* Initialize the table of results for the different tests */ + for (i = 0; i < 5; i++) + test[i] = TIMED_OUT; + + /* + These two variables select the fragment "overlap" size for the tests, and the minimum fragment size. + They are currently hardcoded, but will be configurable in future revisions of the tool. + */ + overlap = 8; + minfragsize = 8 * 10; + + /* + Since the current version of the tool does not reassemble response packets, we need to prevent + response packets from employing fragmentation. The maximum-sized packets that we send is composed + of a 4*minfragsize payload plus IPv6 and ICMPv6 headers -- hence the check bellow. + */ + if (minfragsize > ((idata.mtu - sizeof(struct ip6_hdr) - sizeof(struct icmp6_hdr)) / 4)) { + puts("Error: minimum fragment size is too large"); + exit(EXIT_FAILURE); + } + + if (overlap < 8 || (overlap % 8) != 0 || overlap >= minfragsize) { + puts("Error: Incorrect 'overlap' value"); + exit(EXIT_FAILURE); + } + + FD_ZERO(&sset); + FD_SET(idata.fd, &sset); + start = time(NULL); + + /* + This "schedules" the sending of probes for different types of packets. At most two probes + will be sent for each packet type. Probe #1 will be sent now, and resent after QUERY_TIMEOUT/2 + seconds. Probe #2 will be sent in 1 second, and resent after QUERY_TIMEOUT/2 seconds... etc. + This means that starting now, we send one probe for each packet type, one per second (to avoid + congesting the network). And we resend the probes in after QUERY_TIMEOUT/2 seconds (hence we + have QUERY_TIMEOUT/2 to wait for the responses of such probes). + */ + lastfrag1 = start - QUERY_TIMEOUT / 2; + lastfrag2 = start - QUERY_TIMEOUT / 2 + 1; + lastfrag3 = start - QUERY_TIMEOUT / 2 + 2; + lastfrag4 = start - QUERY_TIMEOUT / 2 + 3; + lastfrag5 = start - QUERY_TIMEOUT / 2 + 4; + responses = 0; + + while (1) { + curtime = time(NULL); + + /* + If we have already the timeout value, or already have results for each of the five tests, + exit the loop + */ + if ((curtime - start) >= QUERY_TIMEOUT || responses >= 5) { + break; + } + + if ((curtime - lastfrag1) >= QUERY_TIMEOUT / 2 && (test[0] == TIMED_OUT || test[0] == TIME_EXCEEDED)) { + if (idata.verbose_f) + puts("Sending Fragments for Test #1...."); + + id = random(); + + if (send_fragment2(&idata, sizeof(struct icmp6_hdr) + minfragsize * 2 - overlap, id, 0, minfragsize, + FIRST_FRAGMENT, block1) == -1) { + } + + if (send_fragment2(&idata, 0, id, sizeof(struct icmp6_hdr) + minfragsize - overlap, minfragsize, + LAST_FRAGMENT, block6) == -1) { + } + + lastfrag1 = curtime; + continue; + } + + if ((curtime - lastfrag2) >= QUERY_TIMEOUT / 2 && (test[1] == TIMED_OUT || test[1] == TIME_EXCEEDED)) { + if (idata.verbose_f) + puts("Sending Fragments for Test #2...."); + + id = random(); + + if (send_fragment2(&idata, sizeof(struct icmp6_hdr) + minfragsize * 3 - overlap, id, 0, minfragsize, + FIRST_FRAGMENT, block2) == -1) { + } + + if (send_fragment2(&idata, 0, id, sizeof(struct icmp6_hdr) + minfragsize * 2 - overlap, minfragsize, + LAST_FRAGMENT, block6) == -1) { + } + + if (send_fragment2(&idata, 0, id, sizeof(struct icmp6_hdr) + minfragsize - overlap, minfragsize, + MIDDLE_FRAGMENT, block7) == -1) { + } + + lastfrag2 = curtime; + continue; + } + + if ((curtime - lastfrag3) >= QUERY_TIMEOUT / 2 && (test[2] == TIMED_OUT || test[2] == TIME_EXCEEDED)) { + if (idata.verbose_f) + puts("Sending Fragments for Test #3...."); + + id = random(); + + if (send_fragment2(&idata, sizeof(struct icmp6_hdr) + minfragsize * 3 - overlap, id, 0, minfragsize, + FIRST_FRAGMENT, block3) == -1) { + } + + if (send_fragment2(&idata, 0, id, sizeof(struct icmp6_hdr) + minfragsize * 2 - overlap, minfragsize, + LAST_FRAGMENT, block6) == -1) { + } + + if (send_fragment2(&idata, 0, id, sizeof(struct icmp6_hdr) + minfragsize, minfragsize, MIDDLE_FRAGMENT, + block7) == -1) { + } + + lastfrag3 = curtime; + continue; + } + + if ((curtime - lastfrag4) >= QUERY_TIMEOUT / 2 && (test[3] == TIMED_OUT || test[3] == TIME_EXCEEDED)) { + if (idata.verbose_f) + puts("Sending Fragments for Test #4...."); + + id = random(); + + if (send_fragment2(&idata, sizeof(struct icmp6_hdr) + minfragsize * 4, id, 0, minfragsize, + FIRST_FRAGMENT, block4) == -1) { + } + + if (send_fragment2(&idata, 0, id, sizeof(struct icmp6_hdr) + minfragsize * 2, minfragsize, + MIDDLE_FRAGMENT, block6) == -1) { + } + + if (send_fragment2(&idata, 0, id, sizeof(struct icmp6_hdr) + minfragsize, minfragsize * 3, + LAST_FRAGMENT, block7) == -1) { + } + + lastfrag4 = curtime; + continue; + } + if ((curtime - lastfrag5) >= QUERY_TIMEOUT / 2 && (test[4] == TIMED_OUT || test[4] == TIME_EXCEEDED)) { + if (idata.verbose_f) + puts("Sending Fragments for Test #5...."); - if((curtime - lastfrag5) >= QUERY_TIMEOUT/2 && (test[4]== TIMED_OUT || test[4]==TIME_EXCEEDED)){ - if(idata.verbose_f) - puts("Sending Fragments for Test #5...."); + id = random(); - id= random(); + if (send_fragment2(&idata, sizeof(struct icmp6_hdr) + minfragsize * 4 - overlap, id, 0, minfragsize, + FIRST_FRAGMENT, block5) == -1) { + puts("Error when writing fragment"); + exit(EXIT_FAILURE); + } - if(send_fragment2(&idata, sizeof(struct icmp6_hdr)+minfragsize * 4 - overlap, id, 0, minfragsize, \ - FIRST_FRAGMENT, block5) == -1){ - puts("Error when writing fragment"); - exit(EXIT_FAILURE); - } + if (send_fragment2(&idata, 0, id, sizeof(struct icmp6_hdr) + minfragsize * 2, minfragsize, + MIDDLE_FRAGMENT, block6) == -1) { + puts("Error when writing fragment"); + exit(EXIT_FAILURE); + } - if(send_fragment2(&idata, 0, id, sizeof(struct icmp6_hdr)+minfragsize * 2, minfragsize, MIDDLE_FRAGMENT, \ - block6) == -1){ - puts("Error when writing fragment"); - exit(EXIT_FAILURE); - } + if (send_fragment2(&idata, 0, id, sizeof(struct icmp6_hdr) + minfragsize * 3 - overlap, minfragsize, + LAST_FRAGMENT, block7) == -1) { + puts("Error when writing fragment"); + exit(EXIT_FAILURE); + } - if(send_fragment2(&idata, 0, id, sizeof(struct icmp6_hdr)+minfragsize * 3 - overlap, minfragsize, \ - LAST_FRAGMENT, block7) == -1){ - puts("Error when writing fragment"); - exit(EXIT_FAILURE); - } + if (send_fragment2(&idata, 0, id, sizeof(struct icmp6_hdr) + minfragsize, minfragsize, MIDDLE_FRAGMENT, + block8) == -1) { + puts("Error when writing fragment"); + exit(EXIT_FAILURE); + } - if(send_fragment2(&idata, 0, id, sizeof(struct icmp6_hdr)+minfragsize, minfragsize, MIDDLE_FRAGMENT, \ - block8) == -1){ - puts("Error when writing fragment"); - exit(EXIT_FAILURE); - } + lastfrag5 = curtime; + } - lastfrag5=curtime; - } - - rset= sset; + rset = sset; #if !defined(sun) && !defined(__sun) && !defined(__linux__) - timeout.tv_usec=0; - timeout.tv_sec= 1; + timeout.tv_usec = 0; + timeout.tv_sec = 1; #else - timeout.tv_usec=10000; - timeout.tv_sec= 0; + timeout.tv_usec = 10000; + timeout.tv_sec = 0; #endif - if((sel=select(idata.fd+1, &rset, NULL, NULL, &timeout)) == -1){ - if(errno == EINTR){ - continue; - } - else{ - puts("Error in select()"); - exit(EXIT_FAILURE); - } - } + if ((sel = select(idata.fd + 1, &rset, NULL, NULL, &timeout)) == -1) { + if (errno == EINTR) { + continue; + } + else { + puts("Error in select()"); + exit(EXIT_FAILURE); + } + } #if defined(sun) || defined(__sun) || defined(__linux__) - if(TRUE){ + if (TRUE) { #else - if(sel && FD_ISSET(idata.fd, &rset)){ + if (sel && FD_ISSET(idata.fd, &rset)) { #endif - /* Read a packet (Echo Reply, ICMPv6 Error, or Neighbor Solicitation) */ - if((r=pcap_next_ex(idata.pfd, &pkthdr, &pktdata)) == -1){ - printf("pcap_next_ex(): %s", pcap_geterr(idata.pfd)); - exit(EXIT_FAILURE); - } - else if(r == 1 && pktdata != NULL){ - pkt_ether = (struct ether_header *) pktdata; - pkt_ipv6 = (struct ip6_hdr *)((char *) pkt_ether + idata.linkhsize); - pkt_icmp6 = (struct icmp6_hdr *) ((char *) pkt_ipv6 + sizeof(struct ip6_hdr)); - pkt_ns= (struct nd_neighbor_solicit *) pkt_icmp6; - pkt_end = (unsigned char *) pktdata + pkthdr->caplen; - - if( (pkt_end - pktdata) < (idata.linkhsize + MIN_IPV6_HLEN)) - continue; - - if(pkt_ipv6->ip6_nxt == IPPROTO_ICMPV6){ - if(idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK) && pkt_icmp6->icmp6_type == ND_NEIGHBOR_SOLICIT){ - if( (pkt_end - (unsigned char *) pkt_ns) < sizeof(struct nd_neighbor_solicit)) - continue; - /* - If the addresses that we're using are not actually configured on the local system - (i.e., they are "spoofed", we must check whether it is a Neighbor Solicitation for - one of our addresses, and respond with a Neighbor Advertisement. Otherwise, the kernel - will take care of that. - */ - if(idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK) && !localaddr_f && \ - is_eq_in6_addr(&(pkt_ns->nd_ns_target), &idata.srcaddr)){ - if(send_neighbor_advert(&idata, idata.pfd, pktdata) == -1){ - puts("Error sending Neighbor Advertisement"); - exit(EXIT_FAILURE); - } - } - } - else if( (pkt_icmp6->icmp6_type == ICMP6_ECHO_REPLY) || (pkt_icmp6->icmp6_type == ICMP6_TIME_EXCEEDED)){ - if( (pkt_end - (unsigned char *) pkt_icmp6) < sizeof(struct icmp6_hdr)) - continue; - - switch(pkt_icmp6->icmp6_type){ - case ICMP6_ECHO_REPLY: - process_icmp6_echo(&idata, pkthdr, pktdata, test, &responses); - break; - - case ICMP6_TIME_EXCEEDED: - process_icmp6_timed(&idata, pkthdr, pktdata, test); - break; - } - } - } - } - } - } - - for(i=0;i<5;i++){ - printf("Test #%u: ", (i+1)); - switch(test[i]){ - case FIRST_COPY: - puts("Target preferred first copy of overlapping data"); - break; - - case LAST_COPY: - puts("Target preferred last copy of overlapping data"); - break; - - case TIME_EXCEEDED: - puts("Received ICMPv6 Time Exceeded error message (fragments discarded)"); - break; - - case TIMED_OUT: - puts("Timed out (fragments discarded without notification)"); - break; - - case UNKNOWN_COPY: - puts("Unknown pattern in response (shouldn't happen!)"); - break; - } - } - - exit(EXIT_SUCCESS); - } - - - /* Assess the Fragment ID generation policy */ - if(fragidp_f){ - puts("Identifying the 'Fragment ID' generation policy of the target node...."); - - /* - Set filter for receiving Neighbor Solicitations, and fragmented ICMPv6 Echo Responses - */ - if(pcap_compile(idata.pfd, &pcap_filter, PCAP_ICMPV6NSFRAG_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1){ - printf("pcap_compile(): %s\n", pcap_geterr(idata.pfd)); - exit(EXIT_FAILURE); - } - - if(pcap_setfilter(idata.pfd, &pcap_filter) == -1){ - printf("pcap_setfilter(): %s\n", pcap_geterr(idata.pfd)); - exit(EXIT_FAILURE); - } - - pcap_freecode(&pcap_filter); - - FD_ZERO(&sset); - FD_SET(idata.fd, &sset); - - if(gettimeofday(&startt, NULL) == -1){ - if(idata.verbose_f) - perror("frag6"); - - exit(EXIT_FAILURE); - } - - lastfrag1t.tv_sec=0; - lastfrag1t.tv_usec=0; - - ntest1=0; - ntest2=0; - icmp6_sig= random(); - testtype= FIXED_ORIGIN; - - if(idata.srcprefix_f){ - randprefix=idata.srcaddr; - randpreflen=idata.srcpreflen; - } - else{ - randprefix= idata.srcaddr; - randpreflen=64; - sanitize_ipv6_prefix(&randprefix, randpreflen); - } - - while(1){ - if(gettimeofday(&curtimet, NULL) == -1){ - if(idata.verbose_f) - perror("scan6"); - - exit(EXIT_FAILURE); - } - - /* - If we were doing tests from a single origin, and we have reached the assessment timeout - or already have enough samples, we must now sample from multiple origins. - - */ - if( testtype==FIXED_ORIGIN && (is_time_elapsed(&curtimet, &startt, FID_ASSESS_TIMEOUT * 1000000) || ntest1 >= NSAMPLES)){ - testtype= MULTI_ORIGIN; - addr_sig= random(); - addr_key= random(); - startt= curtimet; - continue; - } - else if( testtype==MULTI_ORIGIN && (is_time_elapsed(&curtimet, &startt, FID_ASSESS_TIMEOUT * 1000000) || ntest2 >= NSAMPLES)){ - break; - } - - /* - lastfrag1 contains the time the last time we sent probe packets. Probes are sent every - FID_ASSESS_DELTA uses to avoid packet reordering. - - XXX: Eventually we should infer reordering in the sample data and order the samples if - necessary. - */ - - if(is_time_elapsed(&curtimet, &lastfrag1t, FID_ASSESS_DELTA)){ - if(testtype == FIXED_ORIGIN){ - if(send_fid_probe(&idata) == -1){ - puts("Error while sending packet"); - exit(EXIT_FAILURE); - } - } - else{ - randomize_ipv6_addr(&(idata.srcaddr), &randprefix, randpreflen); - - /* - * Two words of the Source IPv6 Address are specially encoded such that we only respond - * to Neighbor Solicitations that target those addresses, and accept ICMPv6 Echo Replies - * only if they are destined to those addresses - */ - idata.srcaddr.s6_addr32[2]= htonl((ntohl(idata.srcaddr.s6_addr32[2]) & 0xffff0000) | addr_sig); - idata.srcaddr.s6_addr32[3]= htonl((ntohl(idata.srcaddr.s6_addr32[3]) & 0xffff0000) | \ - ((uint16_t)(ntohl(idata.srcaddr.s6_addr32[3])>>16) ^ addr_key)); - - /* - * XXX This trick is innefective with OpenBSD. Hence we don't try to prevent the - * first-fragment of the response packet from being dropped. - - if(send_neighbor_solicit(&idata) == -1){ - puts("Error while sending Neighbor Solicitation"); - exit(EXIT_FAILURE); - } - */ - - if(send_fid_probe(&idata) == -1){ - puts("Error while sending packet"); - exit(EXIT_FAILURE); - } - } - - lastfrag1t=curtimet; - continue; - } - - rset= sset; + /* Read a packet (Echo Reply, ICMPv6 Error, or Neighbor Solicitation) */ + if ((r = pcap_next_ex(idata.pfd, &pkthdr, &pktdata)) == -1) { + printf("pcap_next_ex(): %s", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } + else if (r == 1 && pktdata != NULL) { + pkt_ether = (struct ether_header *)pktdata; + pkt_ipv6 = (struct ip6_hdr *)((char *)pkt_ether + idata.linkhsize); + pkt_icmp6 = (struct icmp6_hdr *)((char *)pkt_ipv6 + sizeof(struct ip6_hdr)); + pkt_ns = (struct nd_neighbor_solicit *)pkt_icmp6; + pkt_end = (unsigned char *)pktdata + pkthdr->caplen; + + if ((pkt_end - pktdata) < (idata.linkhsize + MIN_IPV6_HLEN)) + continue; + + if (pkt_ipv6->ip6_nxt == IPPROTO_ICMPV6) { + if (idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK) && + pkt_icmp6->icmp6_type == ND_NEIGHBOR_SOLICIT) { + if ((pkt_end - (unsigned char *)pkt_ns) < sizeof(struct nd_neighbor_solicit)) + continue; + /* + If the addresses that we're using are not actually configured on the local system + (i.e., they are "spoofed", we must check whether it is a Neighbor Solicitation for + one of our addresses, and respond with a Neighbor Advertisement. Otherwise, the + kernel will take care of that. + */ + if (idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK) && !localaddr_f && + is_eq_in6_addr(&(pkt_ns->nd_ns_target), &idata.srcaddr)) { + if (send_neighbor_advert(&idata, idata.pfd, pktdata) == -1) { + puts("Error sending Neighbor Advertisement"); + exit(EXIT_FAILURE); + } + } + } + else if ((pkt_icmp6->icmp6_type == ICMP6_ECHO_REPLY) || + (pkt_icmp6->icmp6_type == ICMP6_TIME_EXCEEDED)) { + if ((pkt_end - (unsigned char *)pkt_icmp6) < sizeof(struct icmp6_hdr)) + continue; + + switch (pkt_icmp6->icmp6_type) { + case ICMP6_ECHO_REPLY: + process_icmp6_echo(&idata, pkthdr, pktdata, test, &responses); + break; + + case ICMP6_TIME_EXCEEDED: + process_icmp6_timed(&idata, pkthdr, pktdata, test); + break; + } + } + } + } + } + } + + for (i = 0; i < 5; i++) { + printf("Test #%u: ", (i + 1)); + switch (test[i]) { + case FIRST_COPY: + puts("Target preferred first copy of overlapping data"); + break; + + case LAST_COPY: + puts("Target preferred last copy of overlapping data"); + break; + + case TIME_EXCEEDED: + puts("Received ICMPv6 Time Exceeded error message (fragments discarded)"); + break; + + case TIMED_OUT: + puts("Timed out (fragments discarded without notification)"); + break; + + case UNKNOWN_COPY: + puts("Unknown pattern in response (shouldn't happen!)"); + break; + } + } + + exit(EXIT_SUCCESS); + } + + /* Assess the Fragment ID generation policy */ + if (fragidp_f) { + puts("Identifying the 'Fragment ID' generation policy of the target node...."); + + /* + Set filter for receiving Neighbor Solicitations, and fragmented ICMPv6 Echo Responses + */ + if (pcap_compile(idata.pfd, &pcap_filter, PCAP_ICMPV6NSFRAG_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1) { + printf("pcap_compile(): %s\n", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } + + if (pcap_setfilter(idata.pfd, &pcap_filter) == -1) { + printf("pcap_setfilter(): %s\n", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } + + pcap_freecode(&pcap_filter); + + FD_ZERO(&sset); + FD_SET(idata.fd, &sset); + + if (gettimeofday(&startt, NULL) == -1) { + if (idata.verbose_f) + perror("frag6"); + + exit(EXIT_FAILURE); + } + + lastfrag1t.tv_sec = 0; + lastfrag1t.tv_usec = 0; + + ntest1 = 0; + ntest2 = 0; + icmp6_sig = random(); + testtype = FIXED_ORIGIN; + + if (idata.srcprefix_f) { + randprefix = idata.srcaddr; + randpreflen = idata.srcpreflen; + } + else { + randprefix = idata.srcaddr; + randpreflen = 64; + sanitize_ipv6_prefix(&randprefix, randpreflen); + } + + while (1) { + if (gettimeofday(&curtimet, NULL) == -1) { + if (idata.verbose_f) + perror("scan6"); + + exit(EXIT_FAILURE); + } + + /* + If we were doing tests from a single origin, and we have reached the assessment timeout + or already have enough samples, we must now sample from multiple origins. + + */ + if (testtype == FIXED_ORIGIN && + (is_time_elapsed(&curtimet, &startt, FID_ASSESS_TIMEOUT * 1000000) || ntest1 >= NSAMPLES)) { + testtype = MULTI_ORIGIN; + addr_sig = random(); + addr_key = random(); + startt = curtimet; + continue; + } + else if (testtype == MULTI_ORIGIN && + (is_time_elapsed(&curtimet, &startt, FID_ASSESS_TIMEOUT * 1000000) || ntest2 >= NSAMPLES)) { + break; + } + + /* + lastfrag1 contains the time the last time we sent probe packets. Probes are sent every + FID_ASSESS_DELTA uses to avoid packet reordering. + + XXX: Eventually we should infer reordering in the sample data and order the samples if + necessary. + */ + + if (is_time_elapsed(&curtimet, &lastfrag1t, FID_ASSESS_DELTA)) { + if (testtype == FIXED_ORIGIN) { + if (send_fid_probe(&idata) == -1) { + puts("Error while sending packet"); + exit(EXIT_FAILURE); + } + } + else { + randomize_ipv6_addr(&(idata.srcaddr), &randprefix, randpreflen); + + /* + * Two words of the Source IPv6 Address are specially encoded such that we only respond + * to Neighbor Solicitations that target those addresses, and accept ICMPv6 Echo Replies + * only if they are destined to those addresses + */ + idata.srcaddr.s6_addr32[2] = htonl((ntohl(idata.srcaddr.s6_addr32[2]) & 0xffff0000) | addr_sig); + idata.srcaddr.s6_addr32[3] = + htonl((ntohl(idata.srcaddr.s6_addr32[3]) & 0xffff0000) | + ((uint16_t)(ntohl(idata.srcaddr.s6_addr32[3]) >> 16) ^ addr_key)); + + /* + * XXX This trick is innefective with OpenBSD. Hence we don't try to prevent the + * first-fragment of the response packet from being dropped. + + if(send_neighbor_solicit(&idata) == -1){ + puts("Error while sending Neighbor Solicitation"); + exit(EXIT_FAILURE); + } + */ + + if (send_fid_probe(&idata) == -1) { + puts("Error while sending packet"); + exit(EXIT_FAILURE); + } + } + + lastfrag1t = curtimet; + continue; + } + + rset = sset; #if !defined(sun) && !defined(__sun) && !defined(__linux__) - timeout.tv_usec=0; - timeout.tv_sec= 1; + timeout.tv_usec = 0; + timeout.tv_sec = 1; #else - timeout.tv_usec=10000; - timeout.tv_sec= 0; + timeout.tv_usec = 10000; + timeout.tv_sec = 0; #endif - if((sel=select(idata.fd+1, &rset, NULL, NULL, &timeout)) == -1){ - if(errno == EINTR){ - continue; - } - else{ - puts("Error in select()"); - exit(EXIT_FAILURE); - } - } + if ((sel = select(idata.fd + 1, &rset, NULL, NULL, &timeout)) == -1) { + if (errno == EINTR) { + continue; + } + else { + puts("Error in select()"); + exit(EXIT_FAILURE); + } + } #if defined(sun) || defined(__sun) || defined(__linux__) - if(TRUE){ + if (TRUE) { #else - if(sel && FD_ISSET(idata.fd, &rset)){ + if (sel && FD_ISSET(idata.fd, &rset)) { #endif - /* Read a packet (Echo Reply, or Neighbor Solicitation) */ - if((r=pcap_next_ex(idata.pfd, &pkthdr, &pktdata)) == -1){ - printf("pcap_next_ex(): %s", pcap_geterr(idata.pfd)); - exit(EXIT_FAILURE); - } - else if(r == 1 && pktdata != NULL){ - pkt_ether = (struct ether_header *) pktdata; - pkt_ipv6 = (struct ip6_hdr *)((char *) pkt_ether + idata.linkhsize); - pkt_icmp6 = (struct icmp6_hdr *) ((char *) pkt_ipv6 + sizeof(struct ip6_hdr)); - pkt_end = (unsigned char *) pktdata + pkthdr->caplen; - - if( (pkt_end - pktdata) < (idata.linkhsize + MIN_IPV6_HLEN)) - continue; - - if(idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK) && \ - pkt_ipv6->ip6_nxt == IPPROTO_ICMPV6 && pkt_icmp6->icmp6_type == ND_NEIGHBOR_SOLICIT){ - pkt_ns= (struct nd_neighbor_solicit *) pkt_icmp6; - - if( (pkt_end - (unsigned char *) pkt_ns) < sizeof(struct nd_neighbor_solicit)) - continue; - /* - If the addresses that we're using are not actually configured on the local system - (i.e., they are "spoofed", we must check whether it is a Neighbor Solicitation for - one of our addresses, and respond with a Neighbor Advertisement. Otherwise, the kernel - will take care of that. - */ - if(testtype==FIXED_ORIGIN){ - if(idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK) && \ - !localaddr_f && is_eq_in6_addr(&(pkt_ns->nd_ns_target), &(idata.srcaddr))){ - if(send_neighbor_advert(&idata, idata.pfd, pktdata) == -1){ - puts("Error sending Neighbor Advertisement"); - exit(EXIT_FAILURE); - } - } - } - else if(idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK)){ - if( (ntohl(pkt_ns->nd_ns_target.s6_addr32[2]) & 0x0000ffff) != addr_sig || \ - (ntohl(pkt_ns->nd_ns_target.s6_addr32[3]) & 0x0000ffff) != ( (ntohl(pkt_ns->nd_ns_target.s6_addr32[3])>>16) ^ addr_key)){ - continue; - } - - if(send_neighbor_advert(&idata, idata.pfd, pktdata) == -1){ - puts("Error sending Neighbor Advertisement"); - exit(EXIT_FAILURE); - } - } - } - else if(pkt_ipv6->ip6_nxt == IPPROTO_FRAGMENT){ - if( (pkt_end - (unsigned char *) pkt_ipv6) < \ - (sizeof(struct ip6_hdr) + sizeof(struct ip6_frag) + sizeof(struct icmp6_hdr) + sizeof(uint32_t))) - continue; - - pkt_fh= (struct ip6_frag *) ( (unsigned char *)pkt_ipv6 + sizeof(struct ip6_hdr)); - - if(pkt_fh->ip6f_nxt != IPPROTO_ICMPV6) - continue; - - /* XXX We only sample non-first fragments (see below) */ - if(!(pkt_fh->ip6f_offlg & IP6F_OFF_MASK)) - continue; - - /* - * XXX These checks were removed, since when assessing some implementations on a local - * network, we never get the first fragment because it is discarded when it triggers ND. - */ - if(!(pkt_fh->ip6f_offlg & IP6F_OFF_MASK)){ - pkt_icmp6= (struct icmp6_hdr *) ((unsigned char *)pkt_fh + sizeof(struct ip6_frag)); - - if(pkt_icmp6->icmp6_type != ICMP6_ECHO_REPLY) - continue; - - if(ntohs(pkt_icmp6->icmp6_data16[0]) != getpid() ) - continue; - } - - if(testtype==FIXED_ORIGIN){ - if(!is_eq_in6_addr(&(pkt_ipv6->ip6_dst), &(idata.srcaddr))){ - continue; - } - - /* XXX Not used when sampling non-first fragments */ - if(!(pkt_fh->ip6f_offlg & IP6F_OFF_MASK)){ - if( *(uint32_t *)((unsigned char *)pkt_icmp6+ sizeof(struct icmp6_hdr)) != icmp6_sig){ - continue; - } - } - - if(ntest1 >= NSAMPLES) - continue; - - test1[ntest1]= ntohl(pkt_fh->ip6f_ident); - ntest1++; - } - else{ - if( (ntohl(pkt_ipv6->ip6_dst.s6_addr32[2]) & 0x0000ffff) != addr_sig || \ - (ntohl(pkt_ipv6->ip6_dst.s6_addr32[3]) & 0x0000ffff) != ( (ntohl(pkt_ipv6->ip6_dst.s6_addr32[3])>>16) ^ addr_key)){ - continue; - } - - /* XXX Not used when sampling non-first fragments */ - if(!(pkt_fh->ip6f_offlg & IP6F_OFF_MASK)){ - if( *(uint32_t *)((unsigned char *)pkt_icmp6+ sizeof(struct icmp6_hdr)) != icmp6_sig){ - continue; - } - } - - if(ntest2 >= NSAMPLES) - continue; - - test2[ntest2]= ntohl(pkt_fh->ip6f_ident); - ntest2++; - } - } - } - } - } - - if(idata.verbose_f > 1){ - printf("Sampled %u Fragment Identifications from single-origin probes\n", ntest1); - - for(i=0; i= QUERY_TIMEOUT || (!resp_f && lastfrag != 0) || (resp_f && gotresp_f))){ - break; - } - - if((curtime - lastfrag) >= nsleep){ - puts("Sending Fragment(s)...."); - - frags=0; - - if(!foffset_f){ - foffset= random(); - } - - if(forder != LAST_FRAGMENT){ - foffset= (foffset >> 3) << 3; - } - - while(frags < nfrags){ - if(send_fragment(&idata, fid_f?fid:random(), foffset, fsize_f?fsize:( ((MIN_FRAG_SIZE+(random()%400))>>3)<<3), \ - forder, tstamp_f) == -1){ - - puts("Error sending packet"); - exit(EXIT_FAILURE); - } - - frags++; - } - - lastfrag=curtime; - continue; - } - - rset= sset; + /* Read a packet (Echo Reply, or Neighbor Solicitation) */ + if ((r = pcap_next_ex(idata.pfd, &pkthdr, &pktdata)) == -1) { + printf("pcap_next_ex(): %s", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } + else if (r == 1 && pktdata != NULL) { + pkt_ether = (struct ether_header *)pktdata; + pkt_ipv6 = (struct ip6_hdr *)((char *)pkt_ether + idata.linkhsize); + pkt_icmp6 = (struct icmp6_hdr *)((char *)pkt_ipv6 + sizeof(struct ip6_hdr)); + pkt_end = (unsigned char *)pktdata + pkthdr->caplen; + + if ((pkt_end - pktdata) < (idata.linkhsize + MIN_IPV6_HLEN)) + continue; + + if (idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK) && + pkt_ipv6->ip6_nxt == IPPROTO_ICMPV6 && pkt_icmp6->icmp6_type == ND_NEIGHBOR_SOLICIT) { + pkt_ns = (struct nd_neighbor_solicit *)pkt_icmp6; + + if ((pkt_end - (unsigned char *)pkt_ns) < sizeof(struct nd_neighbor_solicit)) + continue; + /* + If the addresses that we're using are not actually configured on the local system + (i.e., they are "spoofed", we must check whether it is a Neighbor Solicitation for + one of our addresses, and respond with a Neighbor Advertisement. Otherwise, the kernel + will take care of that. + */ + if (testtype == FIXED_ORIGIN) { + if (idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK) && !localaddr_f && + is_eq_in6_addr(&(pkt_ns->nd_ns_target), &(idata.srcaddr))) { + if (send_neighbor_advert(&idata, idata.pfd, pktdata) == -1) { + puts("Error sending Neighbor Advertisement"); + exit(EXIT_FAILURE); + } + } + } + else if (idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK)) { + if ((ntohl(pkt_ns->nd_ns_target.s6_addr32[2]) & 0x0000ffff) != addr_sig || + (ntohl(pkt_ns->nd_ns_target.s6_addr32[3]) & 0x0000ffff) != + ((ntohl(pkt_ns->nd_ns_target.s6_addr32[3]) >> 16) ^ addr_key)) { + continue; + } + + if (send_neighbor_advert(&idata, idata.pfd, pktdata) == -1) { + puts("Error sending Neighbor Advertisement"); + exit(EXIT_FAILURE); + } + } + } + else if (pkt_ipv6->ip6_nxt == IPPROTO_FRAGMENT) { + if ((pkt_end - (unsigned char *)pkt_ipv6) < (sizeof(struct ip6_hdr) + sizeof(struct ip6_frag) + + sizeof(struct icmp6_hdr) + sizeof(uint32_t))) + continue; + + pkt_fh = (struct ip6_frag *)((unsigned char *)pkt_ipv6 + sizeof(struct ip6_hdr)); + + if (pkt_fh->ip6f_nxt != IPPROTO_ICMPV6) + continue; + + /* XXX We only sample non-first fragments (see below) */ + if (!(pkt_fh->ip6f_offlg & IP6F_OFF_MASK)) + continue; + + /* + * XXX These checks were removed, since when assessing some implementations on a local + * network, we never get the first fragment because it is discarded when it triggers ND. + */ + if (!(pkt_fh->ip6f_offlg & IP6F_OFF_MASK)) { + pkt_icmp6 = (struct icmp6_hdr *)((unsigned char *)pkt_fh + sizeof(struct ip6_frag)); + + if (pkt_icmp6->icmp6_type != ICMP6_ECHO_REPLY) + continue; + + if (ntohs(pkt_icmp6->icmp6_data16[0]) != getpid()) + continue; + } + + if (testtype == FIXED_ORIGIN) { + if (!is_eq_in6_addr(&(pkt_ipv6->ip6_dst), &(idata.srcaddr))) { + continue; + } + + /* XXX Not used when sampling non-first fragments */ + if (!(pkt_fh->ip6f_offlg & IP6F_OFF_MASK)) { + if (*(uint32_t *)((unsigned char *)pkt_icmp6 + sizeof(struct icmp6_hdr)) != icmp6_sig) { + continue; + } + } + + if (ntest1 >= NSAMPLES) + continue; + + test1[ntest1] = ntohl(pkt_fh->ip6f_ident); + ntest1++; + } + else { + if ((ntohl(pkt_ipv6->ip6_dst.s6_addr32[2]) & 0x0000ffff) != addr_sig || + (ntohl(pkt_ipv6->ip6_dst.s6_addr32[3]) & 0x0000ffff) != + ((ntohl(pkt_ipv6->ip6_dst.s6_addr32[3]) >> 16) ^ addr_key)) { + continue; + } + + /* XXX Not used when sampling non-first fragments */ + if (!(pkt_fh->ip6f_offlg & IP6F_OFF_MASK)) { + if (*(uint32_t *)((unsigned char *)pkt_icmp6 + sizeof(struct icmp6_hdr)) != icmp6_sig) { + continue; + } + } + + if (ntest2 >= NSAMPLES) + continue; + + test2[ntest2] = ntohl(pkt_fh->ip6f_ident); + ntest2++; + } + } + } + } + } + + if (idata.verbose_f > 1) { + printf("Sampled %u Fragment Identifications from single-origin probes\n", ntest1); + + for (i = 0; i < ntest1; i++) + printf("#%02u: %08x\n", (i + 1), test1[i]); + + printf("\nSampled %u Fragment Identifications from multi-origin probes\n", ntest2); + + for (i = 0; i < ntest2; i++) + printf("#%02u: %08x\n", (i + 1), test2[i]); + + puts(""); + } + + if (ntest1 < 10 || ntest2 < 10) { + puts("Error: Didn't receive enough response packets"); + exit(EXIT_FAILURE); + } + + if (predict_frag_id(test1, ntest1, test2, ntest2) == -1) { + puts("Error in predict_frag_id()"); + exit(EXIT_FAILURE); + } + + exit(EXIT_SUCCESS); + } + + /* Perform an IPv6-version of the "Ping of Death" attack */ + if (pod_f) { + puts("Performing a 'ping of death' attack against the target node...."); + + /* + Set filter for receiving Neighbor Solicitations, ICMPv6 Echo Responses, and ICMPv6 Time Exceeded + */ + if (pcap_compile(idata.pfd, &pcap_filter, PCAP_ICMPV6_NSECHOEXCEEDED_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == + -1) { + printf("pcap_compile(): %s\n", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } + + if (pcap_setfilter(idata.pfd, &pcap_filter) == -1) { + printf("pcap_setfilter(): %s\n", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } + + pcap_freecode(&pcap_filter); + + maxsizedchunk = idata.mtu - sizeof(struct ip6_hdr) - sizeof(struct ip6_frag); + id = random(); + foffset = 0; + i = 0; + + /* We send maximum-sized fragments to cover the entire offset space */ + while ((foffset + maxsizedchunk) < MAX_FRAG_OFFSET) { + if (send_fragment(&idata, id, foffset, maxsizedchunk, foffset ? MIDDLE_FRAGMENT : FIRST_FRAGMENT, + NO_TIMESTAMP) == -1) { + puts("Error when writing fragment"); + exit(EXIT_FAILURE); + } + + foffset += maxsizedchunk; + i++; + + /* Pause for 1 second every 8 packets */ + if (!(i % 8)) + sleep(1); + } + + /* + We send another fragment to close the gap with the last fragment and a fragment with + offset 0xfff8 + */ + if (foffset != MAX_FRAG_OFFSET) { + if (send_fragment(&idata, id, foffset, (idata.mtu - maxsizedchunk) / 8, MIDDLE_FRAGMENT, NO_TIMESTAMP) == + -1) { + puts("Error when writing fragment"); + exit(EXIT_FAILURE); + } + + foffset += (idata.mtu - maxsizedchunk) / 8; + } + + /* Send a last fragment, at the right edge, with the maximum possible size */ + if (send_fragment(&idata, id, foffset, idata.mtu - sizeof(struct ip6_hdr) - sizeof(struct ip6_frag), + LAST_FRAGMENT, NO_TIMESTAMP) == -1) { + puts("Error when writing fragment"); + exit(EXIT_FAILURE); + } + + exit(EXIT_SUCCESS); + } + + /* Send fragments to a target destination */ + if (idata.dstaddr_f) { + /* + Set filter for receiving Neighbor Solicitations, ICMPv6 Echo Responses, and ICMPv6 Time Exceeded + */ + if (pcap_compile(idata.pfd, &pcap_filter, PCAP_ICMPV6_NSECHOEXCEEDED_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == + -1) { + printf("pcap_compile(): %s\n", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } + + if (pcap_setfilter(idata.pfd, &pcap_filter) == -1) { + printf("pcap_setfilter(): %s\n", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } + + pcap_freecode(&pcap_filter); + + FD_ZERO(&sset); + FD_SET(idata.fd, &sset); + lastfrag = 0; + start = time(NULL); + + while (1) { + curtime = time(NULL); + + if (!loop_f && + ((curtime - start) >= QUERY_TIMEOUT || (!resp_f && lastfrag != 0) || (resp_f && gotresp_f))) { + break; + } + + if ((curtime - lastfrag) >= nsleep) { + puts("Sending Fragment(s)...."); + + frags = 0; + + if (!foffset_f) { + foffset = random(); + } + + if (forder != LAST_FRAGMENT) { + foffset = (foffset >> 3) << 3; + } + + while (frags < nfrags) { + if (send_fragment(&idata, fid_f ? fid : random(), foffset, + fsize_f ? fsize : (((MIN_FRAG_SIZE + (random() % 400)) >> 3) << 3), forder, + tstamp_f) == -1) { + + puts("Error sending packet"); + exit(EXIT_FAILURE); + } + + frags++; + } + + lastfrag = curtime; + continue; + } + + rset = sset; #if defined(sun) || defined(__sun) || defined(__linux__) - timeout.tv_usec=10000; - timeout.tv_sec= 0; + timeout.tv_usec = 10000; + timeout.tv_sec = 0; #else - timeout.tv_usec=0; - timeout.tv_sec= (lastfrag+nsleep)-curtime; + timeout.tv_usec = 0; + timeout.tv_sec = (lastfrag + nsleep) - curtime; #endif - if((sel=select(idata.fd+1, &rset, NULL, NULL, &timeout)) == -1){ - if(errno == EINTR){ - continue; - } - else{ - puts("Error in select()"); - exit(EXIT_FAILURE); - } - } + if ((sel = select(idata.fd + 1, &rset, NULL, NULL, &timeout)) == -1) { + if (errno == EINTR) { + continue; + } + else { + puts("Error in select()"); + exit(EXIT_FAILURE); + } + } #if defined(sun) || defined(__sun) || defined(__linux__) - if(TRUE){ + if (TRUE) { #else - if(sel && FD_ISSET(idata.fd, &rset)){ + if (sel && FD_ISSET(idata.fd, &rset)) { #endif - /* Read a packet (Echo Reply, ICMPv6 Error, or Neighbor Solicitation) */ - if((r=pcap_next_ex(idata.pfd, &pkthdr, &pktdata)) == -1){ - printf("pcap_next_ex(): %s", pcap_geterr(idata.pfd)); - exit(EXIT_FAILURE); - } - else if(r == 1 && pktdata != NULL){ - pkt_ether = (struct ether_header *) pktdata; - pkt_ipv6 = (struct ip6_hdr *)((char *) pkt_ether + idata.linkhsize); - pkt_icmp6 = (struct icmp6_hdr *) ((char *) pkt_ipv6 + sizeof(struct ip6_hdr)); - pkt_ns= (struct nd_neighbor_solicit *) pkt_icmp6; - pkt_end = (unsigned char *) pktdata + pkthdr->caplen; - - if( (pkt_end - pktdata) < (idata.linkhsize + MIN_IPV6_HLEN)) - continue; - - if(pkt_ipv6->ip6_nxt == IPPROTO_ICMPV6){ - if(idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK) && pkt_icmp6->icmp6_type == ND_NEIGHBOR_SOLICIT){ - if( (pkt_end - (unsigned char *) pkt_ns) < sizeof(struct nd_neighbor_solicit)) - continue; - /* - If the addresses that we're using are not actually configured on the local system - (i.e., they are "spoofed", we must check whether it is a Neighbor Solicitation for - one of our addresses, and respond with a Neighbor Advertisement. Otherwise, the kernel - will take care of that. - */ - if(idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK) && !localaddr_f && \ - is_eq_in6_addr(&(pkt_ns->nd_ns_target), &(idata.srcaddr))){ - if(send_neighbor_advert(&idata, idata.pfd, pktdata) == -1){ - puts("Error sending Neighbor Advertisement"); - exit(EXIT_FAILURE); - } - } - } - else if( (pkt_icmp6->icmp6_type == ICMP6_ECHO_REPLY) || (pkt_icmp6->icmp6_type == ICMP6_TIME_EXCEEDED)){ - if( (pkt_end - (unsigned char *) pkt_icmp6) < sizeof(struct icmp6_hdr)){ - continue; - } - /* - Do a preliminar validation check on the ICMPv6 packet (packet size, Source Address, - and Destination Address). - */ - if(!valid_icmp6_response(&idata, pkthdr, pktdata)){ - continue; - } - - switch(pkt_icmp6->icmp6_type){ - case ICMP6_ECHO_REPLY: - gotresp_f= TRUE; - - if(resp_f) - print_icmp6_echo(&idata, pkthdr, pktdata); - - break; - - case ICMP6_TIME_EXCEEDED: - gotresp_f= TRUE; - - if(resp_f) - print_icmp6_timed(&idata, pkthdr, pktdata); - - break; - } - } - } - } - } - } - - exit(EXIT_SUCCESS); - } - - exit(EXIT_SUCCESS); + /* Read a packet (Echo Reply, ICMPv6 Error, or Neighbor Solicitation) */ + if ((r = pcap_next_ex(idata.pfd, &pkthdr, &pktdata)) == -1) { + printf("pcap_next_ex(): %s", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } + else if (r == 1 && pktdata != NULL) { + pkt_ether = (struct ether_header *)pktdata; + pkt_ipv6 = (struct ip6_hdr *)((char *)pkt_ether + idata.linkhsize); + pkt_icmp6 = (struct icmp6_hdr *)((char *)pkt_ipv6 + sizeof(struct ip6_hdr)); + pkt_ns = (struct nd_neighbor_solicit *)pkt_icmp6; + pkt_end = (unsigned char *)pktdata + pkthdr->caplen; + + if ((pkt_end - pktdata) < (idata.linkhsize + MIN_IPV6_HLEN)) + continue; + + if (pkt_ipv6->ip6_nxt == IPPROTO_ICMPV6) { + if (idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK) && + pkt_icmp6->icmp6_type == ND_NEIGHBOR_SOLICIT) { + if ((pkt_end - (unsigned char *)pkt_ns) < sizeof(struct nd_neighbor_solicit)) + continue; + /* + If the addresses that we're using are not actually configured on the local system + (i.e., they are "spoofed", we must check whether it is a Neighbor Solicitation for + one of our addresses, and respond with a Neighbor Advertisement. Otherwise, the + kernel will take care of that. + */ + if (idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK) && !localaddr_f && + is_eq_in6_addr(&(pkt_ns->nd_ns_target), &(idata.srcaddr))) { + if (send_neighbor_advert(&idata, idata.pfd, pktdata) == -1) { + puts("Error sending Neighbor Advertisement"); + exit(EXIT_FAILURE); + } + } + } + else if ((pkt_icmp6->icmp6_type == ICMP6_ECHO_REPLY) || + (pkt_icmp6->icmp6_type == ICMP6_TIME_EXCEEDED)) { + if ((pkt_end - (unsigned char *)pkt_icmp6) < sizeof(struct icmp6_hdr)) { + continue; + } + /* + Do a preliminar validation check on the ICMPv6 packet (packet size, Source Address, + and Destination Address). + */ + if (!valid_icmp6_response(&idata, pkthdr, pktdata)) { + continue; + } + + switch (pkt_icmp6->icmp6_type) { + case ICMP6_ECHO_REPLY: + gotresp_f = TRUE; + + if (resp_f) + print_icmp6_echo(&idata, pkthdr, pktdata); + + break; + + case ICMP6_TIME_EXCEEDED: + gotresp_f = TRUE; + + if (resp_f) + print_icmp6_timed(&idata, pkthdr, pktdata); + + break; + } + } + } + } + } + } + + exit(EXIT_SUCCESS); + } + + exit(EXIT_SUCCESS); } - /* * Function: print_icmp6_echo() * * Print information about a received ICMPv6 Echo Response packet */ -void print_icmp6_echo(struct iface_data *idata, struct pcap_pkthdr *pkthdr, const u_char *pktdata){ - struct ip6_hdr *pkt_ipv6; - time_t rtt; - - pkt_ipv6 = (struct ip6_hdr *) (pktdata + idata->linkhsize); - - if(inet_ntop(AF_INET6, &(pkt_ipv6->ip6_src), pv6addr, sizeof(pv6addr)) == NULL){ - puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); - exit(EXIT_FAILURE); - } - - rtt= time(NULL) - *(time_t *) ( (unsigned char *) pkt_ipv6 + (sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr))); - printf("ICMPv6 echo Reply from %s", pv6addr); - if(rtt > 0) - printf(" (RTT: %u second%s)\n", (uint32_t)rtt, (rtt>1)?"s":""); - else - puts(" (RTT: < 1 second)"); +void print_icmp6_echo(struct iface_data *idata, struct pcap_pkthdr *pkthdr, const u_char *pktdata) { + struct ip6_hdr *pkt_ipv6; + time_t rtt; + + pkt_ipv6 = (struct ip6_hdr *)(pktdata + idata->linkhsize); + + if (inet_ntop(AF_INET6, &(pkt_ipv6->ip6_src), pv6addr, sizeof(pv6addr)) == NULL) { + puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); + exit(EXIT_FAILURE); + } + + rtt = time(NULL) - *(time_t *)((unsigned char *)pkt_ipv6 + (sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr))); + printf("ICMPv6 echo Reply from %s", pv6addr); + if (rtt > 0) + printf(" (RTT: %u second%s)\n", (uint32_t)rtt, (rtt > 1) ? "s" : ""); + else + puts(" (RTT: < 1 second)"); } - /* * Function: print_icmp6_timed() * * Print information about a received ICMPv6 Time Exceeded error message */ -void print_icmp6_timed(struct iface_data *idata, struct pcap_pkthdr *pkthdr, const u_char *pktdata){ - struct ip6_hdr *pkt_ipv6, *pkt_ipv6_ipv6; - struct icmp6_hdr *pkt_icmp6, *pkt_icmp6_icmp6; - struct ip6_ext *pkt_ext; - struct ip6_frag *pkt_fh_fh; - uint8_t pkt_prev_nh; - time_t rtt; - - pkt_ipv6 = (struct ip6_hdr *) (pktdata + idata->linkhsize); - pkt_icmp6= (struct icmp6_hdr *) ((unsigned char *) pkt_ipv6 + sizeof(struct ip6_hdr)); - pkt_ipv6_ipv6= (struct ip6_hdr *) ((unsigned char *)pkt_icmp6+ sizeof(struct icmp6_hdr)); - pkt_fh_fh= NULL; - pkt_ext= (struct ip6_ext *) ((unsigned char *)pkt_ipv6_ipv6 + sizeof(struct ip6_hdr)); - pkt_prev_nh= (pkt_ipv6_ipv6->ip6_nxt); - - while(pkt_prev_nh != IPPROTO_ICMPV6 && \ - ( (unsigned char *)pkt_ext + (pkt_ext->ip6e_len * 8 + 1)) < pkt_end){ - - if(pkt_prev_nh == IPPROTO_FRAGMENT) - pkt_fh_fh= (struct ip6_frag *) pkt_ext; - - pkt_prev_nh= pkt_ext->ip6e_nxt; - pkt_ext= (struct ip6_ext *) ( (unsigned char *)pkt_ext + ((pkt_ext->ip6e_len + 1) * 8)); - } - - if(pkt_prev_nh == IPPROTO_ICMPV6){ - pkt_icmp6_icmp6= (struct icmp6_hdr *) pkt_ext; - - if( ((unsigned char *) pkt_icmp6_icmp6 + (sizeof(struct icmp6_hdr)+ sizeof(struct ip6_hdr)+ \ - sizeof(struct ip6_frag)+sizeof(struct icmp6_hdr))) > pkt_end) - return; - } - else{ - return; - } - - if(pkt_fh_fh == NULL) - return; - - /* - * We can only check the embedded ICMPv6 header if the embedded fragment is the first fragment of - * a packet - */ - if(ntohs(pkt_fh_fh->ip6f_offlg & IP6F_OFF_MASK) == 0){ - if(pkt_icmp6_icmp6->icmp6_type != ICMP6_ECHO_REQUEST){ - return; - } - - if(pkt_icmp6_icmp6->icmp6_data16[0] != htons(getpid())){ - return; - } - } - else{ - return; - } - - if(inet_ntop(AF_INET6, &(pkt_ipv6->ip6_src), pv6addr, sizeof(pv6addr)) == NULL){ - puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); - exit(EXIT_FAILURE); - } - - if(tstamp_f){ - pkt_ptr= ((unsigned char *) pkt_icmp6_icmp6+ sizeof(struct icmp6_hdr)); - - /* Verify our "checksum" */ - if(*(uint32_t *)(pkt_ptr+sizeof(time_t)) != ((*(uint32_t *)pkt_ptr) ^ 0xabcdabcd)){ - return; - } - - rtt= time(NULL) - *(time_t *) pkt_ptr; - - printf("Response from %s: ICMPv6 Time Exceeded error message (Reassembly timeout: %lu seconds)\n", pv6addr, \ - (LUI) rtt); - } - else - printf("Response from %s: ICMPv6 Time Exceeded error message\n", pv6addr); +void print_icmp6_timed(struct iface_data *idata, struct pcap_pkthdr *pkthdr, const u_char *pktdata) { + struct ip6_hdr *pkt_ipv6, *pkt_ipv6_ipv6; + struct icmp6_hdr *pkt_icmp6, *pkt_icmp6_icmp6; + struct ip6_ext *pkt_ext; + struct ip6_frag *pkt_fh_fh; + uint8_t pkt_prev_nh; + time_t rtt; + + pkt_ipv6 = (struct ip6_hdr *)(pktdata + idata->linkhsize); + pkt_icmp6 = (struct icmp6_hdr *)((unsigned char *)pkt_ipv6 + sizeof(struct ip6_hdr)); + pkt_ipv6_ipv6 = (struct ip6_hdr *)((unsigned char *)pkt_icmp6 + sizeof(struct icmp6_hdr)); + pkt_fh_fh = NULL; + pkt_ext = (struct ip6_ext *)((unsigned char *)pkt_ipv6_ipv6 + sizeof(struct ip6_hdr)); + pkt_prev_nh = (pkt_ipv6_ipv6->ip6_nxt); + + while (pkt_prev_nh != IPPROTO_ICMPV6 && ((unsigned char *)pkt_ext + (pkt_ext->ip6e_len * 8 + 1)) < pkt_end) { + + if (pkt_prev_nh == IPPROTO_FRAGMENT) + pkt_fh_fh = (struct ip6_frag *)pkt_ext; + + pkt_prev_nh = pkt_ext->ip6e_nxt; + pkt_ext = (struct ip6_ext *)((unsigned char *)pkt_ext + ((pkt_ext->ip6e_len + 1) * 8)); + } + + if (pkt_prev_nh == IPPROTO_ICMPV6) { + pkt_icmp6_icmp6 = (struct icmp6_hdr *)pkt_ext; + + if (((unsigned char *)pkt_icmp6_icmp6 + (sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr) + + sizeof(struct ip6_frag) + sizeof(struct icmp6_hdr))) > pkt_end) + return; + } + else { + return; + } + + if (pkt_fh_fh == NULL) + return; + + /* + * We can only check the embedded ICMPv6 header if the embedded fragment is the first fragment of + * a packet + */ + if (ntohs(pkt_fh_fh->ip6f_offlg & IP6F_OFF_MASK) == 0) { + if (pkt_icmp6_icmp6->icmp6_type != ICMP6_ECHO_REQUEST) { + return; + } + + if (pkt_icmp6_icmp6->icmp6_data16[0] != htons(getpid())) { + return; + } + } + else { + return; + } + + if (inet_ntop(AF_INET6, &(pkt_ipv6->ip6_src), pv6addr, sizeof(pv6addr)) == NULL) { + puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); + exit(EXIT_FAILURE); + } + + if (tstamp_f) { + pkt_ptr = ((unsigned char *)pkt_icmp6_icmp6 + sizeof(struct icmp6_hdr)); + + /* Verify our "checksum" */ + if (*(uint32_t *)(pkt_ptr + sizeof(time_t)) != ((*(uint32_t *)pkt_ptr) ^ 0xabcdabcd)) { + return; + } + + rtt = time(NULL) - *(time_t *)pkt_ptr; + + printf("Response from %s: ICMPv6 Time Exceeded error message (Reassembly timeout: %lu seconds)\n", pv6addr, + (LUI)rtt); + } + else + printf("Response from %s: ICMPv6 Time Exceeded error message\n", pv6addr); } - - /* * Function: process_icmp6_echoinfo() * * Process ICMPv6 echo reply messages received in response to our probe packets that investigate * the fragment reassembly policy of a target */ -void process_icmp6_echo(struct iface_data *idata, struct pcap_pkthdr *pkthdr, const u_char *pktdata, unsigned char *test, unsigned int *responses){ - struct ip6_hdr *pkt_ipv6; - struct icmp6_hdr *pkt_icmp6; - - pkt_ipv6 = (struct ip6_hdr *) (pktdata + idata->linkhsize); - pkt_icmp6= (struct icmp6_hdr *) ((unsigned char *) pkt_ipv6 + sizeof(struct ip6_hdr)); - - if(test_frag_pattern( ((unsigned char *) pkt_icmp6 + sizeof(struct icmp6_hdr)), FRAG_BLOCK_SIZE, block1)){ - if(!valid_icmp6_response2(idata, pkthdr, pktdata, sizeof(struct ip6_hdr) + \ - sizeof(struct icmp6_hdr)+minfragsize*2-overlap)){ - return; - } - - if(test_frag_pattern( (unsigned char *)pkt_icmp6+(sizeof(struct icmp6_hdr) + minfragsize-overlap), \ - overlap, block1)){ - test[0]= FIRST_COPY; - } - else if(test_frag_pattern((unsigned char *)pkt_icmp6+(sizeof(struct icmp6_hdr)+minfragsize-overlap), \ - overlap, block6)){ - test[0]= LAST_COPY; - } - else{ - test[0]= UNKNOWN_COPY; - } - - (*responses)++; - } - else if(test_frag_pattern( ((unsigned char *) pkt_icmp6 + sizeof(struct icmp6_hdr)), FRAG_BLOCK_SIZE, block2)){ - if(!valid_icmp6_response2(idata, pkthdr, pktdata, sizeof(struct ip6_hdr) + \ - sizeof(struct icmp6_hdr)+minfragsize * 3-overlap)){ - return; - } - - if(test_frag_pattern((unsigned char *)pkt_icmp6+(sizeof(struct icmp6_hdr)+minfragsize-overlap), overlap, block2)){ - test[1]= FIRST_COPY; - } - else if(test_frag_pattern((unsigned char *)pkt_icmp6+(sizeof(struct icmp6_hdr)+minfragsize-overlap), \ - overlap, block7)){ - test[1]= LAST_COPY; - } - else{ - test[1]= UNKNOWN_COPY; - } - - (*responses)++; - } - else if(test_frag_pattern( ((unsigned char *) pkt_icmp6 + sizeof(struct icmp6_hdr)), FRAG_BLOCK_SIZE, block3)){ - if(!valid_icmp6_response2(idata, pkthdr, pktdata, sizeof(struct ip6_hdr) + \ - sizeof(struct icmp6_hdr)+minfragsize * 3-overlap)){ - return; - } - - if(test_frag_pattern((unsigned char *)pkt_icmp6+(sizeof(struct icmp6_hdr)+minfragsize * 2-overlap),\ - overlap, block6)){ - test[2]= FIRST_COPY; - } - else if(test_frag_pattern((unsigned char *)pkt_icmp6+(sizeof(struct icmp6_hdr)+minfragsize * 2-overlap), \ - overlap, block7)){ - test[2]= LAST_COPY; - } - else{ - test[2]= UNKNOWN_COPY; - } - - (*responses)++; - } - else if(test_frag_pattern( ((unsigned char *) pkt_icmp6 + sizeof(struct icmp6_hdr)), FRAG_BLOCK_SIZE, block4)){ - if(!valid_icmp6_response2(idata, pkthdr, pktdata, sizeof(struct ip6_hdr) + \ - sizeof(struct icmp6_hdr)+minfragsize * 4)){ - return; - } - - if(test_frag_pattern((unsigned char *)pkt_icmp6+(sizeof(struct icmp6_hdr)+minfragsize * 2), \ - minfragsize, block6)){ - test[3]= FIRST_COPY; - } - else if(test_frag_pattern((unsigned char *)pkt_icmp6+(sizeof(struct icmp6_hdr)+minfragsize * 2), \ - minfragsize, block7)){ - test[3]= LAST_COPY; - } - else{ - test[3]= UNKNOWN_COPY; - } - - (*responses)++; - } - else if(test_frag_pattern( ((unsigned char *) pkt_icmp6 + sizeof(struct icmp6_hdr)), FRAG_BLOCK_SIZE, block5)){ - if(!valid_icmp6_response2(idata, pkthdr, pktdata, sizeof(struct ip6_hdr) + \ - sizeof(struct icmp6_hdr)+minfragsize * 4 - overlap)){ - return; - } - - if(test_frag_pattern((unsigned char *)pkt_icmp6+(sizeof(struct icmp6_hdr)+minfragsize * 2), \ - minfragsize, block6)){ - test[4]= FIRST_COPY; - } - else if(test_frag_pattern((unsigned char *)pkt_icmp6+(sizeof(struct icmp6_hdr)+minfragsize * 2), \ - minfragsize, block7)){ - test[4]= LAST_COPY; - } - else{ - test[4]= UNKNOWN_COPY; - } - - (*responses)++; - } - else{ - if(idata->verbose_f) - puts("ICMPv6 Echo Reply for unknown probe type"); - } - +void process_icmp6_echo(struct iface_data *idata, struct pcap_pkthdr *pkthdr, const u_char *pktdata, + unsigned char *test, unsigned int *responses) { + struct ip6_hdr *pkt_ipv6; + struct icmp6_hdr *pkt_icmp6; + + pkt_ipv6 = (struct ip6_hdr *)(pktdata + idata->linkhsize); + pkt_icmp6 = (struct icmp6_hdr *)((unsigned char *)pkt_ipv6 + sizeof(struct ip6_hdr)); + + if (test_frag_pattern(((unsigned char *)pkt_icmp6 + sizeof(struct icmp6_hdr)), FRAG_BLOCK_SIZE, block1)) { + if (!valid_icmp6_response2(idata, pkthdr, pktdata, + sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) + minfragsize * 2 - overlap)) { + return; + } + + if (test_frag_pattern((unsigned char *)pkt_icmp6 + (sizeof(struct icmp6_hdr) + minfragsize - overlap), overlap, + block1)) { + test[0] = FIRST_COPY; + } + else if (test_frag_pattern((unsigned char *)pkt_icmp6 + (sizeof(struct icmp6_hdr) + minfragsize - overlap), + overlap, block6)) { + test[0] = LAST_COPY; + } + else { + test[0] = UNKNOWN_COPY; + } + + (*responses)++; + } + else if (test_frag_pattern(((unsigned char *)pkt_icmp6 + sizeof(struct icmp6_hdr)), FRAG_BLOCK_SIZE, block2)) { + if (!valid_icmp6_response2(idata, pkthdr, pktdata, + sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) + minfragsize * 3 - overlap)) { + return; + } + + if (test_frag_pattern((unsigned char *)pkt_icmp6 + (sizeof(struct icmp6_hdr) + minfragsize - overlap), overlap, + block2)) { + test[1] = FIRST_COPY; + } + else if (test_frag_pattern((unsigned char *)pkt_icmp6 + (sizeof(struct icmp6_hdr) + minfragsize - overlap), + overlap, block7)) { + test[1] = LAST_COPY; + } + else { + test[1] = UNKNOWN_COPY; + } + + (*responses)++; + } + else if (test_frag_pattern(((unsigned char *)pkt_icmp6 + sizeof(struct icmp6_hdr)), FRAG_BLOCK_SIZE, block3)) { + if (!valid_icmp6_response2(idata, pkthdr, pktdata, + sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) + minfragsize * 3 - overlap)) { + return; + } + + if (test_frag_pattern((unsigned char *)pkt_icmp6 + (sizeof(struct icmp6_hdr) + minfragsize * 2 - overlap), + overlap, block6)) { + test[2] = FIRST_COPY; + } + else if (test_frag_pattern((unsigned char *)pkt_icmp6 + (sizeof(struct icmp6_hdr) + minfragsize * 2 - overlap), + overlap, block7)) { + test[2] = LAST_COPY; + } + else { + test[2] = UNKNOWN_COPY; + } + + (*responses)++; + } + else if (test_frag_pattern(((unsigned char *)pkt_icmp6 + sizeof(struct icmp6_hdr)), FRAG_BLOCK_SIZE, block4)) { + if (!valid_icmp6_response2(idata, pkthdr, pktdata, + sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) + minfragsize * 4)) { + return; + } + + if (test_frag_pattern((unsigned char *)pkt_icmp6 + (sizeof(struct icmp6_hdr) + minfragsize * 2), minfragsize, + block6)) { + test[3] = FIRST_COPY; + } + else if (test_frag_pattern((unsigned char *)pkt_icmp6 + (sizeof(struct icmp6_hdr) + minfragsize * 2), + minfragsize, block7)) { + test[3] = LAST_COPY; + } + else { + test[3] = UNKNOWN_COPY; + } + + (*responses)++; + } + else if (test_frag_pattern(((unsigned char *)pkt_icmp6 + sizeof(struct icmp6_hdr)), FRAG_BLOCK_SIZE, block5)) { + if (!valid_icmp6_response2(idata, pkthdr, pktdata, + sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) + minfragsize * 4 - overlap)) { + return; + } + + if (test_frag_pattern((unsigned char *)pkt_icmp6 + (sizeof(struct icmp6_hdr) + minfragsize * 2), minfragsize, + block6)) { + test[4] = FIRST_COPY; + } + else if (test_frag_pattern((unsigned char *)pkt_icmp6 + (sizeof(struct icmp6_hdr) + minfragsize * 2), + minfragsize, block7)) { + test[4] = LAST_COPY; + } + else { + test[4] = UNKNOWN_COPY; + } + + (*responses)++; + } + else { + if (idata->verbose_f) + puts("ICMPv6 Echo Reply for unknown probe type"); + } } - /* * Function: process_icmp6_timed() * * Process ICMPv6 Time Exceeded messages received in response to our probe packets that investigate * the fragment reassembly policy of a target */ -void process_icmp6_timed(struct iface_data *idata, struct pcap_pkthdr *pkthdr, const u_char *pktdata, unsigned char *test){ - struct ip6_hdr *pkt_ipv6, *pkt_ipv6_ipv6; - struct icmp6_hdr *pkt_icmp6, *pkt_icmp6_icmp6; - struct ip6_ext *pkt_ext; - struct ip6_frag *pkt_fh_fh; - uint8_t pkt_prev_nh; - - pkt_ipv6 = (struct ip6_hdr *) (pktdata + idata->linkhsize); - pkt_icmp6= (struct icmp6_hdr *) ((unsigned char *) pkt_ipv6 + sizeof(struct ip6_hdr)); - pkt_ipv6_ipv6= (struct ip6_hdr *) ((unsigned char *)pkt_icmp6+ sizeof(struct icmp6_hdr)); - pkt_fh_fh= NULL; - pkt_ext= (struct ip6_ext *) ((unsigned char *)pkt_ipv6_ipv6 + sizeof(struct ip6_hdr)); - pkt_prev_nh= (pkt_ipv6_ipv6->ip6_nxt); - - while(pkt_prev_nh != IPPROTO_ICMPV6 && \ - ( (unsigned char *)pkt_ext + (pkt_ext->ip6e_len * 8 + 1)) < pkt_end){ - - if(pkt_prev_nh == IPPROTO_FRAGMENT) - pkt_fh_fh= (struct ip6_frag *) pkt_ext; - - pkt_prev_nh= pkt_ext->ip6e_nxt; - pkt_ext= (struct ip6_ext *) ( (unsigned char *)pkt_ext + ((pkt_ext->ip6e_len + 1) * 8)); - } - - if(pkt_prev_nh == IPPROTO_ICMPV6){ - pkt_icmp6_icmp6= (struct icmp6_hdr *) pkt_ext; - - if( ((unsigned char *) pkt_icmp6_icmp6 + (sizeof(struct icmp6_hdr)+ sizeof(struct ip6_hdr)+ \ - sizeof(struct ip6_frag)+sizeof(struct icmp6_hdr))) > pkt_end) - return; - } - else{ - return; - } - - if(pkt_fh_fh == NULL) - return; - - /* - * We can only check the embedded ICMPv6 header if the embedded fragment is the first fragment of - * a packet - */ - if(ntohs(pkt_fh_fh->ip6f_offlg & IP6F_OFF_MASK) == 0){ - if(pkt_icmp6_icmp6->icmp6_type != ICMP6_ECHO_REQUEST){ - return; - } - - if(pkt_icmp6_icmp6->icmp6_data16[0] != htons(getpid())){ - return; - } - } - else{ - return; - } - - if(test_frag_pattern( ((unsigned char *) pkt_icmp6_icmp6 + sizeof(struct icmp6_hdr)), FRAG_BLOCK_SIZE, block1)){ - if(!valid_icmp6_response2(idata, pkthdr, pktdata, sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) + \ - sizeof(struct ip6_frag) + sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr)+minfragsize)){ - - return; - } - else{ - test[0]= TIME_EXCEEDED; - } - - } - else if(test_frag_pattern( ((unsigned char *) pkt_icmp6_icmp6 + sizeof(struct icmp6_hdr)), FRAG_BLOCK_SIZE, block2)){ - if(!valid_icmp6_response2(idata, pkthdr, pktdata, sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) + \ - sizeof(struct ip6_frag) + sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr)+minfragsize)){ - return; - } - - test[1]= TIME_EXCEEDED; - } - else if(test_frag_pattern( ((unsigned char *) pkt_icmp6_icmp6 + sizeof(struct icmp6_hdr)), FRAG_BLOCK_SIZE, block3)){ - if(!valid_icmp6_response2(idata, pkthdr, pktdata, sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) + \ - sizeof(struct ip6_frag) + sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr)+minfragsize)){ - return; - } - - test[2]= TIME_EXCEEDED; - } - else if(test_frag_pattern( ((unsigned char *) pkt_icmp6_icmp6 + sizeof(struct icmp6_hdr)), FRAG_BLOCK_SIZE, block4)){ - if(!valid_icmp6_response2(idata, pkthdr, pktdata, sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) + \ - sizeof(struct ip6_frag) + sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr)+minfragsize)){ - return; - } - - test[3]= TIME_EXCEEDED; - } - else if(test_frag_pattern( ((unsigned char *) pkt_icmp6_icmp6 + sizeof(struct icmp6_hdr)), FRAG_BLOCK_SIZE, block5)){ - if(!valid_icmp6_response2(idata, pkthdr, pktdata, sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) + \ - sizeof(struct ip6_frag) + sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr)+minfragsize)){ - return; - } - - test[4]= TIME_EXCEEDED; - } - else{ - test[4]= UNKNOWN_COPY; - } - +void process_icmp6_timed(struct iface_data *idata, struct pcap_pkthdr *pkthdr, const u_char *pktdata, + unsigned char *test) { + struct ip6_hdr *pkt_ipv6, *pkt_ipv6_ipv6; + struct icmp6_hdr *pkt_icmp6, *pkt_icmp6_icmp6; + struct ip6_ext *pkt_ext; + struct ip6_frag *pkt_fh_fh; + uint8_t pkt_prev_nh; + + pkt_ipv6 = (struct ip6_hdr *)(pktdata + idata->linkhsize); + pkt_icmp6 = (struct icmp6_hdr *)((unsigned char *)pkt_ipv6 + sizeof(struct ip6_hdr)); + pkt_ipv6_ipv6 = (struct ip6_hdr *)((unsigned char *)pkt_icmp6 + sizeof(struct icmp6_hdr)); + pkt_fh_fh = NULL; + pkt_ext = (struct ip6_ext *)((unsigned char *)pkt_ipv6_ipv6 + sizeof(struct ip6_hdr)); + pkt_prev_nh = (pkt_ipv6_ipv6->ip6_nxt); + + while (pkt_prev_nh != IPPROTO_ICMPV6 && ((unsigned char *)pkt_ext + (pkt_ext->ip6e_len * 8 + 1)) < pkt_end) { + + if (pkt_prev_nh == IPPROTO_FRAGMENT) + pkt_fh_fh = (struct ip6_frag *)pkt_ext; + + pkt_prev_nh = pkt_ext->ip6e_nxt; + pkt_ext = (struct ip6_ext *)((unsigned char *)pkt_ext + ((pkt_ext->ip6e_len + 1) * 8)); + } + + if (pkt_prev_nh == IPPROTO_ICMPV6) { + pkt_icmp6_icmp6 = (struct icmp6_hdr *)pkt_ext; + + if (((unsigned char *)pkt_icmp6_icmp6 + (sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr) + + sizeof(struct ip6_frag) + sizeof(struct icmp6_hdr))) > pkt_end) + return; + } + else { + return; + } + + if (pkt_fh_fh == NULL) + return; + + /* + * We can only check the embedded ICMPv6 header if the embedded fragment is the first fragment of + * a packet + */ + if (ntohs(pkt_fh_fh->ip6f_offlg & IP6F_OFF_MASK) == 0) { + if (pkt_icmp6_icmp6->icmp6_type != ICMP6_ECHO_REQUEST) { + return; + } + + if (pkt_icmp6_icmp6->icmp6_data16[0] != htons(getpid())) { + return; + } + } + else { + return; + } + + if (test_frag_pattern(((unsigned char *)pkt_icmp6_icmp6 + sizeof(struct icmp6_hdr)), FRAG_BLOCK_SIZE, block1)) { + if (!valid_icmp6_response2(idata, pkthdr, pktdata, + sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) + sizeof(struct ip6_frag) + + sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) + minfragsize)) { + + return; + } + else { + test[0] = TIME_EXCEEDED; + } + } + else if (test_frag_pattern(((unsigned char *)pkt_icmp6_icmp6 + sizeof(struct icmp6_hdr)), FRAG_BLOCK_SIZE, + block2)) { + if (!valid_icmp6_response2(idata, pkthdr, pktdata, + sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) + sizeof(struct ip6_frag) + + sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) + minfragsize)) { + return; + } + + test[1] = TIME_EXCEEDED; + } + else if (test_frag_pattern(((unsigned char *)pkt_icmp6_icmp6 + sizeof(struct icmp6_hdr)), FRAG_BLOCK_SIZE, + block3)) { + if (!valid_icmp6_response2(idata, pkthdr, pktdata, + sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) + sizeof(struct ip6_frag) + + sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) + minfragsize)) { + return; + } + + test[2] = TIME_EXCEEDED; + } + else if (test_frag_pattern(((unsigned char *)pkt_icmp6_icmp6 + sizeof(struct icmp6_hdr)), FRAG_BLOCK_SIZE, + block4)) { + if (!valid_icmp6_response2(idata, pkthdr, pktdata, + sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) + sizeof(struct ip6_frag) + + sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) + minfragsize)) { + return; + } + + test[3] = TIME_EXCEEDED; + } + else if (test_frag_pattern(((unsigned char *)pkt_icmp6_icmp6 + sizeof(struct icmp6_hdr)), FRAG_BLOCK_SIZE, + block5)) { + if (!valid_icmp6_response2(idata, pkthdr, pktdata, + sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) + sizeof(struct ip6_frag) + + sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) + minfragsize)) { + return; + } + + test[4] = TIME_EXCEEDED; + } + else { + test[4] = UNKNOWN_COPY; + } } - /* * Function: send_fragment2() * * Sends an IPv6 for evaluating the fragment reassembly policy */ -int send_fragment2(struct iface_data *idata, uint16_t ip6len, unsigned int id, unsigned int offset, unsigned int fsize, unsigned int order, \ - char *block){ - unsigned char *ptrend; - - ethernet= (struct ether_header *) buffer; - dlt_null= (struct dlt_null *) buffer; - v6buffer = buffer + idata->linkhsize; - ipv6 = (struct ip6_hdr *) v6buffer; - fsize= (fsize>>3) << 3; - - if(idata->type == DLT_EN10MB){ - ethernet->ether_type = htons(ETHERTYPE_IPV6); - - if(!(idata->flags & IFACE_LOOPBACK)){ - ethernet->src = idata->hsrcaddr; - ethernet->dst = idata->hdstaddr; - } - } - else if(idata->type == DLT_NULL){ - dlt_null->family= PF_INET6; - } -#if defined (__OpenBSD__) - else if(idata->type == DLT_LOOP){ - dlt_null->family= htonl(PF_INET6); - } +int send_fragment2(struct iface_data *idata, uint16_t ip6len, unsigned int id, unsigned int offset, unsigned int fsize, + unsigned int order, char *block) { + unsigned char *ptrend; + + ethernet = (struct ether_header *)buffer; + dlt_null = (struct dlt_null *)buffer; + v6buffer = buffer + idata->linkhsize; + ipv6 = (struct ip6_hdr *)v6buffer; + fsize = (fsize >> 3) << 3; + + if (idata->type == DLT_EN10MB) { + ethernet->ether_type = htons(ETHERTYPE_IPV6); + + if (!(idata->flags & IFACE_LOOPBACK)) { + ethernet->src = idata->hsrcaddr; + ethernet->dst = idata->hdstaddr; + } + } + else if (idata->type == DLT_NULL) { + dlt_null->family = PF_INET6; + } +#if defined(__OpenBSD__) + else if (idata->type == DLT_LOOP) { + dlt_null->family = htonl(PF_INET6); + } #endif - ipv6->ip6_flow=0; - ipv6->ip6_vfc= 0x60; - ipv6->ip6_hlim= hoplimit; - ipv6->ip6_src= idata->srcaddr; - ipv6->ip6_dst= idata->dstaddr; - - prev_nh = (unsigned char *) &(ipv6->ip6_nxt); - - ptr = (unsigned char *) v6buffer + MIN_IPV6_HLEN; - - /* Check that we are able to send the Unfragmentable Part, together with a - Fragment Header and a chunk data over our link layer - */ - if( (ptr+sizeof(struct ip6_frag)+fsize) > (v6buffer+idata->mtu)){ - puts("Unfragmentable part too large for current MTU"); - return(-1); - } - - /* We prepare a separete Fragment Header, but we do not include it in the packet to be sent. - This Fragment Header will be used (an assembled with the rest of the packet by the - send_packet() function. - */ - fh= (struct ip6_frag *) ptr; - memset(ptr, 0, FRAG_HDR_SIZE); - - fh->ip6f_ident= htonl(id); + ipv6->ip6_flow = 0; + ipv6->ip6_vfc = 0x60; + ipv6->ip6_hlim = hoplimit; + ipv6->ip6_src = idata->srcaddr; + ipv6->ip6_dst = idata->dstaddr; - if(order == LAST_FRAGMENT || order==ATOMIC_FRAGMENT){ - m=0; - } - else{ - m=IP6F_MORE_FRAG; - } + prev_nh = (unsigned char *)&(ipv6->ip6_nxt); + + ptr = (unsigned char *)v6buffer + MIN_IPV6_HLEN; + + /* Check that we are able to send the Unfragmentable Part, together with a + Fragment Header and a chunk data over our link layer + */ + if ((ptr + sizeof(struct ip6_frag) + fsize) > (v6buffer + idata->mtu)) { + puts("Unfragmentable part too large for current MTU"); + return (-1); + } + + /* We prepare a separete Fragment Header, but we do not include it in the packet to be sent. + This Fragment Header will be used (an assembled with the rest of the packet by the + send_packet() function. + */ + fh = (struct ip6_frag *)ptr; + memset(ptr, 0, FRAG_HDR_SIZE); + + fh->ip6f_ident = htonl(id); + + if (order == LAST_FRAGMENT || order == ATOMIC_FRAGMENT) { + m = 0; + } + else { + m = IP6F_MORE_FRAG; + } + + if (order == FIRST_FRAGMENT || order == ATOMIC_FRAGMENT) + offset = 0; + + fh->ip6f_offlg = (htons(offset) & IP6F_OFF_MASK) | m; + + *prev_nh = IPPROTO_FRAGMENT; + prev_nh = (unsigned char *)fh; + + ptr += sizeof(struct ip6_frag); + + *prev_nh = IPPROTO_ICMPV6; + + if (order == FIRST_FRAGMENT || order == ATOMIC_FRAGMENT) { + if ((ptr + sizeof(struct icmp6_hdr)) > (v6buffer + idata->max_packet_size)) { + puts("Packet too large while inserting ICMPv6 header"); + return (-1); + } + + icmp6 = (struct icmp6_hdr *)ptr; + icmp6->icmp6_type = ICMP6_ECHO_REQUEST; + icmp6->icmp6_code = 0; + icmp6->icmp6_cksum = 0; + icmp6->icmp6_data16[0] = htons(getpid()); /* Identifier */ + icmp6->icmp6_data16[1] = htons(random()); /* Sequence Number */ + + ptr += sizeof(struct icmp6_hdr); + + for (i = 0; i < (fsize / 8); i++) { + memcpy(ptr, block, FRAG_BLOCK_SIZE); + ptr += FRAG_BLOCK_SIZE; + } + + ptrend = ptr; + + for (i = 0; i < (ip6len - sizeof(struct icmp6_hdr) - fsize) / 8; i++) { + memcpy(ptr, block, FRAG_BLOCK_SIZE); + ptr += FRAG_BLOCK_SIZE; + } + + /* Length of the reassembled fragment */ + ipv6->ip6_plen = htons(ip6len); + icmp6->icmp6_cksum = in_chksum(v6buffer, icmp6, ptr - ((unsigned char *)icmp6), IPPROTO_ICMPV6); + + ptr = ptrend; + + /* Length of the current fragment */ + ipv6->ip6_plen = htons(ptr - (v6buffer + MIN_IPV6_HLEN)); + } + else { + if ((ptr + fsize) > (v6buffer + idata->max_packet_size)) { + puts("Packet too large while inserting timestamp"); + return (-1); + } + + for (i = 0; i < (fsize / 8); i++) { + memcpy(ptr, block, FRAG_BLOCK_SIZE); + ptr += FRAG_BLOCK_SIZE; + } + + ipv6->ip6_plen = htons(ptr - (v6buffer + MIN_IPV6_HLEN)); + } + + if ((nw = pcap_inject(idata->pfd, buffer, ptr - buffer)) == -1) { + printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); + return (-1); + } + + if (nw != (ptr - buffer)) { + printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, (LUI)(ptr - buffer)); + return (-1); + } - if(order==FIRST_FRAGMENT || order==ATOMIC_FRAGMENT) - offset=0; - - fh->ip6f_offlg = (htons(offset) & IP6F_OFF_MASK) | m; - - *prev_nh = IPPROTO_FRAGMENT; - prev_nh = (unsigned char *) fh; - - ptr+= sizeof(struct ip6_frag); - - *prev_nh = IPPROTO_ICMPV6; - - - if(order == FIRST_FRAGMENT || order==ATOMIC_FRAGMENT){ - if((ptr+ sizeof(struct icmp6_hdr)) > (v6buffer+idata->max_packet_size)){ - puts("Packet too large while inserting ICMPv6 header"); - return(-1); - } - - icmp6 = (struct icmp6_hdr *) ptr; - icmp6->icmp6_type = ICMP6_ECHO_REQUEST; - icmp6->icmp6_code = 0; - icmp6->icmp6_cksum = 0; - icmp6->icmp6_data16[0]= htons(getpid()); /* Identifier */ - icmp6->icmp6_data16[1]= htons(random()); /* Sequence Number */ - - ptr+= sizeof(struct icmp6_hdr); - - for(i=0; i< (fsize/8); i++){ - memcpy(ptr, block, FRAG_BLOCK_SIZE); - ptr += FRAG_BLOCK_SIZE; - } - - ptrend=ptr; - - for(i=0; i< (ip6len-sizeof(struct icmp6_hdr)-fsize)/8; i++){ - memcpy(ptr, block, FRAG_BLOCK_SIZE); - ptr += FRAG_BLOCK_SIZE; - } - - /* Length of the reassembled fragment */ - ipv6->ip6_plen= htons(ip6len); - icmp6->icmp6_cksum = in_chksum(v6buffer, icmp6, ptr-((unsigned char *)icmp6), IPPROTO_ICMPV6); - - ptr= ptrend; - - /* Length of the current fragment */ - ipv6->ip6_plen= htons(ptr-(v6buffer + MIN_IPV6_HLEN)); - } - else{ - if((ptr+ fsize) > (v6buffer+idata->max_packet_size)){ - puts("Packet too large while inserting timestamp"); - return(-1); - } - - for(i=0; i< (fsize/8); i++){ - memcpy(ptr, block, FRAG_BLOCK_SIZE); - ptr += FRAG_BLOCK_SIZE; - } - - ipv6->ip6_plen= htons(ptr-(v6buffer + MIN_IPV6_HLEN)); - } - - if((nw=pcap_inject(idata->pfd, buffer, ptr - buffer)) == -1){ - printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); - return(-1); - } - - if(nw != (ptr- buffer)){ - printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, (LUI) (ptr-buffer)); - return(-1); - } - - return 0; + return 0; } - - /* * Function: send_fragment() * * Sends an IPv6 fragment */ -int send_fragment(struct iface_data *idata, unsigned int id, unsigned int offset, unsigned int fsize, \ - unsigned int forder, unsigned int tstamp_f){ - uint32_t tstamp; - unsigned int i; - - ethernet= (struct ether_header *) buffer; - dlt_null= (struct dlt_null *) buffer; - v6buffer = buffer + idata->linkhsize; - ipv6 = (struct ip6_hdr *) v6buffer; - - if(idata->type == DLT_EN10MB){ - ethernet->ether_type = htons(ETHERTYPE_IPV6); - - if(!(idata->flags & IFACE_LOOPBACK)){ - ethernet->src = idata->hsrcaddr; - ethernet->dst = idata->hdstaddr; - } - } - else if(idata->type == DLT_NULL){ - dlt_null->family= PF_INET6; - } -#if defined (__OpenBSD__) - else if(idata->type == DLT_LOOP){ - dlt_null->family= htonl(PF_INET6); - } +int send_fragment(struct iface_data *idata, unsigned int id, unsigned int offset, unsigned int fsize, + unsigned int forder, unsigned int tstamp_f) { + uint32_t tstamp; + unsigned int i; + + ethernet = (struct ether_header *)buffer; + dlt_null = (struct dlt_null *)buffer; + v6buffer = buffer + idata->linkhsize; + ipv6 = (struct ip6_hdr *)v6buffer; + + if (idata->type == DLT_EN10MB) { + ethernet->ether_type = htons(ETHERTYPE_IPV6); + + if (!(idata->flags & IFACE_LOOPBACK)) { + ethernet->src = idata->hsrcaddr; + ethernet->dst = idata->hdstaddr; + } + } + else if (idata->type == DLT_NULL) { + dlt_null->family = PF_INET6; + } +#if defined(__OpenBSD__) + else if (idata->type == DLT_LOOP) { + dlt_null->family = htonl(PF_INET6); + } #endif - ipv6->ip6_flow=0; - ipv6->ip6_vfc= 0x60; - ipv6->ip6_hlim= hoplimit; - - if(idata->srcprefix_f){ - randomize_ipv6_addr( &(ipv6->ip6_src), &(idata->srcaddr), idata->srcpreflen); - } - else{ - ipv6->ip6_src= idata->srcaddr; - } - - ipv6->ip6_dst= idata->dstaddr; - - prev_nh = (unsigned char *) &(ipv6->ip6_nxt); - - ptr = (unsigned char *) v6buffer + MIN_IPV6_HLEN; - - if(hbhopthdr_f){ - hbhopthdrs=0; - - while(hbhopthdrs < nhbhopthdr){ - if((ptr+ hbhopthdrlen[hbhopthdrs]) > (v6buffer+ idata->mtu)){ - puts("Packet too large while processing HBH Opt. Header"); - return(-1); - } - - *prev_nh = IPPROTO_HOPOPTS; - prev_nh = ptr; - memcpy(ptr, hbhopthdr[hbhopthdrs], hbhopthdrlen[hbhopthdrs]); - ptr = ptr + hbhopthdrlen[hbhopthdrs]; - hbhopthdrs++; - } - } - - if(dstoptuhdr_f){ - dstoptuhdrs=0; - - while(dstoptuhdrs < ndstoptuhdr){ - if((ptr+ dstoptuhdrlen[dstoptuhdrs]) > (v6buffer+ idata->mtu)){ - puts("Packet too large while processing Dest. Opt. Header (Unfrag. Part)"); - return(-1); - } - - *prev_nh = IPPROTO_DSTOPTS; - prev_nh = ptr; - memcpy(ptr, dstoptuhdr[dstoptuhdrs], dstoptuhdrlen[dstoptuhdrs]); - ptr = ptr + dstoptuhdrlen[dstoptuhdrs]; - dstoptuhdrs++; - } - } - - if(!fsize_f && (forder != LAST_FRAGMENT && forder != ATOMIC_FRAGMENT)){ - fsize= (fsize>>3) << 3; - } - - /* Check that we are able to send the Unfragmentable Part, together with a - Fragment Header and a chunk data over our link layer - */ - if( (ptr+sizeof(struct ip6_frag)+fsize) > (v6buffer+idata->mtu)){ - printf("Unfragmentable part too large for current MTU (%u bytes)\n", idata->mtu); - return(-1); - } - - /* We prepare a separete Fragment Header, but we do not include it in the packet to be sent. - This Fragment Header will be used (an assembled with the rest of the packet by the - send_packet() function. - */ - fh= (struct ip6_frag *) ptr; - memset(ptr, 0, FRAG_HDR_SIZE); - - fh->ip6f_ident= htonl(id); - - if(forder == LAST_FRAGMENT || forder == ATOMIC_FRAGMENT) - m=0; - else - m=IP6F_MORE_FRAG; - - if((forder==FIRST_FRAGMENT || forder==ATOMIC_FRAGMENT) && !foffset_f) - offset=0; - - fh->ip6f_offlg = (htons(offset) & IP6F_OFF_MASK) | m; - - *prev_nh = IPPROTO_FRAGMENT; - prev_nh = (unsigned char *) fh; - - ptr+= sizeof(struct ip6_frag); - - if(dstopthdr_f){ - dstopthdrs=0; - - while(dstopthdrs < ndstopthdr){ - if((ptr+ dstopthdrlen[dstopthdrs]) > (v6buffer+idata->max_packet_size)){ - puts("Packet too large while processing Dest. Opt. Header (should be using the Frag. option?)"); - return(-1); - } - - *prev_nh = IPPROTO_DSTOPTS; - prev_nh = ptr; - memcpy(ptr, dstopthdr[dstopthdrs], dstopthdrlen[dstopthdrs]); - ptr = ptr + dstopthdrlen[dstopthdrs]; - dstopthdrs++; - } - } - - *prev_nh = IPPROTO_ICMPV6; - - if(forder == FIRST_FRAGMENT || forder == ATOMIC_FRAGMENT){ - if((ptr+ fsize) > (v6buffer+idata->max_packet_size)){ - puts("Packet too large while inserting ICMPv6 header"); - return(-1); - } - - if(fsize < sizeof(struct icmp6_hdr)){ - if(idata->verbose_f) - puts("Fragment size too small to hold an ICMPv6 header"); - - return(-1); - } - - icmp6 = (struct icmp6_hdr *) ptr; - icmp6->icmp6_type = ICMP6_ECHO_REQUEST; - icmp6->icmp6_code = 0; - icmp6->icmp6_cksum = 0; - icmp6->icmp6_data16[0]= htons(getpid()); /* Identifier */ - icmp6->icmp6_data16[1]= htons(random()); /* Sequence Number */ - - ptr+= sizeof(struct icmp6_hdr); - fsize-= sizeof(struct icmp6_hdr); - - if(tstamp_f && fsize >= (sizeof(uint32_t)+sizeof(uint32_t))){ - if((ptr+ (sizeof(uint32_t) + sizeof(uint32_t))) > (v6buffer+idata->max_packet_size)){ - puts("Packet too large while inserting timestamp"); - return(-1); - } - - /* We include a timstamp to be able to measure the Fragment Reassembly timeout */ - tstamp= (uint32_t) time(NULL); - *(uint32_t *)ptr= tstamp; - ptr+= sizeof(uint32_t); - - /* We include a "checksum" such that we can tell the responses we elicit from other packets */ - *(uint32_t *)ptr= (uint32_t)tstamp ^ 0xabcdabcd; - ptr+= sizeof(uint32_t); - - - if(fsize > (sizeof(uint32_t)+sizeof(uint32_t))) - fsize-= (sizeof(uint32_t)+sizeof(uint32_t)); - else - fsize=0; - } - - for(i=0; i< (fsize/4); i++){ - *(uint32_t *)ptr = random(); - ptr += sizeof(uint32_t); - } - - ipv6->ip6_plen= htons(ptr-(v6buffer + MIN_IPV6_HLEN)); - icmp6->icmp6_cksum = in_chksum(v6buffer, icmp6, ptr-((unsigned char *)icmp6), IPPROTO_ICMPV6); - } - else{ - /* XXX: Should check */ - if(tstamp_f){ - if((ptr+ (sizeof(uint32_t) + sizeof(uint32_t))) > (v6buffer+idata->max_packet_size)){ - puts("Packet too large while inserting timestamp"); - return(-1); - } - - /* We include a timstamp to be able to measure the Fragment Reassembly timeout */ - tstamp= (uint32_t)time(NULL); - *(uint32_t *)ptr= tstamp; - ptr+= sizeof(time_t); - - /* We include a "checksum" such that we can tell the responses we elicit from other packets */ - *(uint32_t *)ptr= (uint32_t)tstamp ^ 0xabcdabcd; - ptr+= sizeof(uint32_t); - - - if(fsize > (sizeof(uint32_t)+sizeof(uint32_t))) - fsize-= (sizeof(uint32_t)+sizeof(uint32_t)); - else - fsize=0; - } - - - if((ptr+ fsize) > (v6buffer+idata->max_packet_size)){ - puts("Packet too large while inserting payload"); - return(-1); - } - - for(i=0; i<(fsize/sizeof(uint32_t)); i++){ - *(uint32_t *)ptr = random(); - ptr += sizeof(uint32_t); - } - - ipv6->ip6_plen= htons(ptr-(v6buffer + MIN_IPV6_HLEN)); - } - - if((nw=pcap_inject(idata->pfd, buffer, ptr - buffer)) == -1){ - printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); - return(-1); - } - - if(nw != (ptr- buffer)){ - printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, (LUI) (ptr-buffer)); - return(-1); - } - - return 0; + ipv6->ip6_flow = 0; + ipv6->ip6_vfc = 0x60; + ipv6->ip6_hlim = hoplimit; + + if (idata->srcprefix_f) { + randomize_ipv6_addr(&(ipv6->ip6_src), &(idata->srcaddr), idata->srcpreflen); + } + else { + ipv6->ip6_src = idata->srcaddr; + } + + ipv6->ip6_dst = idata->dstaddr; + + prev_nh = (unsigned char *)&(ipv6->ip6_nxt); + + ptr = (unsigned char *)v6buffer + MIN_IPV6_HLEN; + + if (hbhopthdr_f) { + hbhopthdrs = 0; + + while (hbhopthdrs < nhbhopthdr) { + if ((ptr + hbhopthdrlen[hbhopthdrs]) > (v6buffer + idata->mtu)) { + puts("Packet too large while processing HBH Opt. Header"); + return (-1); + } + + *prev_nh = IPPROTO_HOPOPTS; + prev_nh = ptr; + memcpy(ptr, hbhopthdr[hbhopthdrs], hbhopthdrlen[hbhopthdrs]); + ptr = ptr + hbhopthdrlen[hbhopthdrs]; + hbhopthdrs++; + } + } + + if (dstoptuhdr_f) { + dstoptuhdrs = 0; + + while (dstoptuhdrs < ndstoptuhdr) { + if ((ptr + dstoptuhdrlen[dstoptuhdrs]) > (v6buffer + idata->mtu)) { + puts("Packet too large while processing Dest. Opt. Header (Unfrag. Part)"); + return (-1); + } + + *prev_nh = IPPROTO_DSTOPTS; + prev_nh = ptr; + memcpy(ptr, dstoptuhdr[dstoptuhdrs], dstoptuhdrlen[dstoptuhdrs]); + ptr = ptr + dstoptuhdrlen[dstoptuhdrs]; + dstoptuhdrs++; + } + } + + if (!fsize_f && (forder != LAST_FRAGMENT && forder != ATOMIC_FRAGMENT)) { + fsize = (fsize >> 3) << 3; + } + + /* Check that we are able to send the Unfragmentable Part, together with a + Fragment Header and a chunk data over our link layer + */ + if ((ptr + sizeof(struct ip6_frag) + fsize) > (v6buffer + idata->mtu)) { + printf("Unfragmentable part too large for current MTU (%u bytes)\n", idata->mtu); + return (-1); + } + + /* We prepare a separete Fragment Header, but we do not include it in the packet to be sent. + This Fragment Header will be used (an assembled with the rest of the packet by the + send_packet() function. + */ + fh = (struct ip6_frag *)ptr; + memset(ptr, 0, FRAG_HDR_SIZE); + + fh->ip6f_ident = htonl(id); + + if (forder == LAST_FRAGMENT || forder == ATOMIC_FRAGMENT) + m = 0; + else + m = IP6F_MORE_FRAG; + + if ((forder == FIRST_FRAGMENT || forder == ATOMIC_FRAGMENT) && !foffset_f) + offset = 0; + + fh->ip6f_offlg = (htons(offset) & IP6F_OFF_MASK) | m; + + *prev_nh = IPPROTO_FRAGMENT; + prev_nh = (unsigned char *)fh; + + ptr += sizeof(struct ip6_frag); + + if (dstopthdr_f) { + dstopthdrs = 0; + + while (dstopthdrs < ndstopthdr) { + if ((ptr + dstopthdrlen[dstopthdrs]) > (v6buffer + idata->max_packet_size)) { + puts("Packet too large while processing Dest. Opt. Header (should be using the Frag. option?)"); + return (-1); + } + + *prev_nh = IPPROTO_DSTOPTS; + prev_nh = ptr; + memcpy(ptr, dstopthdr[dstopthdrs], dstopthdrlen[dstopthdrs]); + ptr = ptr + dstopthdrlen[dstopthdrs]; + dstopthdrs++; + } + } + + *prev_nh = IPPROTO_ICMPV6; + + if (forder == FIRST_FRAGMENT || forder == ATOMIC_FRAGMENT) { + if ((ptr + fsize) > (v6buffer + idata->max_packet_size)) { + puts("Packet too large while inserting ICMPv6 header"); + return (-1); + } + + if (fsize < sizeof(struct icmp6_hdr)) { + if (idata->verbose_f) + puts("Fragment size too small to hold an ICMPv6 header"); + + return (-1); + } + + icmp6 = (struct icmp6_hdr *)ptr; + icmp6->icmp6_type = ICMP6_ECHO_REQUEST; + icmp6->icmp6_code = 0; + icmp6->icmp6_cksum = 0; + icmp6->icmp6_data16[0] = htons(getpid()); /* Identifier */ + icmp6->icmp6_data16[1] = htons(random()); /* Sequence Number */ + + ptr += sizeof(struct icmp6_hdr); + fsize -= sizeof(struct icmp6_hdr); + + if (tstamp_f && fsize >= (sizeof(uint32_t) + sizeof(uint32_t))) { + if ((ptr + (sizeof(uint32_t) + sizeof(uint32_t))) > (v6buffer + idata->max_packet_size)) { + puts("Packet too large while inserting timestamp"); + return (-1); + } + + /* We include a timstamp to be able to measure the Fragment Reassembly timeout */ + tstamp = (uint32_t)time(NULL); + *(uint32_t *)ptr = tstamp; + ptr += sizeof(uint32_t); + + /* We include a "checksum" such that we can tell the responses we elicit from other packets */ + *(uint32_t *)ptr = (uint32_t)tstamp ^ 0xabcdabcd; + ptr += sizeof(uint32_t); + + if (fsize > (sizeof(uint32_t) + sizeof(uint32_t))) + fsize -= (sizeof(uint32_t) + sizeof(uint32_t)); + else + fsize = 0; + } + + for (i = 0; i < (fsize / 4); i++) { + *(uint32_t *)ptr = random(); + ptr += sizeof(uint32_t); + } + + ipv6->ip6_plen = htons(ptr - (v6buffer + MIN_IPV6_HLEN)); + icmp6->icmp6_cksum = in_chksum(v6buffer, icmp6, ptr - ((unsigned char *)icmp6), IPPROTO_ICMPV6); + } + else { + /* XXX: Should check */ + if (tstamp_f) { + if ((ptr + (sizeof(uint32_t) + sizeof(uint32_t))) > (v6buffer + idata->max_packet_size)) { + puts("Packet too large while inserting timestamp"); + return (-1); + } + + /* We include a timstamp to be able to measure the Fragment Reassembly timeout */ + tstamp = (uint32_t)time(NULL); + *(uint32_t *)ptr = tstamp; + ptr += sizeof(time_t); + + /* We include a "checksum" such that we can tell the responses we elicit from other packets */ + *(uint32_t *)ptr = (uint32_t)tstamp ^ 0xabcdabcd; + ptr += sizeof(uint32_t); + + if (fsize > (sizeof(uint32_t) + sizeof(uint32_t))) + fsize -= (sizeof(uint32_t) + sizeof(uint32_t)); + else + fsize = 0; + } + + if ((ptr + fsize) > (v6buffer + idata->max_packet_size)) { + puts("Packet too large while inserting payload"); + return (-1); + } + + for (i = 0; i < (fsize / sizeof(uint32_t)); i++) { + *(uint32_t *)ptr = random(); + ptr += sizeof(uint32_t); + } + + ipv6->ip6_plen = htons(ptr - (v6buffer + MIN_IPV6_HLEN)); + } + + if ((nw = pcap_inject(idata->pfd, buffer, ptr - buffer)) == -1) { + printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); + return (-1); + } + + if (nw != (ptr - buffer)) { + printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, (LUI)(ptr - buffer)); + return (-1); + } + + return 0; } - /* * Function: send_fid_probe() * * Send a fragmented ICMPv6 Echo Request used for sampling the Fragment Identification * values sent by the target */ -int send_fid_probe(struct iface_data *idata){ - unsigned char fragbuffer[FRAG_BUFFER_SIZE]; - struct ip6_frag *frag; - struct ether_header *ethernet; - struct ip6_hdr *ipv6; - unsigned char *fptr, *fptrend; - unsigned int i; - - ethernet= (struct ether_header *) buffer; - v6buffer = buffer + idata->linkhsize; - ipv6 = (struct ip6_hdr *) v6buffer; - - if(idata->type == DLT_EN10MB){ - ethernet->ether_type = htons(ETHERTYPE_IPV6); - - if(!(idata->flags & IFACE_LOOPBACK)){ - ethernet->src = idata->hsrcaddr; - ethernet->dst = idata->hdstaddr; - } - } - else if(idata->type == DLT_NULL){ - dlt_null->family= PF_INET6; - } - - ipv6->ip6_flow=0; - ipv6->ip6_vfc= 0x60; - ipv6->ip6_hlim= hoplimit; - ipv6->ip6_src= idata->srcaddr; - ipv6->ip6_dst= idata->dstaddr; - ipv6->ip6_nxt= IPPROTO_FRAGMENT; - - /* ptr always points to the part of the original packet that is being crafted */ - ptr = (unsigned char *) v6buffer + sizeof(struct ip6_hdr); - - frag= (struct ip6_frag *) ptr; - memset(frag, 0, sizeof(struct ip6_frag)); - frag->ip6f_nxt= IPPROTO_ICMPV6; - - ptr+= sizeof(struct ip6_frag); - - /* fragpart points to the beginning of the fragmentable part of the original packet */ - fragpart= ptr; - - icmp6 = (struct icmp6_hdr *) ptr; - icmp6->icmp6_type = ICMP6_ECHO_REQUEST; - icmp6->icmp6_code = 0; - icmp6->icmp6_cksum = 0; - icmp6->icmp6_data16[0]= htons(getpid()); /* Identifier */ - icmp6->icmp6_data16[1]= htons(random()); /* Sequence Number */ - - ptr+= sizeof(struct icmp6_hdr); - *(uint32_t *)ptr= icmp6_sig; - ptr+= sizeof(uint32_t); - - for(i=0;i<400; i++){ - *(uint32_t *)ptr= random(); - ptr+=sizeof(uint32_t); - } - - icmp6->icmp6_cksum = in_chksum(v6buffer, icmp6, ptr-(unsigned char *)icmp6, IPPROTO_ICMPV6); - - /* ptrend points to the end of the original packet */ - ptrend= ptr; - ptr= fragpart; - - /* fptr points to the part of the fragment that is being crafted */ - fptr = fragbuffer; - fipv6 = (struct ip6_hdr *) (fragbuffer + idata->linkhsize); - fptrend = fptr + FRAG_BUFFER_SIZE; - - /* Copy everything from the Ethernet header, up to (and including) the Fragmentation Header */ - memcpy(fptr, buffer, fragpart-buffer); - fptr = fptr + (fragpart-buffer); - - fh= (struct ip6_frag *) (fragbuffer + idata->linkhsize + sizeof(struct ip6_hdr)); - fh->ip6f_ident=random(); - startoffragment = fptr; - - /* We'll be sending packets of at most 1280 bytes (the IPv6 minimum MTU) */ - fragsize= ((MIN_IPV6_MTU - sizeof(struct ip6_hdr) - sizeof(struct ip6_frag)) >> 3) << 3; - - /* - * Check that the selected fragment size is not larger than the largest - * fragment size that can be sent. This chec will always be passed, but is useful - * when future versions of the tool support other link-layer technologies. - */ - - if( (startoffragment + fragsize) > fptrend){ - printf("Fragment size too large to fit into fragmentation buffer\n"); - return(-1); - } - - m=IP6F_MORE_FRAG; - - while((ptr< ptrend) && m==IP6F_MORE_FRAG){ - fptr= startoffragment; - - if( (ptrend-ptr) <= fragsize){ - fragsize= ptrend-ptr; - m=0; - } - - memcpy(fptr, ptr, fragsize); - fh->ip6f_offlg = (htons(ptr-fragpart) & IP6F_OFF_MASK) | m; - ptr+=fragsize; - fptr+=fragsize; - - fipv6->ip6_plen = htons((fptr - fragbuffer) - MIN_IPV6_HLEN - idata->linkhsize); - - if((nw=pcap_inject(idata->pfd, fragbuffer, fptr - fragbuffer)) == -1){ - printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); - return(-1); - } - - if(nw != (fptr- fragbuffer)){ - printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", \ - nw, (LUI) (ptr-buffer)); - return(-1); - } - } /* Sending fragments */ - - return(0); +int send_fid_probe(struct iface_data *idata) { + unsigned char fragbuffer[FRAG_BUFFER_SIZE]; + struct ip6_frag *frag; + struct ether_header *ethernet; + struct ip6_hdr *ipv6; + unsigned char *fptr, *fptrend; + unsigned int i; + + ethernet = (struct ether_header *)buffer; + v6buffer = buffer + idata->linkhsize; + ipv6 = (struct ip6_hdr *)v6buffer; + + if (idata->type == DLT_EN10MB) { + ethernet->ether_type = htons(ETHERTYPE_IPV6); + + if (!(idata->flags & IFACE_LOOPBACK)) { + ethernet->src = idata->hsrcaddr; + ethernet->dst = idata->hdstaddr; + } + } + else if (idata->type == DLT_NULL) { + dlt_null->family = PF_INET6; + } + + ipv6->ip6_flow = 0; + ipv6->ip6_vfc = 0x60; + ipv6->ip6_hlim = hoplimit; + ipv6->ip6_src = idata->srcaddr; + ipv6->ip6_dst = idata->dstaddr; + ipv6->ip6_nxt = IPPROTO_FRAGMENT; + + /* ptr always points to the part of the original packet that is being crafted */ + ptr = (unsigned char *)v6buffer + sizeof(struct ip6_hdr); + + frag = (struct ip6_frag *)ptr; + memset(frag, 0, sizeof(struct ip6_frag)); + frag->ip6f_nxt = IPPROTO_ICMPV6; + + ptr += sizeof(struct ip6_frag); + + /* fragpart points to the beginning of the fragmentable part of the original packet */ + fragpart = ptr; + + icmp6 = (struct icmp6_hdr *)ptr; + icmp6->icmp6_type = ICMP6_ECHO_REQUEST; + icmp6->icmp6_code = 0; + icmp6->icmp6_cksum = 0; + icmp6->icmp6_data16[0] = htons(getpid()); /* Identifier */ + icmp6->icmp6_data16[1] = htons(random()); /* Sequence Number */ + + ptr += sizeof(struct icmp6_hdr); + *(uint32_t *)ptr = icmp6_sig; + ptr += sizeof(uint32_t); + + for (i = 0; i < 400; i++) { + *(uint32_t *)ptr = random(); + ptr += sizeof(uint32_t); + } + + icmp6->icmp6_cksum = in_chksum(v6buffer, icmp6, ptr - (unsigned char *)icmp6, IPPROTO_ICMPV6); + + /* ptrend points to the end of the original packet */ + ptrend = ptr; + ptr = fragpart; + + /* fptr points to the part of the fragment that is being crafted */ + fptr = fragbuffer; + fipv6 = (struct ip6_hdr *)(fragbuffer + idata->linkhsize); + fptrend = fptr + FRAG_BUFFER_SIZE; + + /* Copy everything from the Ethernet header, up to (and including) the Fragmentation Header */ + memcpy(fptr, buffer, fragpart - buffer); + fptr = fptr + (fragpart - buffer); + + fh = (struct ip6_frag *)(fragbuffer + idata->linkhsize + sizeof(struct ip6_hdr)); + fh->ip6f_ident = random(); + startoffragment = fptr; + + /* We'll be sending packets of at most 1280 bytes (the IPv6 minimum MTU) */ + fragsize = ((MIN_IPV6_MTU - sizeof(struct ip6_hdr) - sizeof(struct ip6_frag)) >> 3) << 3; + + /* + * Check that the selected fragment size is not larger than the largest + * fragment size that can be sent. This chec will always be passed, but is useful + * when future versions of the tool support other link-layer technologies. + */ + + if ((startoffragment + fragsize) > fptrend) { + printf("Fragment size too large to fit into fragmentation buffer\n"); + return (-1); + } + + m = IP6F_MORE_FRAG; + + while ((ptr < ptrend) && m == IP6F_MORE_FRAG) { + fptr = startoffragment; + + if ((ptrend - ptr) <= fragsize) { + fragsize = ptrend - ptr; + m = 0; + } + + memcpy(fptr, ptr, fragsize); + fh->ip6f_offlg = (htons(ptr - fragpart) & IP6F_OFF_MASK) | m; + ptr += fragsize; + fptr += fragsize; + + fipv6->ip6_plen = htons((fptr - fragbuffer) - MIN_IPV6_HLEN - idata->linkhsize); + + if ((nw = pcap_inject(idata->pfd, fragbuffer, fptr - fragbuffer)) == -1) { + printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); + return (-1); + } + + if (nw != (fptr - fragbuffer)) { + printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, (LUI)(ptr - buffer)); + return (-1); + } + } /* Sending fragments */ + + return (0); } - /* * Function: usage() * * Prints the syntax of the frag6 tool */ -void usage(void){ - puts("usage: frag6 -d DST_ADDR [-i INTERFACE] [-S LINK_SRC_ADDR] [-D LINK-DST-ADDR]\n" - " [-s SRC_ADDR[/LEN]] [-A HOP_LIMIT] [-u DST_OPT_HDR_SIZE]\n" - " [-U DST_OPT_U_HDR_SIZE] [-H HBH_OPT_HDR_SIZE] [-P FRAG_SIZE]\n" - " [-O FRAG_TYPE] [-o FRAG_OFFSET] [-I FRAG_ID] [-T] [-n]\n" - " [-p | -W | -X | -F N_FRAGS] [-l] [-z SECONDS] [-v] [-h]"); +void usage(void) { + puts("usage: frag6 -d DST_ADDR [-i INTERFACE] [-S LINK_SRC_ADDR] [-D LINK-DST-ADDR]\n" + " [-s SRC_ADDR[/LEN]] [-A HOP_LIMIT] [-u DST_OPT_HDR_SIZE]\n" + " [-U DST_OPT_U_HDR_SIZE] [-H HBH_OPT_HDR_SIZE] [-P FRAG_SIZE]\n" + " [-O FRAG_TYPE] [-o FRAG_OFFSET] [-I FRAG_ID] [-T] [-n]\n" + " [-p | -W | -X | -F N_FRAGS] [-l] [-z SECONDS] [-v] [-h]"); } - /* * Function: print_help() * * Prints help information for the frag6 tool */ -void print_help(void){ - puts(SI6_TOOLKIT); - puts( "frag6: A security assessment tool for attack vectors based on IPv6 fragments\n"); - usage(); - - puts("\nOPTIONS:\n" - " --interface, -i Network interface\n" - " --link-src-addr, -S Link-layer Destination Address\n" - " --link-dst-addr, -D Link-layer Source Address\n" - " --src-addr, -s IPv6 Source Address\n" - " --dst-addr, -d IPv6 Destination Address\n" - " --hop-limit, -A IPv6 Hop Limit\n" - " --dst-opt-hdr, -u Destination Options Header (Fragmentable Part)\n" - " --dst-opt-u-hdr, -U Destination Options Header (Unfragmentable Part)\n" - " --hbh-opt-hdr, -H Hop by Hop Options Header\n" - " --frag-size, -P IPv6 fragment payload size\n" - " --frag-type, -O IPv6 Fragment Type {first, last, middle, atomic}\n" - " --frag-offset, -o IPv6 Fragment Offset\n" - " --frag-id, -I IPv6 Fragment Identification\n" - " --no-timestamp, -T Do not include a timestamp in the payload\n" - " --no-responses, -n Do not print responses to transmitted packets\n" - " --frag-reass-policy, -p Assess fragment reassembly policy\n" - " --frag-id-policy, -W Assess the Fragment ID generation policy\n" - " --pod-attack, -X Perform a 'Ping of Death' attack\n" - " --flood-frags, -F Flood target with IPv6 fragments\n" - " --loop, -l Send IPv6 fragments periodically\n" - " --sleep, -z Pause between sending IPv6 fragments\n" - " --verbose, -v Be verbose\n" - " --help, -h Print help for the frag6 tool\n" - "\n" - "Programmed by Fernando Gont for SI6 Networks \n" - "Please send any bug reports to \n" - ); +void print_help(void) { + puts(SI6_TOOLKIT); + puts("frag6: A security assessment tool for attack vectors based on IPv6 fragments\n"); + usage(); + + puts("\nOPTIONS:\n" + " --interface, -i Network interface\n" + " --link-src-addr, -S Link-layer Destination Address\n" + " --link-dst-addr, -D Link-layer Source Address\n" + " --src-addr, -s IPv6 Source Address\n" + " --dst-addr, -d IPv6 Destination Address\n" + " --hop-limit, -A IPv6 Hop Limit\n" + " --dst-opt-hdr, -u Destination Options Header (Fragmentable Part)\n" + " --dst-opt-u-hdr, -U Destination Options Header (Unfragmentable Part)\n" + " --hbh-opt-hdr, -H Hop by Hop Options Header\n" + " --frag-size, -P IPv6 fragment payload size\n" + " --frag-type, -O IPv6 Fragment Type {first, last, middle, atomic}\n" + " --frag-offset, -o IPv6 Fragment Offset\n" + " --frag-id, -I IPv6 Fragment Identification\n" + " --no-timestamp, -T Do not include a timestamp in the payload\n" + " --no-responses, -n Do not print responses to transmitted packets\n" + " --frag-reass-policy, -p Assess fragment reassembly policy\n" + " --frag-id-policy, -W Assess the Fragment ID generation policy\n" + " --pod-attack, -X Perform a 'Ping of Death' attack\n" + " --flood-frags, -F Flood target with IPv6 fragments\n" + " --loop, -l Send IPv6 fragments periodically\n" + " --sleep, -z Pause between sending IPv6 fragments\n" + " --verbose, -v Be verbose\n" + " --help, -h Print help for the frag6 tool\n" + "\n" + "Programmed by Fernando Gont for SI6 Networks \n" + "Please send any bug reports to \n"); } - /* * Function: print_attack_info() * * Prints attack details (when the verbose ("-v") option is specified). */ - -void print_attack_info(struct iface_data *idata){ - if(idata->type == DLT_EN10MB && !(idata->flags & IFACE_LOOPBACK)){ - if(ether_ntop(&(idata->hsrcaddr), plinkaddr, sizeof(plinkaddr)) == 0){ - puts("ether_ntop(): Error converting address"); - exit(EXIT_FAILURE); - } - - printf("Ethernet Source Address: %s%s\n", plinkaddr, (!idata->hsrcaddr_f)?" (automatically selected)":""); - - /* - Ethernet Destination Address only used if a IPv6 Destination Address or an - Ethernet Destination Address were specified. - */ - if(ether_ntop(&(idata->hdstaddr), plinkaddr, sizeof(plinkaddr)) == 0){ - puts("ether_ntop(): Error converting address"); - exit(EXIT_FAILURE); - } - - printf("Ethernet Destination Address: %s%s\n", plinkaddr, (!idata->hdstaddr_f)?" (automatically selected)":""); - } - - if(idata->srcaddr_f){ - if(inet_ntop(AF_INET6, &(idata->srcaddr), psrcaddr, sizeof(psrcaddr)) == NULL){ - puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); - exit(EXIT_FAILURE); - } - - printf("IPv6 Source Address: %s%s\n", psrcaddr, ((idata->srcaddr_f != TRUE)?" (automatically selected)":"")); - } - - if(inet_ntop(AF_INET6, &(idata->dstaddr), pdstaddr, sizeof(pdstaddr)) == NULL){ - puts("inet_ntop(): Error converting IPv6 Destination Address to presentation format"); - exit(EXIT_FAILURE); - } - - printf("IPv6 Destination Address: %s\n", pdstaddr); - - printf("IPv6 Hop Limit: %u%s\n", hoplimit, (hoplimit_f)?"":" (randomized)"); - - for(i=0; itype == DLT_EN10MB && !(idata->flags & IFACE_LOOPBACK)) { + if (ether_ntop(&(idata->hsrcaddr), plinkaddr, sizeof(plinkaddr)) == 0) { + puts("ether_ntop(): Error converting address"); + exit(EXIT_FAILURE); + } + + printf("Ethernet Source Address: %s%s\n", plinkaddr, (!idata->hsrcaddr_f) ? " (automatically selected)" : ""); + + /* + Ethernet Destination Address only used if a IPv6 Destination Address or an + Ethernet Destination Address were specified. + */ + if (ether_ntop(&(idata->hdstaddr), plinkaddr, sizeof(plinkaddr)) == 0) { + puts("ether_ntop(): Error converting address"); + exit(EXIT_FAILURE); + } + + printf("Ethernet Destination Address: %s%s\n", plinkaddr, + (!idata->hdstaddr_f) ? " (automatically selected)" : ""); + } + + if (idata->srcaddr_f) { + if (inet_ntop(AF_INET6, &(idata->srcaddr), psrcaddr, sizeof(psrcaddr)) == NULL) { + puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); + exit(EXIT_FAILURE); + } + + printf("IPv6 Source Address: %s%s\n", psrcaddr, + ((idata->srcaddr_f != TRUE) ? " (automatically selected)" : "")); + } + + if (inet_ntop(AF_INET6, &(idata->dstaddr), pdstaddr, sizeof(pdstaddr)) == NULL) { + puts("inet_ntop(): Error converting IPv6 Destination Address to presentation format"); + exit(EXIT_FAILURE); + } + + printf("IPv6 Destination Address: %s\n", pdstaddr); + + printf("IPv6 Hop Limit: %u%s\n", hoplimit, (hoplimit_f) ? "" : " (randomized)"); + + for (i = 0; i < ndstoptuhdr; i++) + printf("Destination Options Header (Unfragmentable part): %u bytes\n", dstoptuhdrlen[i]); + + for (i = 0; i < nhbhopthdr; i++) + printf("Hop by Hop Options Header: %u bytes\n", hbhopthdrlen[i]); + + for (i = 0; i < ndstopthdr; i++) + printf("Destination Options Header: %u bytes\n", dstopthdrlen[i]); +} /* * Function: valid_icmp6_response() @@ -2388,362 +2381,350 @@ void print_attack_info(struct iface_data *idata){ * Checks whether the response to an ICMPv6 probe is valid */ -int valid_icmp6_response(struct iface_data *idata, struct pcap_pkthdr *pkthdr, const u_char *pktdata){ - - struct ether_header *pkt_ether; - struct ip6_hdr *pkt_ipv6, *pkt_ipv6_ipv6; - struct ip6_ext *pkt_ext; - struct icmp6_hdr *pkt_icmp6, *pkt_icmp6_icmp6; - struct ip6_frag *pkt_fh_fh; - unsigned char *pkt_end, *pkt_ptr; - uint8_t pkt_prev_nh; - unsigned int minfragsize; - - pkt_ether = (struct ether_header *) pktdata; - pkt_ipv6 = (struct ip6_hdr *)((char *) pkt_ether + idata->linkhsize); - pkt_icmp6 = (struct icmp6_hdr *) ((char *) pkt_ipv6 + MIN_IPV6_HLEN); - pkt_icmp6_icmp6= (struct icmp6_hdr *) ((unsigned char *) pkt_icmp6 + sizeof(struct icmp6_hdr) +\ - sizeof(struct ip6_hdr) + MIN_HBH_LEN); - - pkt_end = (unsigned char *) pktdata + pkthdr->caplen; - - /* The packet length is the minimum of what we capured, and what is specified in the - IPv6 Total Lenght field - */ - if( pkt_end > ((unsigned char *)pkt_icmp6 + ntohs(pkt_ipv6->ip6_plen)) ) - pkt_end = (unsigned char *)pkt_icmp6 + ntohs(pkt_ipv6->ip6_plen); - - switch(pkt_icmp6->icmp6_type){ - case ICMP6_ECHO_REPLY: - /* - Discard the packet if it is not of the minimum size to contain an ICMPv6 - header and the payload we included in the ICMPv6 Echo Request - */ - if( (pkt_end - (unsigned char *) pkt_icmp6) < (sizeof(struct icmp6_hdr) + \ - fsize) && (pkt_end - (unsigned char *) pkt_ipv6) < MIN_IPV6_MTU){ - return 0; - } - - /* Check that the ICMPv6 checksum is correct */ - if(in_chksum(pkt_ipv6, pkt_icmp6, pkt_end-((unsigned char *)pkt_icmp6), IPPROTO_ICMPV6) != 0){ - return 0; - } - - if(pkt_icmp6->icmp6_data16[0] != htons(getpid())){ - return 0; - } - - - if(tstamp_f){ - pkt_ptr= ((unsigned char *) pkt_icmp6+ sizeof(struct icmp6_hdr)); - - if( *((uint32_t *) pkt_ptr) != (*((uint32_t *) (pkt_ptr+sizeof(uint32_t))) ^ 0xabcdabcd)){ - return 0; - } - } - - break; - - case ICMP6_TIME_EXCEEDED: - /* - Discard the packet if it is not of the minimum size to contain an ICMPv6 - header and the payload we included in the ICMPv6 Echo Request - */ - minfragsize= sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr)+sizeof(struct ip6_hdr) + \ - sizeof(struct ip6_frag) + sizeof(struct icmp6_hdr) + (fsize_f?fsize:MIN_FRAG_SIZE) + \ - (tstamp_f?(sizeof(time_t)+sizeof(uint32_t)):0); - - if( ((pkt_end - (unsigned char *) pkt_ipv6) < minfragsize) && \ - (pkt_end - (unsigned char *) pkt_ipv6) < MIN_IPV6_MTU){ - return 0; - } - - pkt_ipv6_ipv6= (struct ip6_hdr *) ((unsigned char *)pkt_icmp6+ sizeof(struct icmp6_hdr)); - pkt_fh_fh= NULL; - pkt_ext= (struct ip6_ext *) ((unsigned char *)pkt_ipv6_ipv6 + sizeof(struct ip6_hdr)); - pkt_prev_nh= (pkt_ipv6_ipv6->ip6_nxt); - - while(pkt_prev_nh != IPPROTO_ICMPV6 && \ - ( (unsigned char *)pkt_ext + (pkt_ext->ip6e_len * 8 + 1)) < pkt_end){ - - if(pkt_prev_nh == IPPROTO_FRAGMENT) - pkt_fh_fh= (struct ip6_frag *) pkt_ext; - - pkt_prev_nh= pkt_ext->ip6e_nxt; - pkt_ext= (struct ip6_ext *) ( (unsigned char *)pkt_ext + ((pkt_ext->ip6e_len + 1) * 8)); - } - - if(pkt_prev_nh == IPPROTO_ICMPV6){ - pkt_icmp6_icmp6= (struct icmp6_hdr *) pkt_ext; - - if( ((unsigned char *) pkt_icmp6_icmp6 + (sizeof(struct icmp6_hdr)+ sizeof(struct ip6_hdr)+ \ - sizeof(struct ip6_frag)+sizeof(struct icmp6_hdr))) > pkt_end){ - return 0; - } - } - else{ - return 0; - } - - if(pkt_fh_fh == NULL) - return 0; - - /* - * We can only check the embedded ICMPv6 header if the embedded fragment is the first fragment of - * a packet - */ - if(ntohs(pkt_fh_fh->ip6f_offlg & IP6F_OFF_MASK) == 0){ - if(pkt_icmp6_icmp6->icmp6_type != ICMP6_ECHO_REQUEST){ - return 0; - } - - if(pkt_icmp6_icmp6->icmp6_data16[0] != htons(getpid())){ - return 0; - } - - if(tstamp_f){ - pkt_ptr= ((unsigned char *) pkt_icmp6_icmp6+ sizeof(struct icmp6_hdr)); - if( *(uint32_t *) pkt_ptr != (*(uint32_t *) (pkt_ptr+sizeof(uint32_t)) ^ 0xabcdabcd)){ - return 0; - } - } - } - else{ - return 0; - } - - break; - - default: - return 0; - break; - } - - /* - Check that the Source Address of the Packet is "valid" - */ - if(IN6_IS_ADDR_UNSPECIFIED(&(pkt_ipv6->ip6_src))){ - return 0; - } - - if(IN6_IS_ADDR_LOOPBACK(&(pkt_ipv6->ip6_src))){ - return 0; - } - - if(IN6_IS_ADDR_MULTICAST(&(pkt_ipv6->ip6_src))){ - return 0; - } - - /* - Check that that the Destination Address of the incoming packet is one - of our addresses. - */ - if(!(floodf_f && srcprefix_f) && !is_eq_in6_addr(&(idata->srcaddr), &(pkt_ipv6->ip6_dst))){ - return 0; - } - - return 1; +int valid_icmp6_response(struct iface_data *idata, struct pcap_pkthdr *pkthdr, const u_char *pktdata) { + + struct ether_header *pkt_ether; + struct ip6_hdr *pkt_ipv6, *pkt_ipv6_ipv6; + struct ip6_ext *pkt_ext; + struct icmp6_hdr *pkt_icmp6, *pkt_icmp6_icmp6; + struct ip6_frag *pkt_fh_fh; + unsigned char *pkt_end, *pkt_ptr; + uint8_t pkt_prev_nh; + unsigned int minfragsize; + + pkt_ether = (struct ether_header *)pktdata; + pkt_ipv6 = (struct ip6_hdr *)((char *)pkt_ether + idata->linkhsize); + pkt_icmp6 = (struct icmp6_hdr *)((char *)pkt_ipv6 + MIN_IPV6_HLEN); + pkt_icmp6_icmp6 = (struct icmp6_hdr *)((unsigned char *)pkt_icmp6 + sizeof(struct icmp6_hdr) + + sizeof(struct ip6_hdr) + MIN_HBH_LEN); + + pkt_end = (unsigned char *)pktdata + pkthdr->caplen; + + /* The packet length is the minimum of what we capured, and what is specified in the + IPv6 Total Lenght field + */ + if (pkt_end > ((unsigned char *)pkt_icmp6 + ntohs(pkt_ipv6->ip6_plen))) + pkt_end = (unsigned char *)pkt_icmp6 + ntohs(pkt_ipv6->ip6_plen); + + switch (pkt_icmp6->icmp6_type) { + case ICMP6_ECHO_REPLY: + /* + Discard the packet if it is not of the minimum size to contain an ICMPv6 + header and the payload we included in the ICMPv6 Echo Request + */ + if ((pkt_end - (unsigned char *)pkt_icmp6) < (sizeof(struct icmp6_hdr) + fsize) && + (pkt_end - (unsigned char *)pkt_ipv6) < MIN_IPV6_MTU) { + return 0; + } + + /* Check that the ICMPv6 checksum is correct */ + if (in_chksum(pkt_ipv6, pkt_icmp6, pkt_end - ((unsigned char *)pkt_icmp6), IPPROTO_ICMPV6) != 0) { + return 0; + } + + if (pkt_icmp6->icmp6_data16[0] != htons(getpid())) { + return 0; + } + + if (tstamp_f) { + pkt_ptr = ((unsigned char *)pkt_icmp6 + sizeof(struct icmp6_hdr)); + + if (*((uint32_t *)pkt_ptr) != (*((uint32_t *)(pkt_ptr + sizeof(uint32_t))) ^ 0xabcdabcd)) { + return 0; + } + } + + break; + + case ICMP6_TIME_EXCEEDED: + /* + Discard the packet if it is not of the minimum size to contain an ICMPv6 + header and the payload we included in the ICMPv6 Echo Request + */ + minfragsize = sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr) + + sizeof(struct ip6_frag) + sizeof(struct icmp6_hdr) + (fsize_f ? fsize : MIN_FRAG_SIZE) + + (tstamp_f ? (sizeof(time_t) + sizeof(uint32_t)) : 0); + + if (((pkt_end - (unsigned char *)pkt_ipv6) < minfragsize) && + (pkt_end - (unsigned char *)pkt_ipv6) < MIN_IPV6_MTU) { + return 0; + } + + pkt_ipv6_ipv6 = (struct ip6_hdr *)((unsigned char *)pkt_icmp6 + sizeof(struct icmp6_hdr)); + pkt_fh_fh = NULL; + pkt_ext = (struct ip6_ext *)((unsigned char *)pkt_ipv6_ipv6 + sizeof(struct ip6_hdr)); + pkt_prev_nh = (pkt_ipv6_ipv6->ip6_nxt); + + while (pkt_prev_nh != IPPROTO_ICMPV6 && ((unsigned char *)pkt_ext + (pkt_ext->ip6e_len * 8 + 1)) < pkt_end) { + + if (pkt_prev_nh == IPPROTO_FRAGMENT) + pkt_fh_fh = (struct ip6_frag *)pkt_ext; + + pkt_prev_nh = pkt_ext->ip6e_nxt; + pkt_ext = (struct ip6_ext *)((unsigned char *)pkt_ext + ((pkt_ext->ip6e_len + 1) * 8)); + } + + if (pkt_prev_nh == IPPROTO_ICMPV6) { + pkt_icmp6_icmp6 = (struct icmp6_hdr *)pkt_ext; + + if (((unsigned char *)pkt_icmp6_icmp6 + (sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr) + + sizeof(struct ip6_frag) + sizeof(struct icmp6_hdr))) > pkt_end) { + return 0; + } + } + else { + return 0; + } + + if (pkt_fh_fh == NULL) + return 0; + + /* + * We can only check the embedded ICMPv6 header if the embedded fragment is the first fragment of + * a packet + */ + if (ntohs(pkt_fh_fh->ip6f_offlg & IP6F_OFF_MASK) == 0) { + if (pkt_icmp6_icmp6->icmp6_type != ICMP6_ECHO_REQUEST) { + return 0; + } + + if (pkt_icmp6_icmp6->icmp6_data16[0] != htons(getpid())) { + return 0; + } + + if (tstamp_f) { + pkt_ptr = ((unsigned char *)pkt_icmp6_icmp6 + sizeof(struct icmp6_hdr)); + if (*(uint32_t *)pkt_ptr != (*(uint32_t *)(pkt_ptr + sizeof(uint32_t)) ^ 0xabcdabcd)) { + return 0; + } + } + } + else { + return 0; + } + + break; + + default: + return 0; + break; + } + + /* + Check that the Source Address of the Packet is "valid" + */ + if (IN6_IS_ADDR_UNSPECIFIED(&(pkt_ipv6->ip6_src))) { + return 0; + } + + if (IN6_IS_ADDR_LOOPBACK(&(pkt_ipv6->ip6_src))) { + return 0; + } + + if (IN6_IS_ADDR_MULTICAST(&(pkt_ipv6->ip6_src))) { + return 0; + } + + /* + Check that that the Destination Address of the incoming packet is one + of our addresses. + */ + if (!(floodf_f && srcprefix_f) && !is_eq_in6_addr(&(idata->srcaddr), &(pkt_ipv6->ip6_dst))) { + return 0; + } + + return 1; } - - /* * Function: valid_icmp6_response2() * * Checks whether the response to an ICMPv6 probe (for identifying the fragment reassembly policy) is valid */ -int valid_icmp6_response2(struct iface_data *idata, struct pcap_pkthdr *pkthdr, const u_char *pktdata, unsigned int minsize){ - - struct ether_header *pkt_ether; - struct ip6_hdr *pkt_ipv6, *pkt_ipv6_ipv6; - struct ip6_ext *pkt_ext; - struct icmp6_hdr *pkt_icmp6, *pkt_icmp6_icmp6; - struct ip6_frag *pkt_fh_fh; - unsigned char *pkt_end; - uint8_t pkt_prev_nh; - - pkt_ether = (struct ether_header *) pktdata; - pkt_ipv6 = (struct ip6_hdr *)((char *) pkt_ether + idata->linkhsize); - pkt_icmp6 = (struct icmp6_hdr *) ((char *) pkt_ipv6 + MIN_IPV6_HLEN); - - - pkt_end = (unsigned char *) pktdata + pkthdr->caplen; - - /* The packet length is the minimum of what we capured, and what is specified in the - IPv6 Total Lenght field - */ - if( pkt_end > ((unsigned char *)pkt_icmp6 + ntohs(pkt_ipv6->ip6_plen)) ) - pkt_end = (unsigned char *)pkt_icmp6 + ntohs(pkt_ipv6->ip6_plen); - - switch(pkt_icmp6->icmp6_type){ - case ICMP6_ECHO_REPLY: - /* - Discard the packet if it is not of the minimum size to contain an ICMPv6 - header and the payload we included in the ICMPv6 Echo Request - */ - if( (pkt_end - (unsigned char *) pkt_ipv6) < minsize && (pkt_end - (unsigned char *) pkt_ipv6) < MIN_IPV6_MTU){ - return 0; - } - - /* Check that the ICMPv6 checksum is correct */ - if(in_chksum(pkt_ipv6, pkt_icmp6, pkt_end-((unsigned char *)pkt_icmp6), IPPROTO_ICMPV6) != 0){ - return 0; - } - - if(pkt_icmp6->icmp6_data16[0] != htons(getpid())){ - return 0; - } - - break; - - case ICMP6_TIME_EXCEEDED: - /* - Discard the packet if it is not of the minimum size to contain an ICMPv6 - header and the payload we included in the ICMPv6 Echo Request - */ - if( (pkt_end - (unsigned char *) pkt_ipv6) < minsize \ - && (pkt_end - (unsigned char *) pkt_ipv6) < MIN_IPV6_MTU){ - return 0; - } - - pkt_ipv6_ipv6= (struct ip6_hdr *) ((unsigned char *)pkt_icmp6+ sizeof(struct icmp6_hdr)); - pkt_fh_fh= NULL; - pkt_ext= (struct ip6_ext *) ((unsigned char *)pkt_ipv6_ipv6 + sizeof(struct ip6_hdr)); - pkt_prev_nh= (pkt_ipv6_ipv6->ip6_nxt); - - while(pkt_prev_nh != IPPROTO_ICMPV6 && \ - ( (unsigned char *)pkt_ext + (pkt_ext->ip6e_len * 8 + 1)) < pkt_end){ - - if(pkt_prev_nh == IPPROTO_FRAGMENT) - pkt_fh_fh= (struct ip6_frag *) pkt_ext; - - pkt_prev_nh= pkt_ext->ip6e_nxt; - pkt_ext= (struct ip6_ext *) ( (unsigned char *)pkt_ext + ((pkt_ext->ip6e_len + 1) * 8)); - } - - if(pkt_prev_nh == IPPROTO_ICMPV6){ - pkt_icmp6_icmp6= (struct icmp6_hdr *) pkt_ext; - - if( ((unsigned char *) pkt_icmp6_icmp6 + (sizeof(struct icmp6_hdr)+ sizeof(struct ip6_hdr)+ \ - sizeof(struct ip6_frag)+sizeof(struct icmp6_hdr))) > pkt_end){ - return 0; - } - } - else{ - return 0; - } - - if(pkt_fh_fh == NULL){ - return 0; - } - - /* - * We can only check the embedded ICMPv6 header if the embedded fragment is the first fragment of - * a packet - */ - if(ntohs(pkt_fh_fh->ip6f_offlg & IP6F_OFF_MASK) == 0){ - if(pkt_icmp6_icmp6->icmp6_type != ICMP6_ECHO_REQUEST){ - return 0; - } - - if(pkt_icmp6_icmp6->icmp6_data16[0] != htons(getpid())){ - return 0; - } - - } - else{ - return 0; - } - - break; - - default: - return 0; - break; - } - - /* - Check that the Source Address of the Packet is "valid" - */ - if(IN6_IS_ADDR_UNSPECIFIED(&(pkt_ipv6->ip6_src))){ - return 0; - } - - if(IN6_IS_ADDR_LOOPBACK(&(pkt_ipv6->ip6_src))){ - return 0; - } - - if(IN6_IS_ADDR_MULTICAST(&(pkt_ipv6->ip6_src))){ - return 0; - } - - /* - Check that that the Destination Address of the incoming packet is one - of our addresses. - */ - if(!(floodf_f && srcprefix_f) && !is_eq_in6_addr(&(idata->srcaddr), &(pkt_ipv6->ip6_dst))){ - return 0; - } - - return 1; +int valid_icmp6_response2(struct iface_data *idata, struct pcap_pkthdr *pkthdr, const u_char *pktdata, + unsigned int minsize) { + + struct ether_header *pkt_ether; + struct ip6_hdr *pkt_ipv6, *pkt_ipv6_ipv6; + struct ip6_ext *pkt_ext; + struct icmp6_hdr *pkt_icmp6, *pkt_icmp6_icmp6; + struct ip6_frag *pkt_fh_fh; + unsigned char *pkt_end; + uint8_t pkt_prev_nh; + + pkt_ether = (struct ether_header *)pktdata; + pkt_ipv6 = (struct ip6_hdr *)((char *)pkt_ether + idata->linkhsize); + pkt_icmp6 = (struct icmp6_hdr *)((char *)pkt_ipv6 + MIN_IPV6_HLEN); + + pkt_end = (unsigned char *)pktdata + pkthdr->caplen; + + /* The packet length is the minimum of what we capured, and what is specified in the + IPv6 Total Lenght field + */ + if (pkt_end > ((unsigned char *)pkt_icmp6 + ntohs(pkt_ipv6->ip6_plen))) + pkt_end = (unsigned char *)pkt_icmp6 + ntohs(pkt_ipv6->ip6_plen); + + switch (pkt_icmp6->icmp6_type) { + case ICMP6_ECHO_REPLY: + /* + Discard the packet if it is not of the minimum size to contain an ICMPv6 + header and the payload we included in the ICMPv6 Echo Request + */ + if ((pkt_end - (unsigned char *)pkt_ipv6) < minsize && (pkt_end - (unsigned char *)pkt_ipv6) < MIN_IPV6_MTU) { + return 0; + } + + /* Check that the ICMPv6 checksum is correct */ + if (in_chksum(pkt_ipv6, pkt_icmp6, pkt_end - ((unsigned char *)pkt_icmp6), IPPROTO_ICMPV6) != 0) { + return 0; + } + + if (pkt_icmp6->icmp6_data16[0] != htons(getpid())) { + return 0; + } + + break; + + case ICMP6_TIME_EXCEEDED: + /* + Discard the packet if it is not of the minimum size to contain an ICMPv6 + header and the payload we included in the ICMPv6 Echo Request + */ + if ((pkt_end - (unsigned char *)pkt_ipv6) < minsize && (pkt_end - (unsigned char *)pkt_ipv6) < MIN_IPV6_MTU) { + return 0; + } + + pkt_ipv6_ipv6 = (struct ip6_hdr *)((unsigned char *)pkt_icmp6 + sizeof(struct icmp6_hdr)); + pkt_fh_fh = NULL; + pkt_ext = (struct ip6_ext *)((unsigned char *)pkt_ipv6_ipv6 + sizeof(struct ip6_hdr)); + pkt_prev_nh = (pkt_ipv6_ipv6->ip6_nxt); + + while (pkt_prev_nh != IPPROTO_ICMPV6 && ((unsigned char *)pkt_ext + (pkt_ext->ip6e_len * 8 + 1)) < pkt_end) { + + if (pkt_prev_nh == IPPROTO_FRAGMENT) + pkt_fh_fh = (struct ip6_frag *)pkt_ext; + + pkt_prev_nh = pkt_ext->ip6e_nxt; + pkt_ext = (struct ip6_ext *)((unsigned char *)pkt_ext + ((pkt_ext->ip6e_len + 1) * 8)); + } + + if (pkt_prev_nh == IPPROTO_ICMPV6) { + pkt_icmp6_icmp6 = (struct icmp6_hdr *)pkt_ext; + + if (((unsigned char *)pkt_icmp6_icmp6 + (sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr) + + sizeof(struct ip6_frag) + sizeof(struct icmp6_hdr))) > pkt_end) { + return 0; + } + } + else { + return 0; + } + + if (pkt_fh_fh == NULL) { + return 0; + } + + /* + * We can only check the embedded ICMPv6 header if the embedded fragment is the first fragment of + * a packet + */ + if (ntohs(pkt_fh_fh->ip6f_offlg & IP6F_OFF_MASK) == 0) { + if (pkt_icmp6_icmp6->icmp6_type != ICMP6_ECHO_REQUEST) { + return 0; + } + + if (pkt_icmp6_icmp6->icmp6_data16[0] != htons(getpid())) { + return 0; + } + } + else { + return 0; + } + + break; + + default: + return 0; + break; + } + + /* + Check that the Source Address of the Packet is "valid" + */ + if (IN6_IS_ADDR_UNSPECIFIED(&(pkt_ipv6->ip6_src))) { + return 0; + } + + if (IN6_IS_ADDR_LOOPBACK(&(pkt_ipv6->ip6_src))) { + return 0; + } + + if (IN6_IS_ADDR_MULTICAST(&(pkt_ipv6->ip6_src))) { + return 0; + } + + /* + Check that that the Destination Address of the incoming packet is one + of our addresses. + */ + if (!(floodf_f && srcprefix_f) && !is_eq_in6_addr(&(idata->srcaddr), &(pkt_ipv6->ip6_dst))) { + return 0; + } + + return 1; } - /* * Function: test_frag_pattern() * * Check whether a specific pattern is present in a portion of an IPv6 fragment */ -int test_frag_pattern(unsigned char *ptr, unsigned int size, char *block){ - unsigned int i; +int test_frag_pattern(unsigned char *ptr, unsigned int size, char *block) { + unsigned int i; - for(i=0; i. * * Build with: make icmp6 - * + * * The libpcap library must be previously installed on your system. * * Please send any bug reports to Fernando Gont */ +#include #include #include -#include -#include #include -#include +#include #include +#include +#include #include #include -#include #include +#include +#include #include #include -#include -#include +#include #include +#include +#include #include -#include #include -#include -#include #include "icmp6.h" #include "ipv6toolkit.h" #include "libipv6.h" - /* Function prototypes */ -void init_packet_data(struct iface_data *); -void send_packet(struct iface_data *, const u_char *, struct pcap_pkthdr *); -void print_attack_info(struct iface_data *); -void usage(void); -void print_help(void); +void init_packet_data(struct iface_data *); +void send_packet(struct iface_data *, const u_char *, struct pcap_pkthdr *); +void print_attack_info(struct iface_data *); +void usage(void); +void print_help(void); /* Flags used for the ICMPv6 Redirect (specifically) */ -unsigned int icmp6type_f=0, icmp6code_f=0, mtu_f=0, pointer_f=0; -unsigned int targetaddr_f=0, redirprefix_f=0, targetportl_f=0, targetporth_f=0; -unsigned int peeraddr_f=0, peerportl_f=0, peerporth_f=0; -unsigned int rhip6_f=0, rhtcp_f=0, rhudp_f=0, rhicmp6_f=0, nopayload_f=0, rheader_f=0; -unsigned int tcpseq_f=0, tcpack_f=0, tcpurg_f=0, tcpflags_f=0, tcpwin_f=0; -unsigned int icmp6id_f=0, icmp6seq_f=0; -unsigned int rhlength_f=0, floodr_f=0, respmcast_f=0, makeonlink_f=0; -unsigned int ip6hoplimit_f=0, ip6length_f=0, rhdefault_f=0; -unsigned int learnrouter_f=0, sanityfilters_f=0, useaddrkey_f=0; +unsigned int icmp6type_f = 0, icmp6code_f = 0, mtu_f = 0, pointer_f = 0; +unsigned int targetaddr_f = 0, redirprefix_f = 0, targetportl_f = 0, targetporth_f = 0; +unsigned int peeraddr_f = 0, peerportl_f = 0, peerporth_f = 0; +unsigned int rhip6_f = 0, rhtcp_f = 0, rhudp_f = 0, rhicmp6_f = 0, nopayload_f = 0, rheader_f = 0; +unsigned int tcpseq_f = 0, tcpack_f = 0, tcpurg_f = 0, tcpflags_f = 0, tcpwin_f = 0; +unsigned int icmp6id_f = 0, icmp6seq_f = 0; +unsigned int rhlength_f = 0, floodr_f = 0, respmcast_f = 0, makeonlink_f = 0; +unsigned int ip6hoplimit_f = 0, ip6length_f = 0, rhdefault_f = 0; +unsigned int learnrouter_f = 0, sanityfilters_f = 0, useaddrkey_f = 0; /* Variables used for ICMPv6 Error messages (specifically) */ -uint8_t icmp6type=0, icmp6code=0; -uint32_t mtu, pointer; -uint16_t ip6length; -struct in6_addr targetaddr, peeraddr; -unsigned char redirpreflen, targetpreflen; -unsigned int targetport, peerport; -uint16_t targetportl, targetporth, peerportl, peerporth, auxint16; -uint16_t tcpurg, tcpwin, icmp6id, icmp6seq; -uint32_t tcpseq, tcpack; -uint8_t tcpflags=0, ip6hoplimit; -struct ip6_hdr *rhipv6; -struct udp_hdr *rhudp; -struct tcp_hdr *rhtcp; -struct icmp6_hdr *rhicmp6; -unsigned int nredirs, redirs; -unsigned int rhbytes, rhlength, currentsize; -unsigned char rh_hoplimit; -unsigned char rhbuff[100]; /* This one must be able to hold the IPv6 header and the upper layer header */ - +uint8_t icmp6type = 0, icmp6code = 0; +uint32_t mtu, pointer; +uint16_t ip6length; +struct in6_addr targetaddr, peeraddr; +unsigned char redirpreflen, targetpreflen; +unsigned int targetport, peerport; +uint16_t targetportl, targetporth, peerportl, peerporth, auxint16; +uint16_t tcpurg, tcpwin, icmp6id, icmp6seq; +uint32_t tcpseq, tcpack; +uint8_t tcpflags = 0, ip6hoplimit; +struct ip6_hdr *rhipv6; +struct udp_hdr *rhudp; +struct tcp_hdr *rhtcp; +struct icmp6_hdr *rhicmp6; +unsigned int nredirs, redirs; +unsigned int rhbytes, rhlength, currentsize; +unsigned char rh_hoplimit; +unsigned char rhbuff[100]; /* This one must be able to hold the IPv6 header and the upper layer header */ /* Variables used for learning the default router */ -struct iface_data idata; -struct ether_addr router_ether, rs_ether; -struct in6_addr router_ipv6, rs_ipv6; -struct in6_addr randprefix; -unsigned char randpreflen; - +struct iface_data idata; +struct ether_addr router_ether, rs_ether; +struct in6_addr router_ipv6, rs_ipv6; +struct in6_addr randprefix; +unsigned char randpreflen; /* Data structures for packets read from the wire */ -struct pcap_pkthdr *pkthdr; -const u_char *pktdata; -unsigned char *pkt_end; -struct ether_header *pkt_ether; -struct ip6_hdr *pkt_ipv6; -struct in6_addr *pkt_ipv6addr; -unsigned int pktbytes; - - -bpf_u_int32 my_netmask; -bpf_u_int32 my_ip; -struct bpf_program pcap_filter; -char dev[64], errbuf[PCAP_ERRBUF_SIZE]; -unsigned char buffer[65556], buffrh[MIN_IPV6_HLEN + MIN_TCP_HLEN]; -unsigned char *v6buffer, *ptr, *startofprefixes; -char *pref; - -struct ip6_hdr *ipv6; -struct icmp6_hdr *icmp6; - -struct ether_header *ethernet; -struct dlt_null *dlt_null; - -char *lasts, *rpref; -char *charptr; - -int nw; -unsigned long ul_res, ul_val; -unsigned int i, j, startrand; -unsigned int skip; -unsigned int ntargets, sources, nsources, targets, nsleep; - -uint16_t mask; -uint8_t hoplimit; - -char plinkaddr[ETHER_ADDR_PLEN]; -char psrcaddr[INET6_ADDRSTRLEN], pdstaddr[INET6_ADDRSTRLEN], pv6addr[INET6_ADDRSTRLEN]; -unsigned char floodt_f=0, listen_f = 0, multicastdst_f=0, accepted_f=0, loop_f=0, sleep_f=0; -unsigned char targetprefix_f=0, hoplimit_f=0, newdata_f=0, floods_f=0; +struct pcap_pkthdr *pkthdr; +const u_char *pktdata; +unsigned char *pkt_end; +struct ether_header *pkt_ether; +struct ip6_hdr *pkt_ipv6; +struct in6_addr *pkt_ipv6addr; +unsigned int pktbytes; + +bpf_u_int32 my_netmask; +bpf_u_int32 my_ip; +struct bpf_program pcap_filter; +char dev[64], errbuf[PCAP_ERRBUF_SIZE]; +unsigned char buffer[65556], buffrh[MIN_IPV6_HLEN + MIN_TCP_HLEN]; +unsigned char *v6buffer, *ptr, *startofprefixes; +char *pref; + +struct ip6_hdr *ipv6; +struct icmp6_hdr *icmp6; + +struct ether_header *ethernet; +struct dlt_null *dlt_null; + +char *lasts, *rpref; +char *charptr; + +int nw; +unsigned long ul_res, ul_val; +unsigned int i, j, startrand; +unsigned int skip; +unsigned int ntargets, sources, nsources, targets, nsleep; + +uint16_t mask; +uint8_t hoplimit; + +char plinkaddr[ETHER_ADDR_PLEN]; +char psrcaddr[INET6_ADDRSTRLEN], pdstaddr[INET6_ADDRSTRLEN], pv6addr[INET6_ADDRSTRLEN]; +unsigned char floodt_f = 0, listen_f = 0, multicastdst_f = 0, accepted_f = 0, loop_f = 0, sleep_f = 0; +unsigned char targetprefix_f = 0, hoplimit_f = 0, newdata_f = 0, floods_f = 0; /* Support for Extension Headers */ -unsigned int dstopthdrs, dstoptuhdrs, hbhopthdrs; -char hbhopthdr_f=0, dstoptuhdr_f=0, dstopthdr_f=0; -unsigned char *dstopthdr[MAX_DST_OPT_HDR], *dstoptuhdr[MAX_DST_OPT_U_HDR]; -unsigned char *hbhopthdr[MAX_HBH_OPT_HDR]; -unsigned int dstopthdrlen[MAX_DST_OPT_HDR], dstoptuhdrlen[MAX_DST_OPT_U_HDR]; -unsigned int hbhopthdrlen[MAX_HBH_OPT_HDR], m, pad; - -struct ip6_frag fraghdr, *fh; -struct ip6_hdr *fipv6; -unsigned char fragh_f=0; -unsigned char fragbuffer[ETHER_HDR_LEN+MIN_IPV6_HLEN+MAX_IPV6_PAYLOAD]; -unsigned char *fragpart, *fptr, *fptrend, *ptrend, *ptrhdr, *ptrhdrend; -unsigned int hdrlen, ndstopthdr=0, nhbhopthdr=0, ndstoptuhdr=0; -unsigned int nfrags, fragsize; -unsigned char *prev_nh, *startoffragment; - -struct filters filters; - -int main(int argc, char **argv){ - extern char *optarg; - char *endptr; /* Used by strtoul() */ - int r, sel; - fd_set sset, rset; +unsigned int dstopthdrs, dstoptuhdrs, hbhopthdrs; +char hbhopthdr_f = 0, dstoptuhdr_f = 0, dstopthdr_f = 0; +unsigned char *dstopthdr[MAX_DST_OPT_HDR], *dstoptuhdr[MAX_DST_OPT_U_HDR]; +unsigned char *hbhopthdr[MAX_HBH_OPT_HDR]; +unsigned int dstopthdrlen[MAX_DST_OPT_HDR], dstoptuhdrlen[MAX_DST_OPT_U_HDR]; +unsigned int hbhopthdrlen[MAX_HBH_OPT_HDR], m, pad; + +struct ip6_frag fraghdr, *fh; +struct ip6_hdr *fipv6; +unsigned char fragh_f = 0; +unsigned char fragbuffer[ETHER_HDR_LEN + MIN_IPV6_HLEN + MAX_IPV6_PAYLOAD]; +unsigned char *fragpart, *fptr, *fptrend, *ptrend, *ptrhdr, *ptrhdrend; +unsigned int hdrlen, ndstopthdr = 0, nhbhopthdr = 0, ndstoptuhdr = 0; +unsigned int nfrags, fragsize; +unsigned char *prev_nh, *startoffragment; + +struct filters filters; + +int main(int argc, char **argv) { + extern char *optarg; + char *endptr; /* Used by strtoul() */ + int r, sel; + fd_set sset, rset; #if defined(sun) || defined(__sun) - struct timeval timeout; + struct timeval timeout; #endif - struct target_ipv6 targetipv6; - - static struct option longopts[] = { - {"interface", required_argument, 0, 'i'}, - {"src-addr", required_argument, 0, 's'}, - {"dst-addr", required_argument, 0, 'd'}, - {"hop-limit", required_argument, 0, 'c'}, - {"dst-opt-hdr", required_argument, 0, 'u'}, - {"dst-opt-u-hdr", required_argument, 0, 'U'}, - {"hbh-opt-hdr", required_argument, 0, 'H'}, - {"frag-hdr", required_argument, 0, 'y'}, - {"link-src-addr", required_argument, 0, 'S'}, - {"link-dst-addr", required_argument, 0, 'D'}, - {"icmp6", required_argument, 0, 't'}, - {"icmp6-dest-unreach", required_argument, 0, 'e'}, - {"icmp6-packet-too-big", no_argument, 0, 'E'}, - {"icmp6-time-exceeded", required_argument, 0, 'A'}, - {"icmp6-param-problem", no_argument, 0, 'R'}, - {"mtu", required_argument, 0, 'm'}, - {"pointer", required_argument, 0, 'O'}, - {"sanity-filters", no_argument, 0, 'f'}, - {"payload-type", required_argument, 0, 'p'}, - {"payload-size", required_argument, 0, 'P'}, - {"no-payload", no_argument, 0, 'n'}, - {"ipv6-hlim", required_argument, 0, 'C'}, - {"target-addr", required_argument, 0, 'r'}, - {"peer-addr", required_argument, 0, 'x'}, - {"target-port", required_argument, 0, 'o'}, - {"peer-port", required_argument, 0, 'a'}, - {"tcp-flags", required_argument, 0, 'X'}, - {"tcp-seq", required_argument, 0, 'q'}, - {"tcp-ack", required_argument, 0, 'Q'}, - {"tcp-urg", required_argument, 0, 'V'}, - {"tcp-win", required_argument, 0, 'w'}, - {"resp-mcast", no_argument, 0, 'M'}, - {"block-src-addr", required_argument, 0, 'j'}, - {"block-dst-addr", required_argument, 0, 'k'}, - {"block-link-src-addr", required_argument, 0, 'J'}, - {"block-link-dst-addr", required_argument, 0, 'K'}, - {"accept-src-addr", required_argument, 0, 'b'}, - {"accept-dst-addr", required_argument, 0, 'g'}, - {"accept-link-src-addr", required_argument, 0, 'B'}, - {"accept-link-dst-addr", required_argument, 0, 'G'}, - {"sanity-filters", no_argument, 0, 'f'}, - {"loop", no_argument, 0, 'l'}, - {"sleep", required_argument, 0, 'z'}, - {"listen", no_argument, 0, 'L'}, - {"verbose", no_argument, 0, 'v'}, - {"help", no_argument, 0, 'h'}, - {0, 0, 0, 0 } - }; - - const char shortopts[]= "i:s:d:c:u:U:H:y:S:D:r:t:e:EA:R:m:O:p:P:nC:x:o:a:X:q:Q:V:w:MO:j:k:J:K:b:g:B:G:flz:Lvh"; - - char option; - - if(argc<=1){ - usage(); - exit(EXIT_FAILURE); - } - - /* Initialize filters structure */ - if(init_filters(&filters) == -1){ - puts("Error initializing internal data structure"); - exit(EXIT_FAILURE); - } - - if(init_iface_data(&idata) == FAILURE){ - puts("Error initializing internal data structure"); - exit(EXIT_FAILURE); - } - - hoplimit=64+random()%180; - - while((r=getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { - option= r; - - switch(option) { - - case 'i': /* Interface */ - strncpy(idata.iface, optarg, IFACE_LENGTH); - idata.iface[IFACE_LENGTH-1]=0; - idata.ifindex= if_nametoindex(idata.iface); - idata.iface_f=TRUE; - break; - - case 's': /* IPv6 Source Address */ - if(idata.srcaddr_f){ - puts("Error: Multiple '-s' options have been specified"); - exit(EXIT_FAILURE); - } - - if((charptr = strtok_r(optarg, "/", &lasts)) == NULL){ - puts("Error in Source Address"); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, charptr, &(idata.srcaddr)) <= 0){ - puts("inet_pton(): Source Address not valid"); - exit(EXIT_FAILURE); - } - - idata.srcaddr_f = 1; - - if((charptr = strtok_r(NULL, " ", &lasts)) != NULL){ - idata.srcpreflen = atoi(charptr); - - if(idata.srcpreflen>128){ - puts("Prefix length error in IPv6 Source Address"); - exit(EXIT_FAILURE); - } - - if(idata.srcpreflen == 64) - useaddrkey_f= 1; - - sanitize_ipv6_prefix(&(idata.srcaddr), idata.srcpreflen); - idata.srcprefix_f=1; - } - - break; - - case 'd': /* IPv6 Destination Address */ - strncpy( targetipv6.name, optarg, NI_MAXHOST); - targetipv6.name[NI_MAXHOST-1]= 0; - targetipv6.flags= AI_CANONNAME; - - if( (r=get_ipv6_target(&targetipv6)) != 0){ - - if(r < 0){ - printf("Unknown Destination: %s\n", gai_strerror(targetipv6.res)); - } - else{ - puts("Unknown Destination: No IPv6 address found for specified destination"); - } - - exit(EXIT_FAILURE); - } - - idata.dstaddr= targetipv6.ip6; - idata.dstaddr_f = 1; - break; - - case 'c': /* Hop Limit */ - hoplimit= atoi(optarg); - hoplimit_f=1; - break; - - case 'u': /* Destinations Options Header */ - if(ndstopthdr >= MAX_DST_OPT_HDR){ - puts("Too many Destination Options Headers"); - exit(EXIT_FAILURE); - } - - hdrlen= atoi(optarg); - - if(hdrlen < 8){ - puts("Bad length in Destination Options Header"); - exit(EXIT_FAILURE); - } - - hdrlen = ((hdrlen+7)/8) * 8; - dstopthdrlen[ndstopthdr]= hdrlen; - - if( (dstopthdr[ndstopthdr]= malloc(hdrlen)) == NULL){ - puts("Not enough memory for Destination Options Header"); - exit(EXIT_FAILURE); - } - - ptrhdr= dstopthdr[ndstopthdr] + 2; - ptrhdrend= dstopthdr[ndstopthdr] + hdrlen; - - while( ptrhdr < ptrhdrend){ - - if( (ptrhdrend-ptrhdr)>257) - pad= 257; - else - pad= ptrhdrend-ptrhdr; - - if(!insert_pad_opt(ptrhdr, ptrhdrend, pad)){ - puts("Destination Options Header Too Big"); - exit(EXIT_FAILURE); - } - - ptrhdr= ptrhdr + pad; - } - - *(dstopthdr[ndstopthdr]+1)= (hdrlen/8)-1; - ndstopthdr++; - dstopthdr_f=1; - break; - - case 'U': /* Destination Options Header (Unfragmentable Part) */ - if(ndstoptuhdr >= MAX_DST_OPT_U_HDR){ - puts("Too many Destination Options Headers (Unfragmentable Part)"); - exit(EXIT_FAILURE); - } - - hdrlen= atoi(optarg); - - if(hdrlen < 8){ - puts("Bad length in Destination Options Header (Unfragmentable Part)"); - exit(EXIT_FAILURE); - } - - hdrlen = ((hdrlen+7)/8) * 8; - dstoptuhdrlen[ndstoptuhdr]= hdrlen; - - if( (dstoptuhdr[ndstoptuhdr]= malloc(hdrlen)) == NULL){ - puts("Not enough memory for Destination Options Header (Unfragmentable Part)"); - exit(EXIT_FAILURE); - } - - ptrhdr= dstoptuhdr[ndstoptuhdr]+2; - ptrhdrend= dstoptuhdr[ndstoptuhdr] + hdrlen; - - while( ptrhdr < ptrhdrend){ - - if( (ptrhdrend-ptrhdr)>257) - pad= 257; - else - pad= ptrhdrend-ptrhdr; - - if(!insert_pad_opt(ptrhdr, ptrhdrend, pad)){ - puts("Destination Options Header (Unfragmentable Part) Too Big"); - exit(EXIT_FAILURE); - } - - ptrhdr = ptrhdr + pad; - } - - *(dstoptuhdr[ndstoptuhdr]+1)= (hdrlen/8) - 1; - ndstoptuhdr++; - dstoptuhdr_f=1; - break; - - case 'H': /* Hop-by-Hop Options Header */ - if(nhbhopthdr >= MAX_HBH_OPT_HDR){ - puts("Too many Hop-by-Hop Options Headers"); - exit(EXIT_FAILURE); - } - - hdrlen= atoi(optarg); - - if(hdrlen < 8){ - puts("Bad length in Hop-by-Hop Options Header"); - exit(EXIT_FAILURE); - } - - hdrlen = ((hdrlen+7)/8) * 8; - hbhopthdrlen[nhbhopthdr]= hdrlen; - - if( (hbhopthdr[nhbhopthdr]= malloc(hdrlen)) == NULL){ - puts("Not enough memory for Hop-by-Hop Options Header"); - exit(EXIT_FAILURE); - } - - ptrhdr= hbhopthdr[nhbhopthdr] + 2; - ptrhdrend= hbhopthdr[nhbhopthdr] + hdrlen; - - - while( ptrhdr < ptrhdrend){ - - if( (ptrhdrend-ptrhdr)>257) - pad= 257; - else - pad= ptrhdrend-ptrhdr; - - if(!insert_pad_opt(ptrhdr, ptrhdrend, pad)){ - puts("Hop-by-Hop Options Header Too Big"); - exit(EXIT_FAILURE); - } - - ptrhdr = ptrhdr + pad; - } - - *(hbhopthdr[nhbhopthdr]+1)= (hdrlen/8) - 1; - nhbhopthdr++; - hbhopthdr_f=1; - break; - - case 'y': /* Fragment header */ - nfrags= atoi(optarg); - if(nfrags < 8){ - puts("Error in Fragmentation option: Fragment Size must be at least 8 bytes"); - exit(EXIT_FAILURE); - } - - fragh_f= 1; - break; - - case 'S': /* Source Ethernet address */ - if(ether_pton(optarg, &(idata.hsrcaddr), sizeof(idata.hsrcaddr)) == 0){ - puts("Error in Source link-layer address."); - exit(EXIT_FAILURE); - } - - idata.hsrcaddr_f = 1; - break; - - case 'D': /* Destination Ethernet Address */ - if(ether_pton(optarg, &(idata.hdstaddr), sizeof(idata.hdstaddr)) == 0){ - puts("Error in Source link-layer address."); - exit(EXIT_FAILURE); - } - - idata.hdstaddr_f = 1; - break; - - case 'r': /* Target address */ - - if((charptr = strtok_r(optarg, "/", &lasts)) == NULL){ - puts("Error in Redirected Address"); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, charptr, &targetaddr) <= 0){ - puts("inet_pton(): Redirected Address not valid"); - exit(EXIT_FAILURE); - } - - targetaddr_f = 1; - - if((charptr = strtok_r(NULL, " ", &lasts)) != NULL){ - redirpreflen = atoi(charptr); - - if(redirpreflen>128){ - puts("Prefix length error in IPv6 Source Address"); - exit(EXIT_FAILURE); - } - - sanitize_ipv6_prefix(&targetaddr, redirpreflen); - redirprefix_f=1; - } - - break; - - case 't': /* ICMPv6 Type and Code */ - if((charptr = strtok_r(optarg, ":", &lasts)) == NULL){ - puts("Error in ICMPv6 message Type/Code"); - exit(EXIT_FAILURE); - } - - icmp6type= atoi(charptr); - icmp6type_f=1; - - if((charptr = strtok_r(NULL, " ", &lasts)) != NULL){ - icmp6code= atoi(charptr); - icmp6code_f=1; - } - - break; - - case 'e': /* ICMPv6 Destination Unreachable */ - icmp6type= 1; - icmp6type_f= 1; - icmp6code= atoi(optarg); - icmp6code_f= 1; - break; - - case 'E': /* ICMPv6 Packet Too Big */ - icmp6type= 2; - icmp6type_f= 1; - icmp6code= 0; - icmp6code_f= 1; - break; - - case 'A': /* ICMPv6 Time Exceeded */ - icmp6type= 3; - icmp6type_f= 1; - icmp6code= atoi(optarg); - icmp6code_f= 1; - break; - - case 'R': /* ICMPv6 Parameter Problem */ - icmp6type=4; - icmp6type_f= 1; - icmp6code= atoi(optarg); - icmp6code_f= 1; - break; - - case 'm': /* Next-Hop MTU (for ICMPv6 PTB messages) */ - if((ul_res = strtoul(optarg, &endptr, 0)) == ULONG_MAX){ - perror("Error in 'MTU' parameter"); - exit(EXIT_FAILURE); - } - - if(endptr != optarg){ - mtu = ul_res; - mtu_f=1; - } - break; - - case 'O': /* Pointer (for ICMPv6 "Parameter Problem" messages) */ - if((ul_res = strtoul(optarg, &endptr, 0)) == ULONG_MAX){ - perror("Error in 'Pointer' parameter"); - exit(EXIT_FAILURE); - } - - if(endptr != optarg){ - pointer = ul_res; - pointer_f=1; - } - break; - - case 'p': /* Protocol used in the ICMPv6 Payload */ - if(strcmp(optarg, "TCP") == 0 || strcmp(optarg, "tcp") == 0) - rhtcp_f = 1; - else if(strcmp(optarg, "ICMP6") == 0 || strcmp(optarg, "ICMPv6") == 0 || \ - strcmp(optarg, "icmpv6") == 0 || strcmp(optarg, "icmp6") == 0) - rhicmp6_f = 1; - else if(strcmp(optarg, "UDP") == 0 || strcmp(optarg, "udp") == 0) - rhudp_f = 1; - else if(strcmp(optarg, "IP6") == 0 || strcmp(optarg, "ip6") == 0 || \ - strcmp(optarg, "IPv6") == 0 || strcmp(optarg, "ipv6") == 0){ - rhip6_f= 1; - } - else{ - puts("Unsupported protocol in option '-p'"); - exit(EXIT_FAILURE); - } - break; - - case 'P': /* Payload Size*/ - rhlength= atoi(optarg); - rhlength= (rhlength<<3) >> 3; /* The Redirected Header has a granularity of 8 bytes */ - rhlength_f= 1; - break; - - case 'n': /* No ICMPv6 Payload */ - nopayload_f=1; - break; - - case 'C': /* Hop Limit of the IPv6 Payload */ - ip6hoplimit= atoi(optarg); - ip6hoplimit_f=1; - break; - - case 'x': /* Source Address of the ICMPv6 payload */ - strncpy( targetipv6.name, optarg, NI_MAXHOST); - targetipv6.name[NI_MAXHOST-1]= 0; - targetipv6.flags= AI_CANONNAME; - - if( (r=get_ipv6_target(&targetipv6)) != 0){ - - if(r < 0){ - printf("Unknown Destination: %s\n", gai_strerror(targetipv6.res)); - } - else{ - puts("Unknown Destination: No IPv6 address found for specified destination"); - } - - exit(EXIT_FAILURE); - } - - peeraddr= targetipv6.ip6; - peeraddr_f = 1; - break; - - case 'o': /* Target port */ - if((charptr = strtok_r(optarg, ":-", &lasts)) == NULL){ - printf("Error in TCP/UDP target port"); - exit(EXIT_FAILURE); - } - - targetportl= atoi(charptr); - targetportl_f= 1; - - if((charptr = strtok_r(NULL, " ", &lasts)) == NULL){ - - targetporth= targetportl; - } - else{ - targetporth=atoi(charptr); - targetporth_f=1; - - if(targetportl > targetporth){ - auxint16= targetportl; - targetportl= targetporth; - targetporth= auxint16; - } - } - break; - - case 'a': /* Peer port */ - if((charptr = strtok_r(optarg, ":-", &lasts)) == NULL){ - printf("Error in TCP/UDP peer port"); - exit(EXIT_FAILURE); - } - - peerportl= atoi(charptr); - peerportl_f= 1; - - if((charptr = strtok_r(NULL, " ", &lasts)) == NULL){ - peerporth= peerportl; - } - else{ - peerporth=atoi(charptr); - peerporth_f=1; - - if(peerportl > peerporth){ - auxint16= peerportl; - peerportl= peerporth; - peerporth= auxint16; - } - } - break; - - case 'X': /* TCP flags */ - charptr = optarg; - while(*charptr){ - switch(*charptr){ - case 'F': - tcpflags= tcpflags | TH_FIN; - break; - - case 'S': - tcpflags= tcpflags | TH_SYN; - break; - - case 'R': - tcpflags= tcpflags | TH_RST; - break; - - case 'P': - tcpflags= tcpflags | TH_PUSH; - break; - - case 'A': - tcpflags= tcpflags | TH_ACK; - break; - - case 'U': - tcpflags= tcpflags | TH_URG; - break; - - case 'X': /* No TCP flags */ - break; - - default: - printf("Unknown TCP flag '%c'\n", *charptr); - exit(EXIT_FAILURE); - break; - } - - if(*charptr == 'X') - break; - - charptr++; - } - - tcpflags_f=1; - break; - - case 'q': /* TCP Sequence Number */ - if((ul_res = strtoul(optarg, &endptr, 0)) == ULONG_MAX){ - perror("Error in 'TCP Sequence NUmber' parameter"); - exit(EXIT_FAILURE); - } - - if(endptr != optarg){ - tcpseq = ul_res; - tcpseq_f=1; - } - - break; - - case 'Q': /* TCP Acknowledgement Number */ - if((ul_res = strtoul(optarg, &endptr, 0)) == ULONG_MAX){ - perror("Error in 'TCP Sequence NUmber' parameter"); - exit(EXIT_FAILURE); - } - - if(endptr != optarg){ - tcpack = ul_res; - tcpack_f=1; - } - break; - - case 'V': /* TCP Urgent Pointer */ - tcpurg= atoi(optarg); - tcpurg_f= 1; - break; - - case 'w': /* TCP Window */ - tcpwin= atoi(optarg); - tcpwin_f=1; - break; - - case 'M': /* Respond to multicast packets */ - respmcast_f=1; - break; - - case 'j': /* IPv6 Source Address (block) filter */ - if(filters.nblocksrc >= MAX_BLOCK_SRC){ - puts("Too many IPv6 Source Address (block) filters."); - exit(EXIT_FAILURE); - } - - if((pref = strtok_r(optarg, "/", &lasts)) == NULL){ - printf("Error in IPv6 Source Address (block) filter number %u.\n", \ - filters.nblocksrc+1); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, pref, &(filters.blocksrc[filters.nblocksrc])) <= 0){ - printf("Error in IPv6 Source Address (block) filter number %u.", \ - filters.nblocksrc+1); - exit(EXIT_FAILURE); - } - - if((charptr = strtok_r(NULL, " ", &lasts)) == NULL){ - filters.blocksrclen[filters.nblocksrc] = 128; - } - else{ - filters.blocksrclen[filters.nblocksrc] = atoi(charptr); - - if(filters.blocksrclen[filters.nblocksrc]>128){ - printf("Length error in IPv6 Source Address (block) filter number %u.\n", \ - filters.nblocksrc+1); - exit(EXIT_FAILURE); - } - } - - sanitize_ipv6_prefix(&(filters.blocksrc[filters.nblocksrc]), filters.blocksrclen[filters.nblocksrc]); - (filters.nblocksrc)++; - break; - - case 'k': /* IPv6 Destination Address (block) filter */ - if(filters.nblockdst >= MAX_BLOCK_DST){ - puts("Too many IPv6 Destination Address (block) filters."); - exit(EXIT_FAILURE); - } - - if((pref = strtok_r(optarg, "/", &lasts)) == NULL){ - printf("Error in IPv6 Destination Address (block) filter number %u.\n", \ - filters.nblockdst+1); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, pref, &(filters.blockdst[filters.nblockdst])) <= 0){ - printf("Error in IPv6 Source Address (block) filter number %u.", \ - filters.nblockdst+1); - exit(EXIT_FAILURE); - } - - if((charptr = strtok_r(NULL, " ", &lasts)) == NULL){ - filters.blockdstlen[filters.nblockdst] = 128; - } - else{ - filters.blockdstlen[filters.nblockdst] = atoi(charptr); - - if(filters.blockdstlen[filters.nblockdst]>128){ - printf("Length error in IPv6 Source Address (block) filter number %u.\n", \ - filters.nblockdst+1); - exit(EXIT_FAILURE); - } - } - - sanitize_ipv6_prefix(&(filters.blockdst[filters.nblockdst]), filters.blockdstlen[filters.nblockdst]); - (filters.nblockdst)++; - break; - - case 'J': /* Link Source Address (block) filter */ - if(filters.nblocklinksrc > MAX_BLOCK_LINK_SRC){ - puts("Too many link-layer Source Address (accept) filters."); - exit(EXIT_FAILURE); - } - - if(ether_pton(optarg, &(filters.blocklinksrc[filters.nblocklinksrc]), sizeof(struct ether_addr)) == 0){ - printf("Error in link-layer Source Address (blick) filter number %u.\n", \ - filters.nblocklinksrc+1); - exit(EXIT_FAILURE); - } - - (filters.nblocklinksrc)++; - break; - - case 'K': /* Link Destination Address (block) filter */ - if(filters.nblocklinkdst > MAX_BLOCK_LINK_DST){ - puts("Too many link-layer Destination Address (block) filters."); - exit(EXIT_FAILURE); - } - - if(ether_pton(optarg, &(filters.blocklinkdst[filters.nblocklinkdst]), sizeof(struct ether_addr)) == 0){ - printf("Error in link-layer Destination Address (blick) filter number %u.\n", \ - filters.nblocklinkdst+1); - exit(EXIT_FAILURE); - } - - filters.nblocklinkdst++; - break; - - case 'b': /* IPv6 Source Address (accept) filter */ - if(filters.nacceptsrc > MAX_ACCEPT_SRC){ - puts("Too many IPv6 Source Address (accept) filters."); - exit(EXIT_FAILURE); - } - - if((pref = strtok_r(optarg, "/", &lasts)) == NULL){ - printf("Error in IPv6 Source Address (accept) filter number %u.\n", \ - filters.nacceptsrc+1); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, pref, &(filters.acceptsrc[filters.nacceptsrc])) <= 0){ - printf("Error in IPv6 Source Address (accept) filter number %u.\n", \ - filters.nacceptsrc+1); - exit(EXIT_FAILURE); - } - - if((charptr = strtok_r(NULL, " ", &lasts)) == NULL){ - filters.acceptsrclen[filters.nacceptsrc] = 128; - } - else{ - filters.acceptsrclen[filters.nacceptsrc] = atoi(charptr); - - if(filters.acceptsrclen[filters.nacceptsrc]>128){ - printf("Length error in IPv6 Source Address (accept) filter number %u.\n", \ - filters.nacceptsrc+1); - exit(EXIT_FAILURE); - } - } - - sanitize_ipv6_prefix(&(filters.acceptsrc[filters.nacceptsrc]), filters.acceptsrclen[filters.nacceptsrc]); - (filters.nacceptsrc)++; - filters.acceptfilters_f=1; - break; - - - case 'g': /* IPv6 Destination Address (accept) filter */ - if(filters.nacceptdst > MAX_ACCEPT_DST){ - puts("Too many IPv6 Destination Address (accept) filters."); - exit(EXIT_FAILURE); - } - - if((pref = strtok_r(optarg, "/", &lasts)) == NULL){ - printf("Error in IPv6 Destination Address (accept) filter number %u.\n", \ - filters.nacceptdst+1); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, pref, &(filters.acceptdst[filters.nacceptdst])) <= 0){ - printf("Error in IPv6 Source Address (accept) filter number %u.\n", \ - filters.nacceptdst+1); - exit(EXIT_FAILURE); - } - - if((charptr = strtok_r(NULL, " ", &lasts)) == NULL){ - filters.acceptdstlen[filters.nacceptdst] = 128; - } - else{ - filters.acceptdstlen[filters.nacceptdst] = atoi(charptr); - - if(filters.acceptdstlen[filters.nacceptdst] > 128){ - printf("Length error in IPv6 Source Address (accept) filter number %u.\n", \ - filters.nacceptdst+1); - exit(EXIT_FAILURE); - } - } - - sanitize_ipv6_prefix(&(filters.acceptdst[filters.nacceptdst]), filters.acceptdstlen[filters.nacceptdst]); - (filters.nacceptdst)++; - filters.acceptfilters_f=1; - break; - - case 'B': /* Link-layer Source Address (accept) filter */ - if(filters.nacceptlinksrc > MAX_ACCEPT_LINK_SRC){ - puts("Too many link-later Source Address (accept) filters."); - exit(EXIT_FAILURE); - } - - if(ether_pton(optarg, &(filters.acceptlinksrc[filters.nacceptlinksrc]), sizeof(struct ether_addr)) == 0){ - printf("Error in link-layer Source Address (accept) filter number %u.\n", \ - filters.nacceptlinksrc+1); - exit(EXIT_FAILURE); - } - - (filters.nacceptlinksrc)++; - filters.acceptfilters_f=1; - break; - - case 'G': /* Link Destination Address (accept) filter */ - if(filters.nacceptlinkdst > MAX_ACCEPT_LINK_DST){ - puts("Too many link-layer Destination Address (accept) filters."); - exit(EXIT_FAILURE); - } - - if(ether_pton(optarg, &(filters.acceptlinkdst[filters.nacceptlinkdst]), sizeof(struct ether_addr)) == 0){ - printf("Error in link-layer Destination Address (accept) filter number %u.\n",\ - filters.nacceptlinkdst+1); - exit(EXIT_FAILURE); - } - - (filters.nacceptlinkdst)++; - filters.acceptfilters_f=1; - break; - - case 'f': /* Sanity filters */ - sanityfilters_f=1; - break; - - case 'l': /* "Loop mode */ - loop_f = 1; - break; - - case 'z': /* Sleep option */ - nsleep=atoi(optarg); - if(nsleep==0){ - puts("Invalid number of seconds in '-z' option"); - exit(EXIT_FAILURE); - } - - sleep_f=1; - break; - - case 'L': /* "Listen mode */ - listen_f = 1; - break; - - case 'v': /* Be verbose */ - idata.verbose_f++; - break; - - case 'h': /* Help */ - print_help(); - - exit(EXIT_FAILURE); - break; - - default: - usage(); - exit(EXIT_FAILURE); - break; - - } /* switch */ - } /* while(getopt) */ - - if(geteuid()) { - puts("icmp6 needs root privileges to run."); - exit(EXIT_FAILURE); - } - - if(listen_f && !idata.iface_f){ - puts("Must specify a network interface with the -i option when listening mode is selected"); - exit(EXIT_FAILURE); - } - - if(listen_f && loop_f){ - puts("'Error: listen' mode and 'loop' mode are incompatible"); - exit(EXIT_FAILURE); - } - - if(!idata.dstaddr_f && !listen_f){ /* Must specify IPv6 Destination Address if listening mode not used */ - puts("IPv6 Destination Address not specified (and listening mode not selected)"); - exit(EXIT_FAILURE); - } - - if(load_dst_and_pcap(&idata, LOAD_SRC_NXT_HOP) == FAILURE){ - puts("Error while learning Source Address and Next Hop"); - exit(EXIT_FAILURE); - } - - release_privileges(); - - srandom(time(NULL)); - - if(sanityfilters_f){ - if(filters.nblocksrc >= MAX_BLOCK_SRC){ - puts("Too many Source Address (block) filters while adding sanity filters."); - exit(EXIT_FAILURE); - } - - filters.blocksrc[filters.nblocksrc]= idata.srcaddr; - filters.blocksrclen[filters.nblocksrc]=128; - filters.nblocklinksrc++; - } - - if(!sleep_f) - nsleep=1; - - if( !fragh_f && dstoptuhdr_f){ - puts("Dst. Options Header (Unfragmentable Part) set, but Fragmentation not specified"); - exit(EXIT_FAILURE); - } - - if(!nopayload_f && !(rhtcp_f || rhudp_f || rhicmp6_f)) - rhdefault_f=1; - - if(!ip6hoplimit_f) - ip6hoplimit=64+random()%180; - - if(!ip6length_f) - ip6length=1460; - - if(!targetaddr_f) - targetaddr= idata.dstaddr; - - if(!peeraddr_f){ - if( inet_pton(AF_INET6, "::", &randprefix) <= 0){ - puts("inet_pton(): Error while randomizing Destination Address of the ICMPv6 payload"); - exit(EXIT_FAILURE); - } - randpreflen=0; - - randomize_ipv6_addr(&peeraddr, &randprefix, randpreflen); - } - - if(rhtcp_f || rhdefault_f){ - if(!tcpflags_f) - tcpflags= tcpflags | TH_ACK; - - if(!tcpack_f) - tcpack= random(); - - if(!tcpseq_f) - tcpseq= random(); - - if(!tcpwin_f) - tcpwin= ((uint16_t) random() + 1500) & (uint16_t)0x7f00; - - if(!peerportl_f){ - peerportl= random(); - peerporth= peerportl; - } - - if(!targetportl_f){ - targetportl= random(); - targetporth= targetportl; - } - - if(!tcpurg_f) - tcpurg= 0; - } - - if(rhudp_f){ - if(!peerportl_f){ - peerportl= random(); - peerporth= peerportl; - } - - if(!targetportl_f){ - targetportl= random(); - targetporth= targetportl; - } - } - - if(rhicmp6_f){ - if(!icmp6id_f) - icmp6id= random(); - - if(!icmp6seq_f) - icmp6seq= random(); - } - - if(!icmp6type_f){ - icmp6type= ICMP6_PARAM_PROB; - icmp6code= ICMP6_PARAMPROB_HEADER; - } - - switch(icmp6type){ - case ICMP6_PACKET_TOO_BIG: - if(!mtu_f) - mtu= 296; - break; - - case ICMP6_PARAM_PROB: - if(pointer_f) - pointer= random()%40; - break; - - case ICMP6_DST_UNREACH: - case ICMP6_TIME_EXCEEDED: - default: - break; - } - - if(rhtcp_f){ - if(pcap_compile(idata.pfd, &pcap_filter, PCAP_TCPV6_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1){ - printf("pcap_compile(): %s", pcap_geterr(idata.pfd)); - exit(EXIT_FAILURE); - } - } - else if(rhudp_f){ - if(pcap_compile(idata.pfd, &pcap_filter, PCAP_UDPV6_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1){ - printf("pcap_compile(): %s", pcap_geterr(idata.pfd)); - exit(EXIT_FAILURE); - } - } - else if(rhicmp6_f){ - if(pcap_compile(idata.pfd, &pcap_filter, PCAP_ICMPV6_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1){ - printf("pcap_compile(): %s", pcap_geterr(idata.pfd)); - exit(EXIT_FAILURE); - } - } - else if(pcap_compile(idata.pfd, &pcap_filter, PCAP_IPV6_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1){ - printf("pcap_compile(): %s", pcap_geterr(idata.pfd)); - exit(EXIT_FAILURE); - } - - if(pcap_setfilter(idata.pfd, &pcap_filter) == -1){ - printf("pcap_setfilter(): %s", pcap_geterr(idata.pfd)); - exit(EXIT_FAILURE); - } - - pcap_freecode(&pcap_filter); - - if(idata.verbose_f){ - print_attack_info(&idata); - } - - /* Set initial contents of the attack packet */ - init_packet_data(&idata); - - /* Fire an ICMPv6 error message if an IPv6 Destination Address was specified */ - if(idata.dstaddr_f){ - send_packet(&idata, NULL, NULL); - if(idata.verbose_f) - puts("Initial attack packet(s) sent successfully."); - - if(loop_f){ - if(idata.verbose_f) - printf("Now sending ICMPv6 error messages every %u second%s...\n", nsleep, \ - ((nsleep>1)?"s":"")); - while(loop_f){ - sleep(nsleep); - send_packet(&idata, NULL, NULL); - } - - exit(EXIT_SUCCESS); - } - } - - if(listen_f){ - if(idata.verbose_f){ - print_filters(&idata, &filters); - if(rhtcp_f){ - puts("Listening to incoming TCP packets..."); - } - else if(rhudp_f){ - puts("Listening to incoming UDP packets..."); - } - else if(rhicmp6_f){ - puts("Listening to incoming ICMPv6 packets..."); - } - else{ - puts("Listening to incoming IPv6 packets..."); - } - } - - FD_ZERO(&sset); - FD_SET(idata.fd, &sset); - - while(listen_f){ - rset= sset; + struct target_ipv6 targetipv6; + + static struct option longopts[] = {{"interface", required_argument, 0, 'i'}, + {"src-addr", required_argument, 0, 's'}, + {"dst-addr", required_argument, 0, 'd'}, + {"hop-limit", required_argument, 0, 'c'}, + {"dst-opt-hdr", required_argument, 0, 'u'}, + {"dst-opt-u-hdr", required_argument, 0, 'U'}, + {"hbh-opt-hdr", required_argument, 0, 'H'}, + {"frag-hdr", required_argument, 0, 'y'}, + {"link-src-addr", required_argument, 0, 'S'}, + {"link-dst-addr", required_argument, 0, 'D'}, + {"icmp6", required_argument, 0, 't'}, + {"icmp6-dest-unreach", required_argument, 0, 'e'}, + {"icmp6-packet-too-big", no_argument, 0, 'E'}, + {"icmp6-time-exceeded", required_argument, 0, 'A'}, + {"icmp6-param-problem", no_argument, 0, 'R'}, + {"mtu", required_argument, 0, 'm'}, + {"pointer", required_argument, 0, 'O'}, + {"sanity-filters", no_argument, 0, 'f'}, + {"payload-type", required_argument, 0, 'p'}, + {"payload-size", required_argument, 0, 'P'}, + {"no-payload", no_argument, 0, 'n'}, + {"ipv6-hlim", required_argument, 0, 'C'}, + {"target-addr", required_argument, 0, 'r'}, + {"peer-addr", required_argument, 0, 'x'}, + {"target-port", required_argument, 0, 'o'}, + {"peer-port", required_argument, 0, 'a'}, + {"tcp-flags", required_argument, 0, 'X'}, + {"tcp-seq", required_argument, 0, 'q'}, + {"tcp-ack", required_argument, 0, 'Q'}, + {"tcp-urg", required_argument, 0, 'V'}, + {"tcp-win", required_argument, 0, 'w'}, + {"resp-mcast", no_argument, 0, 'M'}, + {"block-src-addr", required_argument, 0, 'j'}, + {"block-dst-addr", required_argument, 0, 'k'}, + {"block-link-src-addr", required_argument, 0, 'J'}, + {"block-link-dst-addr", required_argument, 0, 'K'}, + {"accept-src-addr", required_argument, 0, 'b'}, + {"accept-dst-addr", required_argument, 0, 'g'}, + {"accept-link-src-addr", required_argument, 0, 'B'}, + {"accept-link-dst-addr", required_argument, 0, 'G'}, + {"sanity-filters", no_argument, 0, 'f'}, + {"loop", no_argument, 0, 'l'}, + {"sleep", required_argument, 0, 'z'}, + {"listen", no_argument, 0, 'L'}, + {"verbose", no_argument, 0, 'v'}, + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0}}; + + const char shortopts[] = "i:s:d:c:u:U:H:y:S:D:r:t:e:EA:R:m:O:p:P:nC:x:o:a:X:q:Q:V:w:MO:j:k:J:K:b:g:B:G:flz:Lvh"; + + char option; + + if (argc <= 1) { + usage(); + exit(EXIT_FAILURE); + } + + /* Initialize filters structure */ + if (init_filters(&filters) == -1) { + puts("Error initializing internal data structure"); + exit(EXIT_FAILURE); + } + + if (init_iface_data(&idata) == FAILURE) { + puts("Error initializing internal data structure"); + exit(EXIT_FAILURE); + } + + hoplimit = 64 + random() % 180; + + while ((r = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { + option = r; + + switch (option) { + + case 'i': /* Interface */ + strncpy(idata.iface, optarg, IFACE_LENGTH); + idata.iface[IFACE_LENGTH - 1] = 0; + idata.ifindex = if_nametoindex(idata.iface); + idata.iface_f = TRUE; + break; + + case 's': /* IPv6 Source Address */ + if (idata.srcaddr_f) { + puts("Error: Multiple '-s' options have been specified"); + exit(EXIT_FAILURE); + } + + if ((charptr = strtok_r(optarg, "/", &lasts)) == NULL) { + puts("Error in Source Address"); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, charptr, &(idata.srcaddr)) <= 0) { + puts("inet_pton(): Source Address not valid"); + exit(EXIT_FAILURE); + } + + idata.srcaddr_f = 1; + + if ((charptr = strtok_r(NULL, " ", &lasts)) != NULL) { + idata.srcpreflen = atoi(charptr); + + if (idata.srcpreflen > 128) { + puts("Prefix length error in IPv6 Source Address"); + exit(EXIT_FAILURE); + } + + if (idata.srcpreflen == 64) + useaddrkey_f = 1; + + sanitize_ipv6_prefix(&(idata.srcaddr), idata.srcpreflen); + idata.srcprefix_f = 1; + } + + break; + + case 'd': /* IPv6 Destination Address */ + strncpy(targetipv6.name, optarg, NI_MAXHOST); + targetipv6.name[NI_MAXHOST - 1] = 0; + targetipv6.flags = AI_CANONNAME; + + if ((r = get_ipv6_target(&targetipv6)) != 0) { + + if (r < 0) { + printf("Unknown Destination: %s\n", gai_strerror(targetipv6.res)); + } + else { + puts("Unknown Destination: No IPv6 address found for specified destination"); + } + + exit(EXIT_FAILURE); + } + + idata.dstaddr = targetipv6.ip6; + idata.dstaddr_f = 1; + break; + + case 'c': /* Hop Limit */ + hoplimit = atoi(optarg); + hoplimit_f = 1; + break; + + case 'u': /* Destinations Options Header */ + if (ndstopthdr >= MAX_DST_OPT_HDR) { + puts("Too many Destination Options Headers"); + exit(EXIT_FAILURE); + } + + hdrlen = atoi(optarg); + + if (hdrlen < 8) { + puts("Bad length in Destination Options Header"); + exit(EXIT_FAILURE); + } + + hdrlen = ((hdrlen + 7) / 8) * 8; + dstopthdrlen[ndstopthdr] = hdrlen; + + if ((dstopthdr[ndstopthdr] = malloc(hdrlen)) == NULL) { + puts("Not enough memory for Destination Options Header"); + exit(EXIT_FAILURE); + } + + ptrhdr = dstopthdr[ndstopthdr] + 2; + ptrhdrend = dstopthdr[ndstopthdr] + hdrlen; + + while (ptrhdr < ptrhdrend) { + + if ((ptrhdrend - ptrhdr) > 257) + pad = 257; + else + pad = ptrhdrend - ptrhdr; + + if (!insert_pad_opt(ptrhdr, ptrhdrend, pad)) { + puts("Destination Options Header Too Big"); + exit(EXIT_FAILURE); + } + + ptrhdr = ptrhdr + pad; + } + + *(dstopthdr[ndstopthdr] + 1) = (hdrlen / 8) - 1; + ndstopthdr++; + dstopthdr_f = 1; + break; + + case 'U': /* Destination Options Header (Unfragmentable Part) */ + if (ndstoptuhdr >= MAX_DST_OPT_U_HDR) { + puts("Too many Destination Options Headers (Unfragmentable Part)"); + exit(EXIT_FAILURE); + } + + hdrlen = atoi(optarg); + + if (hdrlen < 8) { + puts("Bad length in Destination Options Header (Unfragmentable Part)"); + exit(EXIT_FAILURE); + } + + hdrlen = ((hdrlen + 7) / 8) * 8; + dstoptuhdrlen[ndstoptuhdr] = hdrlen; + + if ((dstoptuhdr[ndstoptuhdr] = malloc(hdrlen)) == NULL) { + puts("Not enough memory for Destination Options Header (Unfragmentable Part)"); + exit(EXIT_FAILURE); + } + + ptrhdr = dstoptuhdr[ndstoptuhdr] + 2; + ptrhdrend = dstoptuhdr[ndstoptuhdr] + hdrlen; + + while (ptrhdr < ptrhdrend) { + + if ((ptrhdrend - ptrhdr) > 257) + pad = 257; + else + pad = ptrhdrend - ptrhdr; + + if (!insert_pad_opt(ptrhdr, ptrhdrend, pad)) { + puts("Destination Options Header (Unfragmentable Part) Too Big"); + exit(EXIT_FAILURE); + } + + ptrhdr = ptrhdr + pad; + } + + *(dstoptuhdr[ndstoptuhdr] + 1) = (hdrlen / 8) - 1; + ndstoptuhdr++; + dstoptuhdr_f = 1; + break; + + case 'H': /* Hop-by-Hop Options Header */ + if (nhbhopthdr >= MAX_HBH_OPT_HDR) { + puts("Too many Hop-by-Hop Options Headers"); + exit(EXIT_FAILURE); + } + + hdrlen = atoi(optarg); + + if (hdrlen < 8) { + puts("Bad length in Hop-by-Hop Options Header"); + exit(EXIT_FAILURE); + } + + hdrlen = ((hdrlen + 7) / 8) * 8; + hbhopthdrlen[nhbhopthdr] = hdrlen; + + if ((hbhopthdr[nhbhopthdr] = malloc(hdrlen)) == NULL) { + puts("Not enough memory for Hop-by-Hop Options Header"); + exit(EXIT_FAILURE); + } + + ptrhdr = hbhopthdr[nhbhopthdr] + 2; + ptrhdrend = hbhopthdr[nhbhopthdr] + hdrlen; + + while (ptrhdr < ptrhdrend) { + + if ((ptrhdrend - ptrhdr) > 257) + pad = 257; + else + pad = ptrhdrend - ptrhdr; + + if (!insert_pad_opt(ptrhdr, ptrhdrend, pad)) { + puts("Hop-by-Hop Options Header Too Big"); + exit(EXIT_FAILURE); + } + + ptrhdr = ptrhdr + pad; + } + + *(hbhopthdr[nhbhopthdr] + 1) = (hdrlen / 8) - 1; + nhbhopthdr++; + hbhopthdr_f = 1; + break; + + case 'y': /* Fragment header */ + nfrags = atoi(optarg); + if (nfrags < 8) { + puts("Error in Fragmentation option: Fragment Size must be at least 8 bytes"); + exit(EXIT_FAILURE); + } + + fragh_f = 1; + break; + + case 'S': /* Source Ethernet address */ + if (ether_pton(optarg, &(idata.hsrcaddr), sizeof(idata.hsrcaddr)) == 0) { + puts("Error in Source link-layer address."); + exit(EXIT_FAILURE); + } + + idata.hsrcaddr_f = 1; + break; + + case 'D': /* Destination Ethernet Address */ + if (ether_pton(optarg, &(idata.hdstaddr), sizeof(idata.hdstaddr)) == 0) { + puts("Error in Source link-layer address."); + exit(EXIT_FAILURE); + } + + idata.hdstaddr_f = 1; + break; + + case 'r': /* Target address */ + + if ((charptr = strtok_r(optarg, "/", &lasts)) == NULL) { + puts("Error in Redirected Address"); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, charptr, &targetaddr) <= 0) { + puts("inet_pton(): Redirected Address not valid"); + exit(EXIT_FAILURE); + } + + targetaddr_f = 1; + + if ((charptr = strtok_r(NULL, " ", &lasts)) != NULL) { + redirpreflen = atoi(charptr); + + if (redirpreflen > 128) { + puts("Prefix length error in IPv6 Source Address"); + exit(EXIT_FAILURE); + } + + sanitize_ipv6_prefix(&targetaddr, redirpreflen); + redirprefix_f = 1; + } + + break; + + case 't': /* ICMPv6 Type and Code */ + if ((charptr = strtok_r(optarg, ":", &lasts)) == NULL) { + puts("Error in ICMPv6 message Type/Code"); + exit(EXIT_FAILURE); + } + + icmp6type = atoi(charptr); + icmp6type_f = 1; + + if ((charptr = strtok_r(NULL, " ", &lasts)) != NULL) { + icmp6code = atoi(charptr); + icmp6code_f = 1; + } + + break; + + case 'e': /* ICMPv6 Destination Unreachable */ + icmp6type = 1; + icmp6type_f = 1; + icmp6code = atoi(optarg); + icmp6code_f = 1; + break; + + case 'E': /* ICMPv6 Packet Too Big */ + icmp6type = 2; + icmp6type_f = 1; + icmp6code = 0; + icmp6code_f = 1; + break; + + case 'A': /* ICMPv6 Time Exceeded */ + icmp6type = 3; + icmp6type_f = 1; + icmp6code = atoi(optarg); + icmp6code_f = 1; + break; + + case 'R': /* ICMPv6 Parameter Problem */ + icmp6type = 4; + icmp6type_f = 1; + icmp6code = atoi(optarg); + icmp6code_f = 1; + break; + + case 'm': /* Next-Hop MTU (for ICMPv6 PTB messages) */ + if ((ul_res = strtoul(optarg, &endptr, 0)) == ULONG_MAX) { + perror("Error in 'MTU' parameter"); + exit(EXIT_FAILURE); + } + + if (endptr != optarg) { + mtu = ul_res; + mtu_f = 1; + } + break; + + case 'O': /* Pointer (for ICMPv6 "Parameter Problem" messages) */ + if ((ul_res = strtoul(optarg, &endptr, 0)) == ULONG_MAX) { + perror("Error in 'Pointer' parameter"); + exit(EXIT_FAILURE); + } + + if (endptr != optarg) { + pointer = ul_res; + pointer_f = 1; + } + break; + + case 'p': /* Protocol used in the ICMPv6 Payload */ + if (strcmp(optarg, "TCP") == 0 || strcmp(optarg, "tcp") == 0) + rhtcp_f = 1; + else if (strcmp(optarg, "ICMP6") == 0 || strcmp(optarg, "ICMPv6") == 0 || strcmp(optarg, "icmpv6") == 0 || + strcmp(optarg, "icmp6") == 0) + rhicmp6_f = 1; + else if (strcmp(optarg, "UDP") == 0 || strcmp(optarg, "udp") == 0) + rhudp_f = 1; + else if (strcmp(optarg, "IP6") == 0 || strcmp(optarg, "ip6") == 0 || strcmp(optarg, "IPv6") == 0 || + strcmp(optarg, "ipv6") == 0) { + rhip6_f = 1; + } + else { + puts("Unsupported protocol in option '-p'"); + exit(EXIT_FAILURE); + } + break; + + case 'P': /* Payload Size*/ + rhlength = atoi(optarg); + rhlength = (rhlength << 3) >> 3; /* The Redirected Header has a granularity of 8 bytes */ + rhlength_f = 1; + break; + + case 'n': /* No ICMPv6 Payload */ + nopayload_f = 1; + break; + + case 'C': /* Hop Limit of the IPv6 Payload */ + ip6hoplimit = atoi(optarg); + ip6hoplimit_f = 1; + break; + + case 'x': /* Source Address of the ICMPv6 payload */ + strncpy(targetipv6.name, optarg, NI_MAXHOST); + targetipv6.name[NI_MAXHOST - 1] = 0; + targetipv6.flags = AI_CANONNAME; + + if ((r = get_ipv6_target(&targetipv6)) != 0) { + + if (r < 0) { + printf("Unknown Destination: %s\n", gai_strerror(targetipv6.res)); + } + else { + puts("Unknown Destination: No IPv6 address found for specified destination"); + } + + exit(EXIT_FAILURE); + } + + peeraddr = targetipv6.ip6; + peeraddr_f = 1; + break; + + case 'o': /* Target port */ + if ((charptr = strtok_r(optarg, ":-", &lasts)) == NULL) { + printf("Error in TCP/UDP target port"); + exit(EXIT_FAILURE); + } + + targetportl = atoi(charptr); + targetportl_f = 1; + + if ((charptr = strtok_r(NULL, " ", &lasts)) == NULL) { + + targetporth = targetportl; + } + else { + targetporth = atoi(charptr); + targetporth_f = 1; + + if (targetportl > targetporth) { + auxint16 = targetportl; + targetportl = targetporth; + targetporth = auxint16; + } + } + break; + + case 'a': /* Peer port */ + if ((charptr = strtok_r(optarg, ":-", &lasts)) == NULL) { + printf("Error in TCP/UDP peer port"); + exit(EXIT_FAILURE); + } + + peerportl = atoi(charptr); + peerportl_f = 1; + + if ((charptr = strtok_r(NULL, " ", &lasts)) == NULL) { + peerporth = peerportl; + } + else { + peerporth = atoi(charptr); + peerporth_f = 1; + + if (peerportl > peerporth) { + auxint16 = peerportl; + peerportl = peerporth; + peerporth = auxint16; + } + } + break; + + case 'X': /* TCP flags */ + charptr = optarg; + while (*charptr) { + switch (*charptr) { + case 'F': + tcpflags = tcpflags | TH_FIN; + break; + + case 'S': + tcpflags = tcpflags | TH_SYN; + break; + + case 'R': + tcpflags = tcpflags | TH_RST; + break; + + case 'P': + tcpflags = tcpflags | TH_PUSH; + break; + + case 'A': + tcpflags = tcpflags | TH_ACK; + break; + + case 'U': + tcpflags = tcpflags | TH_URG; + break; + + case 'X': /* No TCP flags */ + break; + + default: + printf("Unknown TCP flag '%c'\n", *charptr); + exit(EXIT_FAILURE); + break; + } + + if (*charptr == 'X') + break; + + charptr++; + } + + tcpflags_f = 1; + break; + + case 'q': /* TCP Sequence Number */ + if ((ul_res = strtoul(optarg, &endptr, 0)) == ULONG_MAX) { + perror("Error in 'TCP Sequence NUmber' parameter"); + exit(EXIT_FAILURE); + } + + if (endptr != optarg) { + tcpseq = ul_res; + tcpseq_f = 1; + } + + break; + + case 'Q': /* TCP Acknowledgement Number */ + if ((ul_res = strtoul(optarg, &endptr, 0)) == ULONG_MAX) { + perror("Error in 'TCP Sequence NUmber' parameter"); + exit(EXIT_FAILURE); + } + + if (endptr != optarg) { + tcpack = ul_res; + tcpack_f = 1; + } + break; + + case 'V': /* TCP Urgent Pointer */ + tcpurg = atoi(optarg); + tcpurg_f = 1; + break; + + case 'w': /* TCP Window */ + tcpwin = atoi(optarg); + tcpwin_f = 1; + break; + + case 'M': /* Respond to multicast packets */ + respmcast_f = 1; + break; + + case 'j': /* IPv6 Source Address (block) filter */ + if (filters.nblocksrc >= MAX_BLOCK_SRC) { + puts("Too many IPv6 Source Address (block) filters."); + exit(EXIT_FAILURE); + } + + if ((pref = strtok_r(optarg, "/", &lasts)) == NULL) { + printf("Error in IPv6 Source Address (block) filter number %u.\n", filters.nblocksrc + 1); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, pref, &(filters.blocksrc[filters.nblocksrc])) <= 0) { + printf("Error in IPv6 Source Address (block) filter number %u.", filters.nblocksrc + 1); + exit(EXIT_FAILURE); + } + + if ((charptr = strtok_r(NULL, " ", &lasts)) == NULL) { + filters.blocksrclen[filters.nblocksrc] = 128; + } + else { + filters.blocksrclen[filters.nblocksrc] = atoi(charptr); + + if (filters.blocksrclen[filters.nblocksrc] > 128) { + printf("Length error in IPv6 Source Address (block) filter number %u.\n", filters.nblocksrc + 1); + exit(EXIT_FAILURE); + } + } + + sanitize_ipv6_prefix(&(filters.blocksrc[filters.nblocksrc]), filters.blocksrclen[filters.nblocksrc]); + (filters.nblocksrc)++; + break; + + case 'k': /* IPv6 Destination Address (block) filter */ + if (filters.nblockdst >= MAX_BLOCK_DST) { + puts("Too many IPv6 Destination Address (block) filters."); + exit(EXIT_FAILURE); + } + + if ((pref = strtok_r(optarg, "/", &lasts)) == NULL) { + printf("Error in IPv6 Destination Address (block) filter number %u.\n", filters.nblockdst + 1); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, pref, &(filters.blockdst[filters.nblockdst])) <= 0) { + printf("Error in IPv6 Source Address (block) filter number %u.", filters.nblockdst + 1); + exit(EXIT_FAILURE); + } + + if ((charptr = strtok_r(NULL, " ", &lasts)) == NULL) { + filters.blockdstlen[filters.nblockdst] = 128; + } + else { + filters.blockdstlen[filters.nblockdst] = atoi(charptr); + + if (filters.blockdstlen[filters.nblockdst] > 128) { + printf("Length error in IPv6 Source Address (block) filter number %u.\n", filters.nblockdst + 1); + exit(EXIT_FAILURE); + } + } + + sanitize_ipv6_prefix(&(filters.blockdst[filters.nblockdst]), filters.blockdstlen[filters.nblockdst]); + (filters.nblockdst)++; + break; + + case 'J': /* Link Source Address (block) filter */ + if (filters.nblocklinksrc > MAX_BLOCK_LINK_SRC) { + puts("Too many link-layer Source Address (accept) filters."); + exit(EXIT_FAILURE); + } + + if (ether_pton(optarg, &(filters.blocklinksrc[filters.nblocklinksrc]), sizeof(struct ether_addr)) == 0) { + printf("Error in link-layer Source Address (blick) filter number %u.\n", filters.nblocklinksrc + 1); + exit(EXIT_FAILURE); + } + + (filters.nblocklinksrc)++; + break; + + case 'K': /* Link Destination Address (block) filter */ + if (filters.nblocklinkdst > MAX_BLOCK_LINK_DST) { + puts("Too many link-layer Destination Address (block) filters."); + exit(EXIT_FAILURE); + } + + if (ether_pton(optarg, &(filters.blocklinkdst[filters.nblocklinkdst]), sizeof(struct ether_addr)) == 0) { + printf("Error in link-layer Destination Address (blick) filter number %u.\n", + filters.nblocklinkdst + 1); + exit(EXIT_FAILURE); + } + + filters.nblocklinkdst++; + break; + + case 'b': /* IPv6 Source Address (accept) filter */ + if (filters.nacceptsrc > MAX_ACCEPT_SRC) { + puts("Too many IPv6 Source Address (accept) filters."); + exit(EXIT_FAILURE); + } + + if ((pref = strtok_r(optarg, "/", &lasts)) == NULL) { + printf("Error in IPv6 Source Address (accept) filter number %u.\n", filters.nacceptsrc + 1); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, pref, &(filters.acceptsrc[filters.nacceptsrc])) <= 0) { + printf("Error in IPv6 Source Address (accept) filter number %u.\n", filters.nacceptsrc + 1); + exit(EXIT_FAILURE); + } + + if ((charptr = strtok_r(NULL, " ", &lasts)) == NULL) { + filters.acceptsrclen[filters.nacceptsrc] = 128; + } + else { + filters.acceptsrclen[filters.nacceptsrc] = atoi(charptr); + + if (filters.acceptsrclen[filters.nacceptsrc] > 128) { + printf("Length error in IPv6 Source Address (accept) filter number %u.\n", filters.nacceptsrc + 1); + exit(EXIT_FAILURE); + } + } + + sanitize_ipv6_prefix(&(filters.acceptsrc[filters.nacceptsrc]), filters.acceptsrclen[filters.nacceptsrc]); + (filters.nacceptsrc)++; + filters.acceptfilters_f = 1; + break; + + case 'g': /* IPv6 Destination Address (accept) filter */ + if (filters.nacceptdst > MAX_ACCEPT_DST) { + puts("Too many IPv6 Destination Address (accept) filters."); + exit(EXIT_FAILURE); + } + + if ((pref = strtok_r(optarg, "/", &lasts)) == NULL) { + printf("Error in IPv6 Destination Address (accept) filter number %u.\n", filters.nacceptdst + 1); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, pref, &(filters.acceptdst[filters.nacceptdst])) <= 0) { + printf("Error in IPv6 Source Address (accept) filter number %u.\n", filters.nacceptdst + 1); + exit(EXIT_FAILURE); + } + + if ((charptr = strtok_r(NULL, " ", &lasts)) == NULL) { + filters.acceptdstlen[filters.nacceptdst] = 128; + } + else { + filters.acceptdstlen[filters.nacceptdst] = atoi(charptr); + + if (filters.acceptdstlen[filters.nacceptdst] > 128) { + printf("Length error in IPv6 Source Address (accept) filter number %u.\n", filters.nacceptdst + 1); + exit(EXIT_FAILURE); + } + } + + sanitize_ipv6_prefix(&(filters.acceptdst[filters.nacceptdst]), filters.acceptdstlen[filters.nacceptdst]); + (filters.nacceptdst)++; + filters.acceptfilters_f = 1; + break; + + case 'B': /* Link-layer Source Address (accept) filter */ + if (filters.nacceptlinksrc > MAX_ACCEPT_LINK_SRC) { + puts("Too many link-later Source Address (accept) filters."); + exit(EXIT_FAILURE); + } + + if (ether_pton(optarg, &(filters.acceptlinksrc[filters.nacceptlinksrc]), sizeof(struct ether_addr)) == 0) { + printf("Error in link-layer Source Address (accept) filter number %u.\n", filters.nacceptlinksrc + 1); + exit(EXIT_FAILURE); + } + + (filters.nacceptlinksrc)++; + filters.acceptfilters_f = 1; + break; + + case 'G': /* Link Destination Address (accept) filter */ + if (filters.nacceptlinkdst > MAX_ACCEPT_LINK_DST) { + puts("Too many link-layer Destination Address (accept) filters."); + exit(EXIT_FAILURE); + } + + if (ether_pton(optarg, &(filters.acceptlinkdst[filters.nacceptlinkdst]), sizeof(struct ether_addr)) == 0) { + printf("Error in link-layer Destination Address (accept) filter number %u.\n", + filters.nacceptlinkdst + 1); + exit(EXIT_FAILURE); + } + + (filters.nacceptlinkdst)++; + filters.acceptfilters_f = 1; + break; + + case 'f': /* Sanity filters */ + sanityfilters_f = 1; + break; + + case 'l': /* "Loop mode */ + loop_f = 1; + break; + + case 'z': /* Sleep option */ + nsleep = atoi(optarg); + if (nsleep == 0) { + puts("Invalid number of seconds in '-z' option"); + exit(EXIT_FAILURE); + } + + sleep_f = 1; + break; + + case 'L': /* "Listen mode */ + listen_f = 1; + break; + + case 'v': /* Be verbose */ + idata.verbose_f++; + break; + + case 'h': /* Help */ + print_help(); + + exit(EXIT_FAILURE); + break; + + default: + usage(); + exit(EXIT_FAILURE); + break; + + } /* switch */ + } /* while(getopt) */ + + if (geteuid()) { + puts("icmp6 needs root privileges to run."); + exit(EXIT_FAILURE); + } + + if (listen_f && !idata.iface_f) { + puts("Must specify a network interface with the -i option when listening mode is selected"); + exit(EXIT_FAILURE); + } + + if (listen_f && loop_f) { + puts("'Error: listen' mode and 'loop' mode are incompatible"); + exit(EXIT_FAILURE); + } + + if (!idata.dstaddr_f && !listen_f) { /* Must specify IPv6 Destination Address if listening mode not used */ + puts("IPv6 Destination Address not specified (and listening mode not selected)"); + exit(EXIT_FAILURE); + } + + if (load_dst_and_pcap(&idata, LOAD_SRC_NXT_HOP) == FAILURE) { + puts("Error while learning Source Address and Next Hop"); + exit(EXIT_FAILURE); + } + + release_privileges(); + + srandom(time(NULL)); + + if (sanityfilters_f) { + if (filters.nblocksrc >= MAX_BLOCK_SRC) { + puts("Too many Source Address (block) filters while adding sanity filters."); + exit(EXIT_FAILURE); + } + + filters.blocksrc[filters.nblocksrc] = idata.srcaddr; + filters.blocksrclen[filters.nblocksrc] = 128; + filters.nblocklinksrc++; + } + + if (!sleep_f) + nsleep = 1; + + if (!fragh_f && dstoptuhdr_f) { + puts("Dst. Options Header (Unfragmentable Part) set, but Fragmentation not specified"); + exit(EXIT_FAILURE); + } + + if (!nopayload_f && !(rhtcp_f || rhudp_f || rhicmp6_f)) + rhdefault_f = 1; + + if (!ip6hoplimit_f) + ip6hoplimit = 64 + random() % 180; + + if (!ip6length_f) + ip6length = 1460; + + if (!targetaddr_f) + targetaddr = idata.dstaddr; + + if (!peeraddr_f) { + if (inet_pton(AF_INET6, "::", &randprefix) <= 0) { + puts("inet_pton(): Error while randomizing Destination Address of the ICMPv6 payload"); + exit(EXIT_FAILURE); + } + randpreflen = 0; + + randomize_ipv6_addr(&peeraddr, &randprefix, randpreflen); + } + + if (rhtcp_f || rhdefault_f) { + if (!tcpflags_f) + tcpflags = tcpflags | TH_ACK; + + if (!tcpack_f) + tcpack = random(); + + if (!tcpseq_f) + tcpseq = random(); + + if (!tcpwin_f) + tcpwin = ((uint16_t)random() + 1500) & (uint16_t)0x7f00; + + if (!peerportl_f) { + peerportl = random(); + peerporth = peerportl; + } + + if (!targetportl_f) { + targetportl = random(); + targetporth = targetportl; + } + + if (!tcpurg_f) + tcpurg = 0; + } + + if (rhudp_f) { + if (!peerportl_f) { + peerportl = random(); + peerporth = peerportl; + } + + if (!targetportl_f) { + targetportl = random(); + targetporth = targetportl; + } + } + + if (rhicmp6_f) { + if (!icmp6id_f) + icmp6id = random(); + + if (!icmp6seq_f) + icmp6seq = random(); + } + + if (!icmp6type_f) { + icmp6type = ICMP6_PARAM_PROB; + icmp6code = ICMP6_PARAMPROB_HEADER; + } + + switch (icmp6type) { + case ICMP6_PACKET_TOO_BIG: + if (!mtu_f) + mtu = 296; + break; + + case ICMP6_PARAM_PROB: + if (pointer_f) + pointer = random() % 40; + break; + + case ICMP6_DST_UNREACH: + case ICMP6_TIME_EXCEEDED: + default: + break; + } + + if (rhtcp_f) { + if (pcap_compile(idata.pfd, &pcap_filter, PCAP_TCPV6_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1) { + printf("pcap_compile(): %s", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } + } + else if (rhudp_f) { + if (pcap_compile(idata.pfd, &pcap_filter, PCAP_UDPV6_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1) { + printf("pcap_compile(): %s", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } + } + else if (rhicmp6_f) { + if (pcap_compile(idata.pfd, &pcap_filter, PCAP_ICMPV6_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1) { + printf("pcap_compile(): %s", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } + } + else if (pcap_compile(idata.pfd, &pcap_filter, PCAP_IPV6_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1) { + printf("pcap_compile(): %s", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } + + if (pcap_setfilter(idata.pfd, &pcap_filter) == -1) { + printf("pcap_setfilter(): %s", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } + + pcap_freecode(&pcap_filter); + + if (idata.verbose_f) { + print_attack_info(&idata); + } + + /* Set initial contents of the attack packet */ + init_packet_data(&idata); + + /* Fire an ICMPv6 error message if an IPv6 Destination Address was specified */ + if (idata.dstaddr_f) { + send_packet(&idata, NULL, NULL); + if (idata.verbose_f) + puts("Initial attack packet(s) sent successfully."); + + if (loop_f) { + if (idata.verbose_f) + printf("Now sending ICMPv6 error messages every %u second%s...\n", nsleep, ((nsleep > 1) ? "s" : "")); + while (loop_f) { + sleep(nsleep); + send_packet(&idata, NULL, NULL); + } + + exit(EXIT_SUCCESS); + } + } + + if (listen_f) { + if (idata.verbose_f) { + print_filters(&idata, &filters); + if (rhtcp_f) { + puts("Listening to incoming TCP packets..."); + } + else if (rhudp_f) { + puts("Listening to incoming UDP packets..."); + } + else if (rhicmp6_f) { + puts("Listening to incoming ICMPv6 packets..."); + } + else { + puts("Listening to incoming IPv6 packets..."); + } + } + + FD_ZERO(&sset); + FD_SET(idata.fd, &sset); + + while (listen_f) { + rset = sset; #if defined(sun) || defined(__sun) - timeout.tv_usec=10000; - timeout.tv_sec= 0; - if((sel=select(idata.fd+1, &rset, NULL, NULL, &timeout)) == -1){ + timeout.tv_usec = 10000; + timeout.tv_sec = 0; + if ((sel = select(idata.fd + 1, &rset, NULL, NULL, &timeout)) == -1) { #else - if((sel=select(idata.fd+1, &rset, NULL, NULL, NULL)) == -1){ + if ((sel = select(idata.fd + 1, &rset, NULL, NULL, NULL)) == -1) { #endif - if(errno == EINTR){ - continue; - } - else{ - puts("Error in select()"); - exit(EXIT_FAILURE); - } - } + if (errno == EINTR) { + continue; + } + else { + puts("Error in select()"); + exit(EXIT_FAILURE); + } + } #if defined(sun) || defined(__sun) - if(TRUE){ + if (TRUE) { #else - if(sel && FD_ISSET(idata.fd, &rset)){ + if (sel && FD_ISSET(idata.fd, &rset)) { #endif - /* Read a Neighbor Solicitation message */ - if((r=pcap_next_ex(idata.pfd, &pkthdr, &pktdata)) == -1){ - printf("pcap_next_ex(): %s", pcap_geterr(idata.pfd)); - exit(EXIT_FAILURE); - } - else if(r == 1 && pktdata != NULL){ - pkt_ether = (struct ether_header *) pktdata; - pkt_ipv6 = (struct ip6_hdr *)((char *) pkt_ether + idata.linkhsize); - - accepted_f=0; - - if(idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK)){ - if(filters.nblocklinksrc){ - if(match_ether(filters.blocklinksrc, filters.nblocklinksrc, &(pkt_ether->src))){ - if(idata.verbose_f>1) - print_filter_result(&idata, pktdata, BLOCKED); - - continue; - } - } - - if(filters.nblocklinkdst){ - if(match_ether(filters.blocklinkdst, filters.nblocklinkdst, &(pkt_ether->dst))){ - if(idata.verbose_f>1) - print_filter_result(&idata, pktdata, BLOCKED); - - continue; - } - } - } - - if(filters.nblocksrc){ - if(match_ipv6(filters.blocksrc, filters.blocksrclen, filters.nblocksrc, &(pkt_ipv6->ip6_src))){ - if(idata.verbose_f>1) - print_filter_result(&idata, pktdata, BLOCKED); - - continue; - } - } - - if(filters.nblockdst){ - if(match_ipv6(filters.blockdst, filters.blockdstlen, filters.nblockdst, &(pkt_ipv6->ip6_dst))){ - if(idata.verbose_f>1) - print_filter_result(&idata, pktdata, BLOCKED); - - continue; - } - } - - if(idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK)){ - if(filters.nacceptlinksrc){ - if(match_ether(filters.acceptlinksrc, filters.nacceptlinksrc, &(pkt_ether->src))) - accepted_f=1; - } - - if(filters.nacceptlinkdst && !accepted_f){ - if(match_ether(filters.acceptlinkdst, filters.nacceptlinkdst, &(pkt_ether->dst))) - accepted_f= 1; - } - } - - if(filters.nacceptsrc && !accepted_f){ - if(match_ipv6(filters.acceptsrc, filters.acceptsrclen, filters.nacceptsrc, &(pkt_ipv6->ip6_src))) - accepted_f= 1; - } - - if(filters.nacceptdst && !accepted_f){ - if(match_ipv6(filters.acceptdst, filters.acceptdstlen, filters.nacceptdst, &(pkt_ipv6->ip6_dst))) - accepted_f=1; - } - - if(filters.acceptfilters_f && !accepted_f){ - if(idata.verbose_f>1) - print_filter_result(&idata, pktdata, BLOCKED); - - continue; - } - - if(idata.verbose_f>1) - print_filter_result(&idata, pktdata, ACCEPTED); - - - /* Send a Neighbor Advertisement */ - send_packet(&idata, pktdata, pkthdr); - } - } - } - - exit(EXIT_SUCCESS); - } - - - if(!idata.dstaddr_f && !listen_f){ - puts("Error: Nothing to send! (key parameters left unspecified, and not using listening mode)"); - exit(EXIT_FAILURE); - } - - exit(EXIT_SUCCESS); + /* Read a Neighbor Solicitation message */ + if ((r = pcap_next_ex(idata.pfd, &pkthdr, &pktdata)) == -1) { + printf("pcap_next_ex(): %s", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } + else if (r == 1 && pktdata != NULL) { + pkt_ether = (struct ether_header *)pktdata; + pkt_ipv6 = (struct ip6_hdr *)((char *)pkt_ether + idata.linkhsize); + + accepted_f = 0; + + if (idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK)) { + if (filters.nblocklinksrc) { + if (match_ether(filters.blocklinksrc, filters.nblocklinksrc, &(pkt_ether->src))) { + if (idata.verbose_f > 1) + print_filter_result(&idata, pktdata, BLOCKED); + + continue; + } + } + + if (filters.nblocklinkdst) { + if (match_ether(filters.blocklinkdst, filters.nblocklinkdst, &(pkt_ether->dst))) { + if (idata.verbose_f > 1) + print_filter_result(&idata, pktdata, BLOCKED); + + continue; + } + } + } + + if (filters.nblocksrc) { + if (match_ipv6(filters.blocksrc, filters.blocksrclen, filters.nblocksrc, + &(pkt_ipv6->ip6_src))) { + if (idata.verbose_f > 1) + print_filter_result(&idata, pktdata, BLOCKED); + + continue; + } + } + + if (filters.nblockdst) { + if (match_ipv6(filters.blockdst, filters.blockdstlen, filters.nblockdst, + &(pkt_ipv6->ip6_dst))) { + if (idata.verbose_f > 1) + print_filter_result(&idata, pktdata, BLOCKED); + + continue; + } + } + + if (idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK)) { + if (filters.nacceptlinksrc) { + if (match_ether(filters.acceptlinksrc, filters.nacceptlinksrc, &(pkt_ether->src))) + accepted_f = 1; + } + + if (filters.nacceptlinkdst && !accepted_f) { + if (match_ether(filters.acceptlinkdst, filters.nacceptlinkdst, &(pkt_ether->dst))) + accepted_f = 1; + } + } + + if (filters.nacceptsrc && !accepted_f) { + if (match_ipv6(filters.acceptsrc, filters.acceptsrclen, filters.nacceptsrc, + &(pkt_ipv6->ip6_src))) + accepted_f = 1; + } + + if (filters.nacceptdst && !accepted_f) { + if (match_ipv6(filters.acceptdst, filters.acceptdstlen, filters.nacceptdst, + &(pkt_ipv6->ip6_dst))) + accepted_f = 1; + } + + if (filters.acceptfilters_f && !accepted_f) { + if (idata.verbose_f > 1) + print_filter_result(&idata, pktdata, BLOCKED); + + continue; + } + + if (idata.verbose_f > 1) + print_filter_result(&idata, pktdata, ACCEPTED); + + /* Send a Neighbor Advertisement */ + send_packet(&idata, pktdata, pkthdr); + } + } + } + + exit(EXIT_SUCCESS); + } + + if (!idata.dstaddr_f && !listen_f) { + puts("Error: Nothing to send! (key parameters left unspecified, and not using listening mode)"); + exit(EXIT_FAILURE); + } + + exit(EXIT_SUCCESS); } - - /* * Function: init_packet_data() * * Initialize the contents of the attack packet (Ethernet header, IPv6 Header, and ICMPv6 header) * that are expected to remain constant for the specified attack. */ -void init_packet_data(struct iface_data *idata){ - ethernet= (struct ether_header *) buffer; - dlt_null= (struct dlt_null *) buffer; - v6buffer = buffer + idata->linkhsize; - ipv6 = (struct ip6_hdr *) v6buffer; - - if(idata->type == DLT_EN10MB){ - ethernet->ether_type = htons(ETHERTYPE_IPV6); - - if(!(idata->flags & IFACE_LOOPBACK)){ - ethernet->src = idata->hsrcaddr; - ethernet->dst = idata->hdstaddr; - } - } - else if(idata->type == DLT_NULL){ - dlt_null->family= PF_INET6; - } -#if defined (__OpenBSD__) - else if(idata->type == DLT_LOOP){ - dlt_null->family= htonl(PF_INET6); - } +void init_packet_data(struct iface_data *idata) { + ethernet = (struct ether_header *)buffer; + dlt_null = (struct dlt_null *)buffer; + v6buffer = buffer + idata->linkhsize; + ipv6 = (struct ip6_hdr *)v6buffer; + + if (idata->type == DLT_EN10MB) { + ethernet->ether_type = htons(ETHERTYPE_IPV6); + + if (!(idata->flags & IFACE_LOOPBACK)) { + ethernet->src = idata->hsrcaddr; + ethernet->dst = idata->hdstaddr; + } + } + else if (idata->type == DLT_NULL) { + dlt_null->family = PF_INET6; + } +#if defined(__OpenBSD__) + else if (idata->type == DLT_LOOP) { + dlt_null->family = htonl(PF_INET6); + } #endif - ipv6->ip6_flow=0; - ipv6->ip6_vfc= 0x60; - ipv6->ip6_hlim= hoplimit; - ipv6->ip6_src= idata->srcaddr; - ipv6->ip6_dst= idata->dstaddr; - - prev_nh = (unsigned char *) &(ipv6->ip6_nxt); - - ptr = (unsigned char *) v6buffer + MIN_IPV6_HLEN; - - if(hbhopthdr_f){ - hbhopthdrs=0; - - while(hbhopthdrs < nhbhopthdr){ - if((ptr+ hbhopthdrlen[hbhopthdrs]) > (v6buffer+ idata->mtu)){ - puts("Packet too large while processing HBH Opt. Header"); - exit(EXIT_FAILURE); - } - - *prev_nh = IPPROTO_HOPOPTS; - prev_nh = ptr; - memcpy(ptr, hbhopthdr[hbhopthdrs], hbhopthdrlen[hbhopthdrs]); - ptr = ptr + hbhopthdrlen[hbhopthdrs]; - hbhopthdrs++; - } - } - - if(dstoptuhdr_f){ - dstoptuhdrs=0; - - while(dstoptuhdrs < ndstoptuhdr){ - if((ptr+ dstoptuhdrlen[dstoptuhdrs]) > (v6buffer+ idata->mtu)){ - puts("Packet too large while processing Dest. Opt. Header (Unfrag. Part)"); - exit(EXIT_FAILURE); - } - - *prev_nh = IPPROTO_DSTOPTS; - prev_nh = ptr; - memcpy(ptr, dstoptuhdr[dstoptuhdrs], dstoptuhdrlen[dstoptuhdrs]); - ptr = ptr + dstoptuhdrlen[dstoptuhdrs]; - dstoptuhdrs++; - } - } - - /* Everything that follows is the Fragmentable Part of the packet */ - fragpart = ptr; - - if(fragh_f){ - /* Check that we are able to send the Unfragmentable Part, together with a - Fragment Header and a chunk data over our link layer - */ - if( (fragpart+sizeof(fraghdr)+nfrags) > (v6buffer+ idata->mtu)){ - printf("Unfragmentable part too large for current MTU (%u bytes)\n", idata->mtu); - exit(EXIT_FAILURE); - } - - /* We prepare a separate Fragment Header, but we do not include it in the packet to be sent. - This Fragment Header will be used (an assembled with the rest of the packet by the - send_packet() function. - */ - memset(&fraghdr, 0, FRAG_HDR_SIZE); - *prev_nh = IPPROTO_FRAGMENT; - prev_nh = (unsigned char *) &fraghdr; - } - - if(dstopthdr_f){ - dstopthdrs=0; - - while(dstopthdrs < ndstopthdr){ - if((ptr+ dstopthdrlen[dstopthdrs]) > (v6buffer+idata->max_packet_size)){ - puts("Packet too large while processing Dest. Opt. Header (should be using the Frag. option?)"); - exit(EXIT_FAILURE); - } - - *prev_nh = IPPROTO_DSTOPTS; - prev_nh = ptr; - memcpy(ptr, dstopthdr[dstopthdrs], dstopthdrlen[dstopthdrs]); - ptr = ptr + dstopthdrlen[dstopthdrs]; - dstopthdrs++; - } - } - - - *prev_nh = IPPROTO_ICMPV6; - - if( (ptr+sizeof(struct icmp6_hdr)) > (v6buffer+ idata->max_packet_size)){ - puts("Packet too large while inserting ICMPv6 header (should be using Frag. option?)"); - exit(EXIT_FAILURE); - } - - icmp6= (struct icmp6_hdr *) ptr; - - icmp6->icmp6_type = icmp6type; - icmp6->icmp6_code = icmp6code; - - switch(icmp6type){ - case ICMP6_PACKET_TOO_BIG: - icmp6->icmp6_mtu= htonl(mtu); - break; - - case ICMP6_PARAM_PROB: - icmp6->icmp6_pptr=htonl(pointer); - break; - - case ICMP6_TIME_EXCEEDED: - case ICMP6_DST_UNREACH: - default: - icmp6->icmp6_data32[0]=0; - break; - } - - ptr += sizeof(struct icmp6_hdr); - - startofprefixes=ptr; + ipv6->ip6_flow = 0; + ipv6->ip6_vfc = 0x60; + ipv6->ip6_hlim = hoplimit; + ipv6->ip6_src = idata->srcaddr; + ipv6->ip6_dst = idata->dstaddr; + + prev_nh = (unsigned char *)&(ipv6->ip6_nxt); + + ptr = (unsigned char *)v6buffer + MIN_IPV6_HLEN; + + if (hbhopthdr_f) { + hbhopthdrs = 0; + + while (hbhopthdrs < nhbhopthdr) { + if ((ptr + hbhopthdrlen[hbhopthdrs]) > (v6buffer + idata->mtu)) { + puts("Packet too large while processing HBH Opt. Header"); + exit(EXIT_FAILURE); + } + + *prev_nh = IPPROTO_HOPOPTS; + prev_nh = ptr; + memcpy(ptr, hbhopthdr[hbhopthdrs], hbhopthdrlen[hbhopthdrs]); + ptr = ptr + hbhopthdrlen[hbhopthdrs]; + hbhopthdrs++; + } + } + + if (dstoptuhdr_f) { + dstoptuhdrs = 0; + + while (dstoptuhdrs < ndstoptuhdr) { + if ((ptr + dstoptuhdrlen[dstoptuhdrs]) > (v6buffer + idata->mtu)) { + puts("Packet too large while processing Dest. Opt. Header (Unfrag. Part)"); + exit(EXIT_FAILURE); + } + + *prev_nh = IPPROTO_DSTOPTS; + prev_nh = ptr; + memcpy(ptr, dstoptuhdr[dstoptuhdrs], dstoptuhdrlen[dstoptuhdrs]); + ptr = ptr + dstoptuhdrlen[dstoptuhdrs]; + dstoptuhdrs++; + } + } + + /* Everything that follows is the Fragmentable Part of the packet */ + fragpart = ptr; + + if (fragh_f) { + /* Check that we are able to send the Unfragmentable Part, together with a + Fragment Header and a chunk data over our link layer + */ + if ((fragpart + sizeof(fraghdr) + nfrags) > (v6buffer + idata->mtu)) { + printf("Unfragmentable part too large for current MTU (%u bytes)\n", idata->mtu); + exit(EXIT_FAILURE); + } + + /* We prepare a separate Fragment Header, but we do not include it in the packet to be sent. + This Fragment Header will be used (an assembled with the rest of the packet by the + send_packet() function. + */ + memset(&fraghdr, 0, FRAG_HDR_SIZE); + *prev_nh = IPPROTO_FRAGMENT; + prev_nh = (unsigned char *)&fraghdr; + } + + if (dstopthdr_f) { + dstopthdrs = 0; + + while (dstopthdrs < ndstopthdr) { + if ((ptr + dstopthdrlen[dstopthdrs]) > (v6buffer + idata->max_packet_size)) { + puts("Packet too large while processing Dest. Opt. Header (should be using the Frag. option?)"); + exit(EXIT_FAILURE); + } + + *prev_nh = IPPROTO_DSTOPTS; + prev_nh = ptr; + memcpy(ptr, dstopthdr[dstopthdrs], dstopthdrlen[dstopthdrs]); + ptr = ptr + dstopthdrlen[dstopthdrs]; + dstopthdrs++; + } + } + + *prev_nh = IPPROTO_ICMPV6; + + if ((ptr + sizeof(struct icmp6_hdr)) > (v6buffer + idata->max_packet_size)) { + puts("Packet too large while inserting ICMPv6 header (should be using Frag. option?)"); + exit(EXIT_FAILURE); + } + + icmp6 = (struct icmp6_hdr *)ptr; + + icmp6->icmp6_type = icmp6type; + icmp6->icmp6_code = icmp6code; + + switch (icmp6type) { + case ICMP6_PACKET_TOO_BIG: + icmp6->icmp6_mtu = htonl(mtu); + break; + + case ICMP6_PARAM_PROB: + icmp6->icmp6_pptr = htonl(pointer); + break; + + case ICMP6_TIME_EXCEEDED: + case ICMP6_DST_UNREACH: + default: + icmp6->icmp6_data32[0] = 0; + break; + } + + ptr += sizeof(struct icmp6_hdr); + + startofprefixes = ptr; } - - /* * Function: send_packet() * * Initialize the remaining fields of the Neighbor Advertisement Message, and * send the attack packet(s). */ -void send_packet(struct iface_data *idata, const u_char *pktdata, struct pcap_pkthdr * pkthdr){ - if(pktdata != NULL){ /* Sending a Redirect in response to a received packet */ - pkt_ether = (struct ether_header *) pktdata; - pkt_ipv6 = (struct ip6_hdr *)((char *) pkt_ether + idata->linkhsize); - - /* If the IPv6 Source Address of the incoming Neighbor Solicitation is the unspecified - address (::), the Neighbor Advertisement must be directed to the IPv6 all-nodes - multicast address (and the Ethernet Destination address should be 33:33:33:00:00:01). - Otherwise, the Neighbor Advertisement is sent to the IPv6 Source Address (and - Ethernet Source Address) of the incoming Neighbor Solicitation message - */ - pkt_ipv6addr = &(pkt_ipv6->ip6_src); - - /* - We don't send any packets if the Source Address of the captured packet is the unspecified - address. - */ - if(IN6_IS_ADDR_UNSPECIFIED(pkt_ipv6addr)){ - return; - } - else{ - ipv6->ip6_dst = pkt_ipv6->ip6_src; - - if(idata->type == DLT_EN10MB && !(idata->flags & IFACE_LOOPBACK)) - ethernet->dst = pkt_ether->src; - } - - pkt_ipv6addr = &(pkt_ipv6->ip6_dst); - - /* - We respond to packets sent to a multicast address only if the tool has been explicitly instructed - to do so. - */ - if(IN6_IS_ADDR_MULTICAST(pkt_ipv6addr) && !respmcast_f) - return; - } - - targetport= targetportl; - - do{ - peerport= peerportl; - - do{ - ptr=startofprefixes; - - /* We include a Redirected Header by default */ - if(!nopayload_f){ - /* - The amount of data that we include in the Redirected Header depends on a number - of factors: - a) If a specific amount has been specified, we include up to that amount of - data (i.e., provided it is available from the captured packet) - b) If our packet has not yet exceeded the minimum IPv6 MTU (1280 bytes), we - include as many bytes as possible without exceeding that size. - c) If our packet already exceeds the minimum IPv6 MTU, we include at most 68 - bytes - */ - if(pktdata != NULL){ - if(rhlength_f){ - rhbytes= rhlength; - } - else{ - currentsize= ptr - (unsigned char *)ipv6; - if(currentsize > 1280) - rhbytes=48; - else - rhbytes= 1280- currentsize; - } - - pktbytes= pkthdr->caplen; - - if( rhbytes > pktbytes) - rhbytes= pktbytes; - - rhbytes= (rhbytes>>3) << 3; - - if( (ptr+rhbytes) > (v6buffer+idata->max_packet_size)){ - puts("Packet Too Large while inserting ICMPv6 payload"); - exit(EXIT_FAILURE); - } - - memcpy(ptr, pkt_ipv6, rhbytes); - ptr+= rhbytes; - } - else{ - /* The ICMPv6 Error is *not* being sent in response to a received packet */ - - if(rhlength_f){ - rhbytes= rhlength; - } - else{ - currentsize= ptr - (unsigned char *)ipv6; - if(currentsize > 1280) - rhbytes=48; - else - rhbytes= 1280- currentsize; - } - - rhbytes= (rhbytes>>3) << 3; - - if( (ptr+rhbytes) > (v6buffer+idata->max_packet_size)){ - puts("Packet Too Large while inserting Redirected Header Option"); - exit(EXIT_FAILURE); - } - - rhipv6 = (struct ip6_hdr *) rhbuff; - rhipv6->ip6_flow= 0; - rhipv6->ip6_vfc= 0x60; - rhipv6->ip6_hlim= ip6hoplimit; - rhipv6->ip6_src= targetaddr; - rhipv6->ip6_dst= peeraddr; - rhipv6->ip6_plen= htons(ip6length); - - if(rhtcp_f || rhdefault_f){ - rhipv6->ip6_nxt= IPPROTO_TCP; - rhtcp= (struct tcp_hdr *) (rhbuff + sizeof(struct ip6_hdr)); - memset(rhtcp, 0, sizeof(struct tcp_hdr)); - rhtcp->th_sport= htons((uint16_t) targetport); - rhtcp->th_dport= htons((uint16_t) peerport); - rhtcp->th_seq = htonl(tcpseq); - rhtcp->th_ack= htonl(tcpack); - rhtcp->th_flags= tcpflags; - rhtcp->th_urp= htons(tcpurg); - rhtcp->th_win= htons(tcpwin); - rhtcp->th_off= MIN_TCP_HLEN >> 2; - - if(rhbytes < (MIN_IPV6_HLEN + MIN_TCP_HLEN)){ - rhtcp->th_sum= random(); - memcpy(ptr, rhbuff, rhbytes); - ptr+= rhbytes; - } - else{ - /* We will compute the TCP checksum */ - rhtcp->th_sum= 0; - - /* We now reuse the rhipv6 and rhtcp variables to point to the IPv6 and TCP header of the packet to be sent */ - rhipv6= (struct ip6_hdr *) ptr; - rhtcp= (struct tcp_hdr *) ( (char *) rhipv6 + sizeof(struct ip6_hdr)); - - memcpy(ptr, rhbuff, MIN_IPV6_HLEN+MIN_TCP_HLEN); - ptr += MIN_IPV6_HLEN+MIN_TCP_HLEN; - rhbytes -= MIN_IPV6_HLEN+MIN_TCP_HLEN; - - while(rhbytes>=4){ - *(uint32_t *)ptr = random(); - ptr += sizeof(uint32_t); - rhbytes -= sizeof(uint32_t); - } - - if(ip6length_f) - rhipv6->ip6_plen= htons(ip6length); - else - rhipv6->ip6_plen= htons(ptr - ((unsigned char *) rhipv6 + sizeof(struct ip6_hdr))); - - rhtcp->th_sum= in_chksum(rhipv6, rhtcp, (ptr - (unsigned char *) rhtcp), IPPROTO_TCP); - } - } - - else if(rhudp_f){ - rhipv6->ip6_nxt= IPPROTO_UDP; - rhudp = (struct udp_hdr *) (rhbuff + sizeof(struct ip6_hdr)); - rhudp->uh_sport= htons(targetport); - rhudp->uh_dport= htons(peerport); - - if(rhbytes < (MIN_IPV6_HLEN + MIN_UDP_HLEN)){ - rhudp->uh_sum= random(); - memcpy(ptr, rhbuff, rhbytes); - ptr+= rhbytes; - } - else{ - /* We will compute the UDP checksum */ - rhudp->uh_sum= 0; - - /* We now reuse the rhipv6 and rhudp variables to point to the IPv6 and TCP header of the packet to be sent */ - rhipv6= (struct ip6_hdr *) ptr; - rhudp= (struct udp_hdr *) ( (char *) rhipv6 + sizeof(struct ip6_hdr)); - - memcpy(ptr, rhbuff, MIN_IPV6_HLEN+MIN_UDP_HLEN); - ptr += (MIN_IPV6_HLEN+MIN_UDP_HLEN); - rhbytes -= MIN_IPV6_HLEN+MIN_UDP_HLEN; - while(rhbytes>=4){ - *(uint32_t *)ptr = random(); - ptr += sizeof(uint32_t); - rhbytes -= sizeof(uint32_t); - } - - if(!ip6length_f) - rhipv6->ip6_plen= htons(ptr - ((unsigned char *) rhipv6 + sizeof(struct ip6_hdr))); - - rhudp->uh_ulen= htons(ptr - ((unsigned char *) rhipv6 + sizeof(struct ip6_hdr))); - rhudp->uh_sum= in_chksum(rhipv6, rhudp, (ptr - (unsigned char *) rhudp), IPPROTO_UDP); - } - } - else if(rhicmp6_f){ - rhipv6->ip6_nxt= IPPROTO_ICMPV6; - rhicmp6 = (struct icmp6_hdr *) (rhbuff + sizeof(struct ip6_hdr)); - rhicmp6->icmp6_type = ICMP6_ECHO_REQUEST; - rhicmp6->icmp6_code = 0; - rhicmp6->icmp6_data16[0]= random(); /* Identifier */ - rhicmp6->icmp6_data16[1]= random(); /* Sequence Number */ - - if(rhbytes <= (MIN_IPV6_HLEN + MIN_ICMP6_HLEN)){ - rhicmp6->icmp6_cksum = random(); - memcpy(ptr, rhbuff, rhbytes); - ptr+= rhbytes; - } - else{ - rhicmp6->icmp6_cksum = 0; - - /* We now reuse the rhipv6 and rhicmp6 variables to point to the IPv6 and ICMPv6 header of the packet to be sent */ - rhipv6= (struct ip6_hdr *) ptr; - rhicmp6= (struct icmp6_hdr *) ( (char *) rhipv6 + sizeof(struct ip6_hdr)); - - memcpy(ptr, rhbuff, MIN_IPV6_HLEN+MIN_ICMP6_HLEN); - ptr += MIN_IPV6_HLEN+MIN_ICMP6_HLEN; - rhbytes -= MIN_IPV6_HLEN+MIN_ICMP6_HLEN; - while(rhbytes>=4){ - *(uint32_t *)ptr = random(); - ptr += sizeof(uint32_t); - rhbytes -= sizeof(uint32_t); - } - - if(!ip6length_f) - rhipv6->ip6_plen= htons(ptr - ((unsigned char *) rhipv6 + sizeof(struct ip6_hdr))); - - rhicmp6->icmp6_cksum= in_chksum(rhipv6, rhicmp6, (ptr - (unsigned char *) rhicmp6), IPPROTO_ICMPV6); - } - } - } - } - - icmp6->icmp6_cksum = 0; - icmp6->icmp6_cksum = in_chksum(v6buffer, icmp6, ptr-((unsigned char *)icmp6), IPPROTO_ICMPV6); - - if(!fragh_f){ - ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); - - if((nw=pcap_inject(idata->pfd, buffer, ptr - buffer)) == -1){ - printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); - exit(EXIT_FAILURE); - } - - if(nw != (ptr-buffer)){ - printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, \ - (LUI) (ptr-buffer)); - exit(EXIT_FAILURE); - } - } - else{ - ptrend= ptr; - ptr= fragpart; - fptr = fragbuffer; - fipv6 = (struct ip6_hdr *) (fragbuffer + idata->linkhsize); - fptrend = fptr + idata->linkhsize+MIN_IPV6_HLEN+MAX_IPV6_PAYLOAD; - memcpy(fptr, buffer, fragpart-buffer); - fptr = fptr + (fragpart-buffer); - - if( (fptr+FRAG_HDR_SIZE)> fptrend){ - puts("Unfragmentable Part is Too Large"); - exit(EXIT_FAILURE); - } - - memcpy(fptr, (char *) &fraghdr, FRAG_HDR_SIZE); - fh= (struct ip6_frag *) fptr; - fh->ip6f_ident=random(); - startoffragment = fptr + FRAG_HDR_SIZE; - - /* - * Check that the selected fragment size is not larger than the largest - * fragment size that can be sent - */ - - if(nfrags > (fptrend - fptr)) - nfrags= (fptrend-fptr); - - m=IP6F_MORE_FRAG; - - while((ptr< ptrend) && m==IP6F_MORE_FRAG){ - fptr= startoffragment; - - if( (ptrend-ptr) <= nfrags){ - fragsize= ptrend-ptr; - m=0; - } - else{ - fragsize = (nfrags + 7) & ntohs(IP6F_OFF_MASK); - } - - memcpy(fptr, ptr, fragsize); - fh->ip6f_offlg = (htons(ptr-fragpart) & IP6F_OFF_MASK) | m; - ptr+=fragsize; - fptr+=fragsize; - - fipv6->ip6_plen = htons((fptr - fragbuffer) - MIN_IPV6_HLEN - idata->linkhsize); - - if((nw=pcap_inject(idata->pfd, fragbuffer, fptr - fragbuffer)) == -1){ - printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); - exit(EXIT_FAILURE); - } - - if(nw != (fptr- fragbuffer)){ - printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", \ - nw, (LUI) (ptr-buffer)); - exit(EXIT_FAILURE); - } - } /* Sending fragments */ - } /* Sending fragmented datagram */ - - peerport++; - - }while(peerport<=peerporth); - - targetport++; - }while(targetport<=targetporth); +void send_packet(struct iface_data *idata, const u_char *pktdata, struct pcap_pkthdr *pkthdr) { + if (pktdata != NULL) { /* Sending a Redirect in response to a received packet */ + pkt_ether = (struct ether_header *)pktdata; + pkt_ipv6 = (struct ip6_hdr *)((char *)pkt_ether + idata->linkhsize); + + /* If the IPv6 Source Address of the incoming Neighbor Solicitation is the unspecified + address (::), the Neighbor Advertisement must be directed to the IPv6 all-nodes + multicast address (and the Ethernet Destination address should be 33:33:33:00:00:01). + Otherwise, the Neighbor Advertisement is sent to the IPv6 Source Address (and + Ethernet Source Address) of the incoming Neighbor Solicitation message + */ + pkt_ipv6addr = &(pkt_ipv6->ip6_src); + + /* + We don't send any packets if the Source Address of the captured packet is the unspecified + address. + */ + if (IN6_IS_ADDR_UNSPECIFIED(pkt_ipv6addr)) { + return; + } + else { + ipv6->ip6_dst = pkt_ipv6->ip6_src; + + if (idata->type == DLT_EN10MB && !(idata->flags & IFACE_LOOPBACK)) + ethernet->dst = pkt_ether->src; + } + + pkt_ipv6addr = &(pkt_ipv6->ip6_dst); + + /* + We respond to packets sent to a multicast address only if the tool has been explicitly instructed + to do so. + */ + if (IN6_IS_ADDR_MULTICAST(pkt_ipv6addr) && !respmcast_f) + return; + } + + targetport = targetportl; + + do { + peerport = peerportl; + + do { + ptr = startofprefixes; + + /* We include a Redirected Header by default */ + if (!nopayload_f) { + /* + The amount of data that we include in the Redirected Header depends on a number + of factors: + a) If a specific amount has been specified, we include up to that amount of + data (i.e., provided it is available from the captured packet) + b) If our packet has not yet exceeded the minimum IPv6 MTU (1280 bytes), we + include as many bytes as possible without exceeding that size. + c) If our packet already exceeds the minimum IPv6 MTU, we include at most 68 + bytes + */ + if (pktdata != NULL) { + if (rhlength_f) { + rhbytes = rhlength; + } + else { + currentsize = ptr - (unsigned char *)ipv6; + if (currentsize > 1280) + rhbytes = 48; + else + rhbytes = 1280 - currentsize; + } + + pktbytes = pkthdr->caplen; + + if (rhbytes > pktbytes) + rhbytes = pktbytes; + + rhbytes = (rhbytes >> 3) << 3; + + if ((ptr + rhbytes) > (v6buffer + idata->max_packet_size)) { + puts("Packet Too Large while inserting ICMPv6 payload"); + exit(EXIT_FAILURE); + } + + memcpy(ptr, pkt_ipv6, rhbytes); + ptr += rhbytes; + } + else { + /* The ICMPv6 Error is *not* being sent in response to a received packet */ + + if (rhlength_f) { + rhbytes = rhlength; + } + else { + currentsize = ptr - (unsigned char *)ipv6; + if (currentsize > 1280) + rhbytes = 48; + else + rhbytes = 1280 - currentsize; + } + + rhbytes = (rhbytes >> 3) << 3; + + if ((ptr + rhbytes) > (v6buffer + idata->max_packet_size)) { + puts("Packet Too Large while inserting Redirected Header Option"); + exit(EXIT_FAILURE); + } + + rhipv6 = (struct ip6_hdr *)rhbuff; + rhipv6->ip6_flow = 0; + rhipv6->ip6_vfc = 0x60; + rhipv6->ip6_hlim = ip6hoplimit; + rhipv6->ip6_src = targetaddr; + rhipv6->ip6_dst = peeraddr; + rhipv6->ip6_plen = htons(ip6length); + + if (rhtcp_f || rhdefault_f) { + rhipv6->ip6_nxt = IPPROTO_TCP; + rhtcp = (struct tcp_hdr *)(rhbuff + sizeof(struct ip6_hdr)); + memset(rhtcp, 0, sizeof(struct tcp_hdr)); + rhtcp->th_sport = htons((uint16_t)targetport); + rhtcp->th_dport = htons((uint16_t)peerport); + rhtcp->th_seq = htonl(tcpseq); + rhtcp->th_ack = htonl(tcpack); + rhtcp->th_flags = tcpflags; + rhtcp->th_urp = htons(tcpurg); + rhtcp->th_win = htons(tcpwin); + rhtcp->th_off = MIN_TCP_HLEN >> 2; + + if (rhbytes < (MIN_IPV6_HLEN + MIN_TCP_HLEN)) { + rhtcp->th_sum = random(); + memcpy(ptr, rhbuff, rhbytes); + ptr += rhbytes; + } + else { + /* We will compute the TCP checksum */ + rhtcp->th_sum = 0; + + /* We now reuse the rhipv6 and rhtcp variables to point to the IPv6 and TCP header of the + * packet to be sent */ + rhipv6 = (struct ip6_hdr *)ptr; + rhtcp = (struct tcp_hdr *)((char *)rhipv6 + sizeof(struct ip6_hdr)); + + memcpy(ptr, rhbuff, MIN_IPV6_HLEN + MIN_TCP_HLEN); + ptr += MIN_IPV6_HLEN + MIN_TCP_HLEN; + rhbytes -= MIN_IPV6_HLEN + MIN_TCP_HLEN; + + while (rhbytes >= 4) { + *(uint32_t *)ptr = random(); + ptr += sizeof(uint32_t); + rhbytes -= sizeof(uint32_t); + } + + if (ip6length_f) + rhipv6->ip6_plen = htons(ip6length); + else + rhipv6->ip6_plen = htons(ptr - ((unsigned char *)rhipv6 + sizeof(struct ip6_hdr))); + + rhtcp->th_sum = in_chksum(rhipv6, rhtcp, (ptr - (unsigned char *)rhtcp), IPPROTO_TCP); + } + } + + else if (rhudp_f) { + rhipv6->ip6_nxt = IPPROTO_UDP; + rhudp = (struct udp_hdr *)(rhbuff + sizeof(struct ip6_hdr)); + rhudp->uh_sport = htons(targetport); + rhudp->uh_dport = htons(peerport); + + if (rhbytes < (MIN_IPV6_HLEN + MIN_UDP_HLEN)) { + rhudp->uh_sum = random(); + memcpy(ptr, rhbuff, rhbytes); + ptr += rhbytes; + } + else { + /* We will compute the UDP checksum */ + rhudp->uh_sum = 0; + + /* We now reuse the rhipv6 and rhudp variables to point to the IPv6 and TCP header of the + * packet to be sent */ + rhipv6 = (struct ip6_hdr *)ptr; + rhudp = (struct udp_hdr *)((char *)rhipv6 + sizeof(struct ip6_hdr)); + + memcpy(ptr, rhbuff, MIN_IPV6_HLEN + MIN_UDP_HLEN); + ptr += (MIN_IPV6_HLEN + MIN_UDP_HLEN); + rhbytes -= MIN_IPV6_HLEN + MIN_UDP_HLEN; + while (rhbytes >= 4) { + *(uint32_t *)ptr = random(); + ptr += sizeof(uint32_t); + rhbytes -= sizeof(uint32_t); + } + + if (!ip6length_f) + rhipv6->ip6_plen = htons(ptr - ((unsigned char *)rhipv6 + sizeof(struct ip6_hdr))); + + rhudp->uh_ulen = htons(ptr - ((unsigned char *)rhipv6 + sizeof(struct ip6_hdr))); + rhudp->uh_sum = in_chksum(rhipv6, rhudp, (ptr - (unsigned char *)rhudp), IPPROTO_UDP); + } + } + else if (rhicmp6_f) { + rhipv6->ip6_nxt = IPPROTO_ICMPV6; + rhicmp6 = (struct icmp6_hdr *)(rhbuff + sizeof(struct ip6_hdr)); + rhicmp6->icmp6_type = ICMP6_ECHO_REQUEST; + rhicmp6->icmp6_code = 0; + rhicmp6->icmp6_data16[0] = random(); /* Identifier */ + rhicmp6->icmp6_data16[1] = random(); /* Sequence Number */ + + if (rhbytes <= (MIN_IPV6_HLEN + MIN_ICMP6_HLEN)) { + rhicmp6->icmp6_cksum = random(); + memcpy(ptr, rhbuff, rhbytes); + ptr += rhbytes; + } + else { + rhicmp6->icmp6_cksum = 0; + + /* We now reuse the rhipv6 and rhicmp6 variables to point to the IPv6 and ICMPv6 header of + * the packet to be sent */ + rhipv6 = (struct ip6_hdr *)ptr; + rhicmp6 = (struct icmp6_hdr *)((char *)rhipv6 + sizeof(struct ip6_hdr)); + + memcpy(ptr, rhbuff, MIN_IPV6_HLEN + MIN_ICMP6_HLEN); + ptr += MIN_IPV6_HLEN + MIN_ICMP6_HLEN; + rhbytes -= MIN_IPV6_HLEN + MIN_ICMP6_HLEN; + while (rhbytes >= 4) { + *(uint32_t *)ptr = random(); + ptr += sizeof(uint32_t); + rhbytes -= sizeof(uint32_t); + } + + if (!ip6length_f) + rhipv6->ip6_plen = htons(ptr - ((unsigned char *)rhipv6 + sizeof(struct ip6_hdr))); + + rhicmp6->icmp6_cksum = + in_chksum(rhipv6, rhicmp6, (ptr - (unsigned char *)rhicmp6), IPPROTO_ICMPV6); + } + } + } + } + + icmp6->icmp6_cksum = 0; + icmp6->icmp6_cksum = in_chksum(v6buffer, icmp6, ptr - ((unsigned char *)icmp6), IPPROTO_ICMPV6); + + if (!fragh_f) { + ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); + + if ((nw = pcap_inject(idata->pfd, buffer, ptr - buffer)) == -1) { + printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); + exit(EXIT_FAILURE); + } + + if (nw != (ptr - buffer)) { + printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, (LUI)(ptr - buffer)); + exit(EXIT_FAILURE); + } + } + else { + ptrend = ptr; + ptr = fragpart; + fptr = fragbuffer; + fipv6 = (struct ip6_hdr *)(fragbuffer + idata->linkhsize); + fptrend = fptr + idata->linkhsize + MIN_IPV6_HLEN + MAX_IPV6_PAYLOAD; + memcpy(fptr, buffer, fragpart - buffer); + fptr = fptr + (fragpart - buffer); + + if ((fptr + FRAG_HDR_SIZE) > fptrend) { + puts("Unfragmentable Part is Too Large"); + exit(EXIT_FAILURE); + } + + memcpy(fptr, (char *)&fraghdr, FRAG_HDR_SIZE); + fh = (struct ip6_frag *)fptr; + fh->ip6f_ident = random(); + startoffragment = fptr + FRAG_HDR_SIZE; + + /* + * Check that the selected fragment size is not larger than the largest + * fragment size that can be sent + */ + + if (nfrags > (fptrend - fptr)) + nfrags = (fptrend - fptr); + + m = IP6F_MORE_FRAG; + + while ((ptr < ptrend) && m == IP6F_MORE_FRAG) { + fptr = startoffragment; + + if ((ptrend - ptr) <= nfrags) { + fragsize = ptrend - ptr; + m = 0; + } + else { + fragsize = (nfrags + 7) & ntohs(IP6F_OFF_MASK); + } + + memcpy(fptr, ptr, fragsize); + fh->ip6f_offlg = (htons(ptr - fragpart) & IP6F_OFF_MASK) | m; + ptr += fragsize; + fptr += fragsize; + + fipv6->ip6_plen = htons((fptr - fragbuffer) - MIN_IPV6_HLEN - idata->linkhsize); + + if ((nw = pcap_inject(idata->pfd, fragbuffer, fptr - fragbuffer)) == -1) { + printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); + exit(EXIT_FAILURE); + } + + if (nw != (fptr - fragbuffer)) { + printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, (LUI)(ptr - buffer)); + exit(EXIT_FAILURE); + } + } /* Sending fragments */ + } /* Sending fragmented datagram */ + + peerport++; + + } while (peerport <= peerporth); + + targetport++; + } while (targetport <= targetporth); } - - /* * Function: usage() * * Prints the syntax of the icmp6 tool */ -void usage(void){ +void usage(void) { puts("usage: icmp6 [-i INTERFACE] [-s SRC_ADDR[/LEN]] [-d DST_ADDR]\n" - " [-S LINK_SRC_ADDR] [-D LINK-DST-ADDR] [-c HOP_LIMIT] [-y FRAG_SIZE]\n" - " [-u DST_OPT_HDR_SIZE] [-U DST_OPT_U_HDR_SIZE] [-H HBH_OPT_HDR_SIZE]\n" - " [-t TYPE[:CODE] | -e CODE | -A CODE -V CODE -R CODE] [-r TARGET_ADDR]\n" - " [-x PEER_ADDR] [-c HOP_LIMIT] [-m MTU] [-O POINTER] [-p PAYLOAD_TYPE]\n" - " [-P PAYLOAD_SIZE] [-n] [-a SRC_PORTL[:SRC_PORTH]]\n" - " [-o DST_PORTL[:DST_PORTH]] [-X TCP_FLAGS] [-q TCP_SEQ] [-Q TCP_ACK]\n" - " [-V TCP_URP] [-w TCP_WIN] [-M] [-j PREFIX[/LEN]] [-k PREFIX[/LEN]]\n" - " [-J LINK_ADDR] [-K LINK_ADDR] [-b PREFIX[/LEN]] [-g PREFIX[/LEN]]\n" - " [-B LINK_ADDR] [-G LINK_ADDR] [-f] [-L | -l] [-z] [-v] [-h]"); + " [-S LINK_SRC_ADDR] [-D LINK-DST-ADDR] [-c HOP_LIMIT] [-y FRAG_SIZE]\n" + " [-u DST_OPT_HDR_SIZE] [-U DST_OPT_U_HDR_SIZE] [-H HBH_OPT_HDR_SIZE]\n" + " [-t TYPE[:CODE] | -e CODE | -A CODE -V CODE -R CODE] [-r TARGET_ADDR]\n" + " [-x PEER_ADDR] [-c HOP_LIMIT] [-m MTU] [-O POINTER] [-p PAYLOAD_TYPE]\n" + " [-P PAYLOAD_SIZE] [-n] [-a SRC_PORTL[:SRC_PORTH]]\n" + " [-o DST_PORTL[:DST_PORTH]] [-X TCP_FLAGS] [-q TCP_SEQ] [-Q TCP_ACK]\n" + " [-V TCP_URP] [-w TCP_WIN] [-M] [-j PREFIX[/LEN]] [-k PREFIX[/LEN]]\n" + " [-J LINK_ADDR] [-K LINK_ADDR] [-b PREFIX[/LEN]] [-g PREFIX[/LEN]]\n" + " [-B LINK_ADDR] [-G LINK_ADDR] [-f] [-L | -l] [-z] [-v] [-h]"); } - /* * Function: print_help() * * Prints help information for the icmp6 tool */ -void print_help(void){ - puts(SI6_TOOLKIT); - puts("icmp6: Security assessment tool for attack vectors based on ICMPv6 error messages\n"); - usage(); - - puts("\nOPTIONS:\n" - " --interface, -i Network interface\n" - " --src-addr, -s IPv6 Source Address\n" - " --dst-addr, -d IPv6 Destination Address\n" - " --hop-limit, -c IPv6 Hop Limit\n" - " --frag-hdr. -y Fragment Header\n" - " --dst-opt-hdr, -u Destination Options Header (Fragmentable Part)\n" - " --dst-opt-u-hdr, -U Destination Options Header (Unfragmentable Part)\n" - " --hbh-opt-hdr, -H Hop by Hop Options Header\n" - " --link-src-addr, -S Link-layer Destination Address\n" - " --link-dst-addr, -D Link-layer Source Address\n" - " --icmp6, -t ICMPv6 Type:Code\n" - " --icmp6-dest-unreach, -e ICMPv6 Destination Unreachable\n" - " --icmp6-packet-too-big, -E ICMPv6 Packet Too Big\n" - " --icmp6-time-exceeded, -A ICMPv6 Time Exceeeded\n" - " --icmp6-param-problem, -R ICMPv6 Parameter Problem\n" - " --mtu, -m Next-Hop MTU (ICMPv6 Packet Too Big)\n" - " --pointer, -O Pointer (ICMPv6 Parameter Problem\n" - " --payload-type, -p Redirected Header Payload Type\n" - " --payload-size, -P Redirected Header Payload Size\n" - " --no-payload, -n Do not include a Redirected Header Option\n" - " --ipv6-hlim, -C ICMPv6 Payload's Hop Limit\n" - " --target-addr, -r ICMPv6 Payload's IPv6 Source Address\n" - " --peer-addr, -x ICMPv6 Payload's IPv6 Destination Address\n" - " --target-port, -o ICMPv6 Payload's Source Port\n" - " --peer-port, -a ICMPv6 Payload's Destination Port\n" - " --tcp-flags, -X ICMPv6 Payload's TCP Flags\n" - " --tcp-seq, -q ICMPv6 Payload's TCP SEQ Number\n" - " --tcp-ack, -Q ICMPv6 Payload's TCP ACK Number\n" - " --tcp-urg, -V ICMPv6 Payload's TCP URG Pointer\n" - " --tcp-win, -w ICMPv6 Payload's TCP Window\n" - " --resp-mcast, -M Respond to Multicast Packets\n" - " --block-src, -j Block IPv6 Source Address prefix\n" - " --block-dst, -k Block IPv6 Destination Address prefix\n" - " --block-link-src, -J Block Ethernet Source Address\n" - " --block-link-dst, -K Block Ethernet Destination Address\n" - " --accept-src, -b Accept IPv6 Source Address prefix\n" - " --accept-dst, -g Accept IPv6 Destination Address prefix\n" - " --accept-link-src, -B Accept Ethernet Source Address\n" - " --accept-link-dst, -G Accept Ethernet Destination Address\n" - " --sanity-filters, -f Add sanity filters\n" - " --listen, -L Listen to incoming traffic\n" - " --loop, -l Send periodic ICMPv6 error messages\n" - " --sleep, -z Pause between sending ICMPv6 error messages\n" - " --help, -h Print help for the icmp6 tool\n" - " --verbose, -v Be verbose\n" - "\n" - " Programmed by Fernando Gont for SI6 Networks \n" - " Please send any bug reports to \n" - ); +void print_help(void) { + puts(SI6_TOOLKIT); + puts("icmp6: Security assessment tool for attack vectors based on ICMPv6 error messages\n"); + usage(); + + puts("\nOPTIONS:\n" + " --interface, -i Network interface\n" + " --src-addr, -s IPv6 Source Address\n" + " --dst-addr, -d IPv6 Destination Address\n" + " --hop-limit, -c IPv6 Hop Limit\n" + " --frag-hdr. -y Fragment Header\n" + " --dst-opt-hdr, -u Destination Options Header (Fragmentable Part)\n" + " --dst-opt-u-hdr, -U Destination Options Header (Unfragmentable Part)\n" + " --hbh-opt-hdr, -H Hop by Hop Options Header\n" + " --link-src-addr, -S Link-layer Destination Address\n" + " --link-dst-addr, -D Link-layer Source Address\n" + " --icmp6, -t ICMPv6 Type:Code\n" + " --icmp6-dest-unreach, -e ICMPv6 Destination Unreachable\n" + " --icmp6-packet-too-big, -E ICMPv6 Packet Too Big\n" + " --icmp6-time-exceeded, -A ICMPv6 Time Exceeeded\n" + " --icmp6-param-problem, -R ICMPv6 Parameter Problem\n" + " --mtu, -m Next-Hop MTU (ICMPv6 Packet Too Big)\n" + " --pointer, -O Pointer (ICMPv6 Parameter Problem\n" + " --payload-type, -p Redirected Header Payload Type\n" + " --payload-size, -P Redirected Header Payload Size\n" + " --no-payload, -n Do not include a Redirected Header Option\n" + " --ipv6-hlim, -C ICMPv6 Payload's Hop Limit\n" + " --target-addr, -r ICMPv6 Payload's IPv6 Source Address\n" + " --peer-addr, -x ICMPv6 Payload's IPv6 Destination Address\n" + " --target-port, -o ICMPv6 Payload's Source Port\n" + " --peer-port, -a ICMPv6 Payload's Destination Port\n" + " --tcp-flags, -X ICMPv6 Payload's TCP Flags\n" + " --tcp-seq, -q ICMPv6 Payload's TCP SEQ Number\n" + " --tcp-ack, -Q ICMPv6 Payload's TCP ACK Number\n" + " --tcp-urg, -V ICMPv6 Payload's TCP URG Pointer\n" + " --tcp-win, -w ICMPv6 Payload's TCP Window\n" + " --resp-mcast, -M Respond to Multicast Packets\n" + " --block-src, -j Block IPv6 Source Address prefix\n" + " --block-dst, -k Block IPv6 Destination Address prefix\n" + " --block-link-src, -J Block Ethernet Source Address\n" + " --block-link-dst, -K Block Ethernet Destination Address\n" + " --accept-src, -b Accept IPv6 Source Address prefix\n" + " --accept-dst, -g Accept IPv6 Destination Address prefix\n" + " --accept-link-src, -B Accept Ethernet Source Address\n" + " --accept-link-dst, -G Accept Ethernet Destination Address\n" + " --sanity-filters, -f Add sanity filters\n" + " --listen, -L Listen to incoming traffic\n" + " --loop, -l Send periodic ICMPv6 error messages\n" + " --sleep, -z Pause between sending ICMPv6 error messages\n" + " --help, -h Print help for the icmp6 tool\n" + " --verbose, -v Be verbose\n" + "\n" + " Programmed by Fernando Gont for SI6 Networks \n" + " Please send any bug reports to \n"); } - /* * Function: print_attack_info() * * Prints attack details (when the verbose ("-v") option is specified). */ - -void print_attack_info(struct iface_data *idata){ - puts( "icmp6: Security assessment tool for attack vectors based on ICMPv6 messages\n"); - - if(idata->type == DLT_EN10MB && !(idata->flags & IFACE_LOOPBACK)){ - if(ether_ntop(&(idata->hsrcaddr), plinkaddr, sizeof(plinkaddr)) == 0){ - puts("ether_ntop(): Error converting address"); - exit(EXIT_FAILURE); - } - - printf("Ethernet Source Address: %s%s\n", plinkaddr, ((!idata->hsrcaddr_f)?" (randomized)":"")); - - /* - Ethernet Destination Address only used if a IPv6 Destination Address or an - Ethernet Destination Address were specified. - */ - if(idata->dstaddr_f){ - if(ether_ntop(&(idata->hdstaddr), plinkaddr, sizeof(plinkaddr)) == 0){ - puts("ether_ntop(): Error converting address"); - exit(EXIT_FAILURE); - } - - printf("Ethernet Destination Address: %s%s\n", plinkaddr, \ - ((!idata->hdstaddr_f)?" (automatically selected)":"")); - } - } - - if(idata->srcaddr_f){ - if(inet_ntop(AF_INET6, &(idata->srcaddr), psrcaddr, sizeof(psrcaddr)) == NULL){ - puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); - exit(EXIT_FAILURE); - } - - /* XXX Should really differentate between 'automatically selected' and 'randomized' */ - printf("IPv6 Source Address: %s%s\n", psrcaddr, ((idata->srcaddr_f != TRUE)?" (automatically selected)":"")); - } - - if(idata->dstaddr_f){ - if(inet_ntop(AF_INET6, &(idata->dstaddr), pdstaddr, sizeof(pdstaddr)) == NULL){ - puts("inet_ntop(): Error converting IPv6 Destination Address to presentation format"); - exit(EXIT_FAILURE); - } - - printf("IPv6 Destination Address: %s\n", pdstaddr); - } - - printf("IPv6 Hop Limit: %u%s\n", hoplimit, (hoplimit_f)?"":" (randomized)"); - - for(i=0; idstaddr_f){ - printf("Payload Type: IPv6/TCP%s\n", (rhdefault_f?" (default)":"")); - } - else if(rhudp_f && idata->dstaddr_f){ - puts("Payload Type: IPv6/UDP"); - } - else if(rhicmp6_f && idata->dstaddr_f){ - puts("Payload Type: IPv6/ICMPv6 Echo Request"); - } - - if(inet_ntop(AF_INET6, &targetaddr, pv6addr, sizeof(pv6addr)) == NULL){ - puts("inet_ntop(): Error converting Redirected Address to presentation format"); - exit(EXIT_FAILURE); - } - - if(idata->srcaddr_f){ - printf("Source Address: %s%s\n", pv6addr, ((!targetaddr_f)?" (automatically-selected)":"")); - } - - if(inet_ntop(AF_INET6, &peeraddr, pv6addr, sizeof(pv6addr)) == NULL){ - puts("inet_ntop(): Error converting Redirect Target Address to presentation format"); - exit(EXIT_FAILURE); - } - - if(idata->dstaddr_f){ - printf("Destination Address: %s%s\n", pv6addr, ((!peeraddr_f)?" (randomized)":"")); - } - - printf("Hop Limit: %u%s\n", ip6hoplimit, (ip6hoplimit_f)?"":" (randomized)"); - - if((rhtcp_f || rhdefault_f) && idata->dstaddr_f){ - if(targetporth_f){ - printf("Source Port: %u-%u\t", targetportl, targetporth); - } - else{ - printf("Source Port: %u%s\t", targetportl, (targetportl_f?"":" (randomized)")); - - } - - if(peerporth_f){ - printf("Destination Port: %u-%u\t", peerportl, peerporth); - } - else{ - printf("Destination Port: %u%s\n", peerportl, (peerportl_f?"":" (randomized)")); - - } - - printf("SEQ Number: %u%s\tACK Number: %u%s\n", tcpseq, (tcpseq_f?"":" (randomized)"), \ - tcpack, (tcpack_f?"":" (randomized)")); - - printf("Flags: %s%s%s%s%s%s%s%s\t", ((tcpflags & TH_FIN)?"F":""), ((tcpflags & TH_SYN)?"S":""), \ - ((tcpflags & TH_RST)?"R":""), ((tcpflags & TH_PUSH)?"P":""),\ - ((tcpflags & TH_ACK)?"A":""), ((tcpflags & TH_URG)?"U":""),\ - ((!tcpflags)?"none":""), ((!tcpflags_f)?" (default)":"")); - - printf("Window: %u%s\tURG Pointer: %u%s\n", tcpwin, (tcpwin_f?"":" (randomized)"), \ - tcpurg, (tcpurg_f?"":" (default)")); - } - - else if(rhudp_f && idata->dstaddr_f){ - if(targetporth_f){ - printf("Source Port: %u-%u\t", targetportl, targetporth); - } - else{ - printf("Source Port: %u%s\t", targetportl, (targetportl_f?"":" (randomized)")); - - } - - if(peerporth_f){ - printf("Destination Port: %u-%u\n", peerportl, peerporth); - } - else{ - printf("Destination Port: %u%s\n", peerportl, (peerportl_f?"":" (randomized)")); - - } - } - - else if(rhicmp6_f && idata->dstaddr_f){ - printf("Identifier: %u%s\tSequence Number: %u%s\n", icmp6id, (icmp6id_f?"":" (randomized)"), \ - icmp6seq, (icmp6seq_f?"":" (randomized)")); - } -} +void print_attack_info(struct iface_data *idata) { + puts("icmp6: Security assessment tool for attack vectors based on ICMPv6 messages\n"); + + if (idata->type == DLT_EN10MB && !(idata->flags & IFACE_LOOPBACK)) { + if (ether_ntop(&(idata->hsrcaddr), plinkaddr, sizeof(plinkaddr)) == 0) { + puts("ether_ntop(): Error converting address"); + exit(EXIT_FAILURE); + } + + printf("Ethernet Source Address: %s%s\n", plinkaddr, ((!idata->hsrcaddr_f) ? " (randomized)" : "")); + + /* + Ethernet Destination Address only used if a IPv6 Destination Address or an + Ethernet Destination Address were specified. + */ + if (idata->dstaddr_f) { + if (ether_ntop(&(idata->hdstaddr), plinkaddr, sizeof(plinkaddr)) == 0) { + puts("ether_ntop(): Error converting address"); + exit(EXIT_FAILURE); + } + + printf("Ethernet Destination Address: %s%s\n", plinkaddr, + ((!idata->hdstaddr_f) ? " (automatically selected)" : "")); + } + } + + if (idata->srcaddr_f) { + if (inet_ntop(AF_INET6, &(idata->srcaddr), psrcaddr, sizeof(psrcaddr)) == NULL) { + puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); + exit(EXIT_FAILURE); + } + + /* XXX Should really differentate between 'automatically selected' and 'randomized' */ + printf("IPv6 Source Address: %s%s\n", psrcaddr, + ((idata->srcaddr_f != TRUE) ? " (automatically selected)" : "")); + } + + if (idata->dstaddr_f) { + if (inet_ntop(AF_INET6, &(idata->dstaddr), pdstaddr, sizeof(pdstaddr)) == NULL) { + puts("inet_ntop(): Error converting IPv6 Destination Address to presentation format"); + exit(EXIT_FAILURE); + } + + printf("IPv6 Destination Address: %s\n", pdstaddr); + } + + printf("IPv6 Hop Limit: %u%s\n", hoplimit, (hoplimit_f) ? "" : " (randomized)"); + + for (i = 0; i < ndstoptuhdr; i++) + printf("Destination Options Header (Unfragmentable part): %u bytes\n", dstoptuhdrlen[i]); + + for (i = 0; i < nhbhopthdr; i++) + printf("Hop by Hop Options Header: %u bytes\n", hbhopthdrlen[i]); + + for (i = 0; i < ndstopthdr; i++) + printf("Destination Options Header: %u bytes\n", dstopthdrlen[i]); + + if (fragh_f) + printf("Sending each packet in fragments of %u bytes (plus the Unfragmentable part)\n", nfrags); + + switch (icmp6type) { + case ICMP6_DST_UNREACH: + printf("ICMPv6 Destination Unreachable (Type %u)", icmp6type); + switch (icmp6code) { + case ICMP6_DST_UNREACH_NOROUTE: + printf(", No route to destination (Code %u)\n", icmp6code); + break; + case ICMP6_DST_UNREACH_ADMIN: + printf(", Communication administratively prohibited (Code %u)\n", icmp6code); + break; + + case ICMP6_DST_UNREACH_BEYONDSCOPE: + printf(", Beyond scope of source address (Code %u)\n", icmp6code); + break; + + case ICMP6_DST_UNREACH_ADDR: + printf(", Address Unreachable (Code %u)\n", icmp6code); + break; + + case ICMP6_DST_UNREACH_NOPORT: + printf(", Port Unreachable (Code %u)\n", icmp6code); + break; + + case ICMP6_DST_UNREACH_FAILEDPOLICY: + printf(", Source address failed ingress/egress policy (Code %u)\n", icmp6code); + break; + + case ICMP6_DST_UNREACH_REJECTROUTE: + printf(", Reject route to destination (Code %u)\n", icmp6code); + break; + + default: + printf(", Unknown ICMPv6 code (Code %u)\n", icmp6code); + break; + } + break; + + case ICMP6_PACKET_TOO_BIG: + printf("ICMPv6 Packet Too Big (Type %u)", icmp6type); + + switch (icmp6code) { + case 0: + printf(", Code 0\n"); + printf("Next-Hop MTU: %u\n", mtu); + break; + + default: + printf(", Unknown ICMPv6 code (Code %u)\n", icmp6code); + break; + } + break; + + case ICMP6_PARAM_PROB: + printf("ICMPv6 Parameter Problem (Type %u)", icmp6type); + + switch (icmp6code) { + case ICMP6_PARAMPROB_HEADER: + printf(", Erroneous header field (Code %u)\n", icmp6code); + break; + + case ICMP6_PARAMPROB_NEXTHEADER: + printf(", Unrecognized Next Header (Code %u)\n", icmp6code); + break; + + case ICMP6_PARAMPROB_OPTION: + printf(", Unrecognized IPv6 option (Code %u)\n)", icmp6code); + break; + + default: + printf(", Unknown ICMPv6 code (Code %u)\n", icmp6code); + break; + } + break; + + case ICMP6_TIME_EXCEEDED: + printf("ICMPv6 Time Exceeded (Type %u)", icmp6type); + + switch (icmp6code) { + case ICMP6_TIME_EXCEED_TRANSIT: + printf(", Hop Limit exceeded in transit (Code %u)\n", icmp6code); + break; + + case ICMP6_TIME_EXCEED_REASSEMBLY: + printf(", Fragment reassembly time exceeded (Code %u)\n", icmp6code); + break; + + default: + printf(", Unknown ICMPv6 code (Code %u)\n", icmp6code); + break; + } + + break; + + default: + printf("Unknown ICMPv6 Type/Code (Type=%u, Code %u)\n", icmp6type, icmp6code); + break; + } + + if ((rhtcp_f || rhdefault_f) && idata->dstaddr_f) { + printf("Payload Type: IPv6/TCP%s\n", (rhdefault_f ? " (default)" : "")); + } + else if (rhudp_f && idata->dstaddr_f) { + puts("Payload Type: IPv6/UDP"); + } + else if (rhicmp6_f && idata->dstaddr_f) { + puts("Payload Type: IPv6/ICMPv6 Echo Request"); + } + + if (inet_ntop(AF_INET6, &targetaddr, pv6addr, sizeof(pv6addr)) == NULL) { + puts("inet_ntop(): Error converting Redirected Address to presentation format"); + exit(EXIT_FAILURE); + } + + if (idata->srcaddr_f) { + printf("Source Address: %s%s\n", pv6addr, ((!targetaddr_f) ? " (automatically-selected)" : "")); + } + + if (inet_ntop(AF_INET6, &peeraddr, pv6addr, sizeof(pv6addr)) == NULL) { + puts("inet_ntop(): Error converting Redirect Target Address to presentation format"); + exit(EXIT_FAILURE); + } + + if (idata->dstaddr_f) { + printf("Destination Address: %s%s\n", pv6addr, ((!peeraddr_f) ? " (randomized)" : "")); + } + + printf("Hop Limit: %u%s\n", ip6hoplimit, (ip6hoplimit_f) ? "" : " (randomized)"); + + if ((rhtcp_f || rhdefault_f) && idata->dstaddr_f) { + if (targetporth_f) { + printf("Source Port: %u-%u\t", targetportl, targetporth); + } + else { + printf("Source Port: %u%s\t", targetportl, (targetportl_f ? "" : " (randomized)")); + } + + if (peerporth_f) { + printf("Destination Port: %u-%u\t", peerportl, peerporth); + } + else { + printf("Destination Port: %u%s\n", peerportl, (peerportl_f ? "" : " (randomized)")); + } + + printf("SEQ Number: %u%s\tACK Number: %u%s\n", tcpseq, (tcpseq_f ? "" : " (randomized)"), tcpack, + (tcpack_f ? "" : " (randomized)")); + + printf("Flags: %s%s%s%s%s%s%s%s\t", ((tcpflags & TH_FIN) ? "F" : ""), ((tcpflags & TH_SYN) ? "S" : ""), + ((tcpflags & TH_RST) ? "R" : ""), ((tcpflags & TH_PUSH) ? "P" : ""), ((tcpflags & TH_ACK) ? "A" : ""), + ((tcpflags & TH_URG) ? "U" : ""), ((!tcpflags) ? "none" : ""), ((!tcpflags_f) ? " (default)" : "")); + + printf("Window: %u%s\tURG Pointer: %u%s\n", tcpwin, (tcpwin_f ? "" : " (randomized)"), tcpurg, + (tcpurg_f ? "" : " (default)")); + } + + else if (rhudp_f && idata->dstaddr_f) { + if (targetporth_f) { + printf("Source Port: %u-%u\t", targetportl, targetporth); + } + else { + printf("Source Port: %u%s\t", targetportl, (targetportl_f ? "" : " (randomized)")); + } + + if (peerporth_f) { + printf("Destination Port: %u-%u\n", peerportl, peerporth); + } + else { + printf("Destination Port: %u%s\n", peerportl, (peerportl_f ? "" : " (randomized)")); + } + } + + else if (rhicmp6_f && idata->dstaddr_f) { + printf("Identifier: %u%s\tSequence Number: %u%s\n", icmp6id, (icmp6id_f ? "" : " (randomized)"), icmp6seq, + (icmp6seq_f ? "" : " (randomized)")); + } +} diff --git a/tools/icmp6.h b/tools/icmp6.h index 5f9740c..9fd4667 100644 --- a/tools/icmp6.h +++ b/tools/icmp6.h @@ -2,5 +2,3 @@ * Header file for the icmp6 tool * */ - - diff --git a/tools/ipv6toolkit.h b/tools/ipv6toolkit.h index bb95e13..3e2afaa 100644 --- a/tools/ipv6toolkit.h +++ b/tools/ipv6toolkit.h @@ -1,4 +1,3 @@ #define SI6_TOOLKIT "SI6 Networks' IPv6 Toolkit (current)" -#define MAX_CMDLINE_OPT_LEN 40 -#define DATE_STR_LEN 40 - +#define MAX_CMDLINE_OPT_LEN 40 +#define DATE_STR_LEN 40 diff --git a/tools/jumbo6.c b/tools/jumbo6.c index 63ff324..3bf551a 100644 --- a/tools/jumbo6.c +++ b/tools/jumbo6.c @@ -18,1212 +18,1184 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . - * + * * Build with: make jumbo6 - * + * * The libpcap library must be previously installed on your system. * * Please send any bug reports to Fernando Gont */ -#include #include -#include #include +#include +#include -#include #include -#include -#include -#include #include #include +#include +#include +#include +#include #include -#include -#include -#include #include -#include #include -#include +#include +#include #include +#include +#include #include -#include +#include +#include +#include "ipv6toolkit.h" #include "jumbo6.h" #include "libipv6.h" -#include "ipv6toolkit.h" - /* Function prototypes */ -void init_packet_data(struct iface_data *); -int send_packet(struct iface_data *, struct pcap_pkthdr *, const u_char *); -void print_icmp6_echo(struct iface_data *, struct pcap_pkthdr *, const u_char *); -void print_icmp6_error(struct iface_data *, struct pcap_pkthdr *, const u_char *); -void print_attack_info(struct iface_data *); -void usage(void); -void print_help(void); -int valid_icmp6_response(struct iface_data *, struct pcap_pkthdr *, const u_char *); - +void init_packet_data(struct iface_data *); +int send_packet(struct iface_data *, struct pcap_pkthdr *, const u_char *); +void print_icmp6_echo(struct iface_data *, struct pcap_pkthdr *, const u_char *); +void print_icmp6_error(struct iface_data *, struct pcap_pkthdr *, const u_char *); +void print_attack_info(struct iface_data *); +void usage(void); +void print_help(void); +int valid_icmp6_response(struct iface_data *, struct pcap_pkthdr *, const u_char *); /* Data structures for packets read from the wire */ -struct pcap_pkthdr *pkthdr; -const u_char *pktdata; -unsigned char *pkt_end; -struct ether_header *pkt_ether; -struct ip6_hdr *pkt_ipv6; -struct icmp6_hdr *pkt_icmp6; +struct pcap_pkthdr *pkthdr; +const u_char *pktdata; +unsigned char *pkt_end; +struct ether_header *pkt_ether; +struct ip6_hdr *pkt_ipv6; +struct icmp6_hdr *pkt_icmp6; struct nd_neighbor_solicit *pkt_ns; -struct in6_addr *pkt_ipv6addr; -unsigned int pktbytes; - -bpf_u_int32 my_netmask; -bpf_u_int32 my_ip; -struct bpf_program pcap_filter; -char dev[64], errbuf[PCAP_ERRBUF_SIZE]; -unsigned char buffer[65556], buffrh[MIN_IPV6_HLEN + MIN_TCP_HLEN]; -unsigned char *v6buffer, *ptr, *startofprefixes; -char *pref; - -struct ip6_hdr *ipv6; -struct icmp6_hdr *icmp6; - -struct ether_header *ethernet; -struct nd_opt_tlla *tllaopt; - -struct in6_addr targetaddr; -struct ether_addr linkaddr[MAX_TLLA_OPTION]; -unsigned int nlinkaddr=0, linkaddrs; - -char *lasts, *rpref; -char *charptr; - -int nw; -unsigned long ul_res, ul_val; -unsigned int i, j, startrand; -unsigned int skip; -unsigned int sources, nsources, ports, nports, nsleep; - -uint16_t mask, ip6length; -uint32_t jplength, *jplengthptr, *fjplengthptr, icmp6psize; -uint8_t hoplimit; - -char plinkaddr[ETHER_ADDR_PLEN]; -char psrcaddr[INET6_ADDRSTRLEN], pdstaddr[INET6_ADDRSTRLEN], pv6addr[INET6_ADDRSTRLEN]; -unsigned char floodt_f=0; -unsigned char listen_f=0, accepted_f=0, loop_f=0, sleep_f=0, localaddr_f=0; -unsigned char hoplimit_f=0, ip6length_f=0, jplength_f=0, icmp6psize_f=0; - +struct in6_addr *pkt_ipv6addr; +unsigned int pktbytes; + +bpf_u_int32 my_netmask; +bpf_u_int32 my_ip; +struct bpf_program pcap_filter; +char dev[64], errbuf[PCAP_ERRBUF_SIZE]; +unsigned char buffer[65556], buffrh[MIN_IPV6_HLEN + MIN_TCP_HLEN]; +unsigned char *v6buffer, *ptr, *startofprefixes; +char *pref; + +struct ip6_hdr *ipv6; +struct icmp6_hdr *icmp6; + +struct ether_header *ethernet; +struct nd_opt_tlla *tllaopt; + +struct in6_addr targetaddr; +struct ether_addr linkaddr[MAX_TLLA_OPTION]; +unsigned int nlinkaddr = 0, linkaddrs; + +char *lasts, *rpref; +char *charptr; + +int nw; +unsigned long ul_res, ul_val; +unsigned int i, j, startrand; +unsigned int skip; +unsigned int sources, nsources, ports, nports, nsleep; + +uint16_t mask, ip6length; +uint32_t jplength, *jplengthptr, *fjplengthptr, icmp6psize; +uint8_t hoplimit; + +char plinkaddr[ETHER_ADDR_PLEN]; +char psrcaddr[INET6_ADDRSTRLEN], pdstaddr[INET6_ADDRSTRLEN], pv6addr[INET6_ADDRSTRLEN]; +unsigned char floodt_f = 0; +unsigned char listen_f = 0, accepted_f = 0, loop_f = 0, sleep_f = 0, localaddr_f = 0; +unsigned char hoplimit_f = 0, ip6length_f = 0, jplength_f = 0, icmp6psize_f = 0; /* Support for Extension Headers */ -unsigned int dstopthdrs, dstoptuhdrs, hbhopthdrs; -char hbhopthdr_f=0, dstoptuhdr_f=0, dstopthdr_f=0; -unsigned char *dstopthdr[MAX_DST_OPT_HDR], *dstoptuhdr[MAX_DST_OPT_U_HDR]; -unsigned char *hbhopthdr[MAX_HBH_OPT_HDR]; -unsigned int dstopthdrlen[MAX_DST_OPT_HDR], dstoptuhdrlen[MAX_DST_OPT_U_HDR]; -unsigned int hbhopthdrlen[MAX_HBH_OPT_HDR], m, pad; - -struct ip6_frag fraghdr, *fh; -struct ip6_hdr *fipv6; -unsigned char fragh_f=0; -unsigned char fragbuffer[ETHER_HDR_LEN+MIN_IPV6_HLEN+MAX_IPV6_PAYLOAD]; -unsigned char *fragpart, *fptr, *fptrend, *ptrend, *ptrhdr, *ptrhdrend; -unsigned int hdrlen, ndstopthdr=0, nhbhopthdr=0, ndstoptuhdr=0; -unsigned int nfrags, fragsize; -unsigned char *prev_nh, *startoffragment; - -struct iface_data idata; - -int main(int argc, char **argv){ - extern char *optarg; - char *endptr; /* Used by strtoul() */ - fd_set sset, rset; - struct timeval timeout; - struct target_ipv6 targetipv6; - int r, sel; - time_t curtime, start, lastecho=0; - - static struct option longopts[] = { - {"interface", required_argument, 0, 'i'}, - {"link-src-addr", required_argument, 0, 'S'}, - {"link-dst-addr", required_argument, 0, 'D'}, - {"src-addr", required_argument, 0, 's'}, - {"dst-addr", required_argument, 0, 'd'}, - {"hop-limit", required_argument, 0, 'A'}, - {"dst-opt-hdr", required_argument, 0, 'u'}, - {"dst-opt-u-hdr", required_argument, 0, 'U'}, - {"hbh-opt-hdr", required_argument, 0, 'H'}, - {"frag-hdr", required_argument, 0, 'y'}, - {"ipv6-length", required_argument, 0, 'q'}, - {"jumbo-length", required_argument, 0, 'Q'}, - {"payload-size", required_argument, 0, 'P'}, - {"loop", no_argument, 0, 'l'}, - {"sleep", required_argument, 0, 'z'}, - {"listen", no_argument, 0, 'L'}, - {"verbose", no_argument, 0, 'v'}, - {"help", no_argument, 0, 'h'}, - {0, 0, 0, 0 } - }; - - char shortopts[]= "i:s:d:A:u:U:H:y:S:D:q:Q:P:lz:Lvh"; - - char option; - - if(argc<=1){ - usage(); - exit(EXIT_FAILURE); - } - - hoplimit=64+random()%180; - init_iface_data(&idata); - - while((r=getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { - option= r; - - switch(option) { - case 'i': /* Interface */ - strncpy(idata.iface, optarg, IFACE_LENGTH-1); - idata.iface[IFACE_LENGTH-1]=0; - idata.ifindex= if_nametoindex(idata.iface); - idata.iface_f=TRUE; - break; - - case 's': /* IPv6 Source Address */ - if(idata.srcaddr_f){ - puts("Error: Multiple '-s' options have been specified"); - exit(EXIT_FAILURE); - } - - if((charptr = strtok_r(optarg, "/", &lasts)) == NULL){ - puts("Error in Source Address"); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, charptr, &(idata.srcaddr)) <= 0){ - puts("inet_pton(): Source Address not valid"); - exit(EXIT_FAILURE); - } - - idata.srcaddr_f = 1; - - if((charptr = strtok_r(NULL, " ", &lasts)) != NULL){ - idata.srcpreflen = atoi(charptr); - - if(idata.srcpreflen>128){ - puts("Prefix length error in IPv6 Source Address"); - exit(EXIT_FAILURE); - } - - sanitize_ipv6_prefix(&(idata.srcaddr), idata.srcpreflen); - idata.srcprefix_f=1; - } - - break; - - case 'd': /* IPv6 Destination Address */ - strncpy( targetipv6.name, optarg, NI_MAXHOST); - targetipv6.name[NI_MAXHOST-1]= 0; - targetipv6.flags= AI_CANONNAME; - - if( (r=get_ipv6_target(&targetipv6)) != 0){ - - if(r < 0){ - printf("Unknown Destination: %s\n", gai_strerror(targetipv6.res)); - } - else{ - puts("Unknown Destination: No IPv6 address found for specified destination"); - } - - exit(EXIT_FAILURE); - } - - idata.dstaddr= targetipv6.ip6; - idata.dstaddr_f = 1; - break; - - case 'A': /* Hop Limit */ - hoplimit= atoi(optarg); - hoplimit_f=1; - break; - - case 'u': /* Destinations Options Header */ - if(ndstopthdr >= MAX_DST_OPT_HDR){ - puts("Too many Destination Options Headers"); - exit(EXIT_FAILURE); - } - - hdrlen= atoi(optarg); - - if(hdrlen < 8){ - puts("Bad length in Destination Options Header"); - exit(EXIT_FAILURE); - } - - hdrlen = ((hdrlen+7)/8) * 8; - dstopthdrlen[ndstopthdr]= hdrlen; - - if( (dstopthdr[ndstopthdr]= malloc(hdrlen)) == NULL){ - puts("Not enough memory for Destination Options Header"); - exit(EXIT_FAILURE); - } - - ptrhdr= dstopthdr[ndstopthdr] + 2; - ptrhdrend= dstopthdr[ndstopthdr] + hdrlen; - - while( ptrhdr < ptrhdrend){ - - if( (ptrhdrend-ptrhdr)>257) - pad= 257; - else - pad= ptrhdrend-ptrhdr; - - if(!insert_pad_opt(ptrhdr, ptrhdrend, pad)){ - puts("Destination Options Header Too Big"); - exit(EXIT_FAILURE); - } - - ptrhdr= ptrhdr + pad; - } - - *(dstopthdr[ndstopthdr]+1)= (hdrlen/8)-1; - ndstopthdr++; - dstopthdr_f=1; - break; - - case 'U': /* Destination Options Header (Unfragmentable Part) */ - if(ndstoptuhdr >= MAX_DST_OPT_U_HDR){ - puts("Too many Destination Options Headers (Unfragmentable Part)"); - exit(EXIT_FAILURE); - } - - hdrlen= atoi(optarg); - - if(hdrlen < 8){ - puts("Bad length in Destination Options Header (Unfragmentable Part)"); - exit(EXIT_FAILURE); - } - - hdrlen = ((hdrlen+7)/8) * 8; - dstoptuhdrlen[ndstoptuhdr]= hdrlen; - - if( (dstoptuhdr[ndstoptuhdr]= malloc(hdrlen)) == NULL){ - puts("Not enough memory for Destination Options Header (Unfragmentable Part)"); - exit(EXIT_FAILURE); - } - - ptrhdr= dstoptuhdr[ndstoptuhdr]+2; - ptrhdrend= dstoptuhdr[ndstoptuhdr] + hdrlen; - - while( ptrhdr < ptrhdrend){ - - if( (ptrhdrend-ptrhdr)>257) - pad= 257; - else - pad= ptrhdrend-ptrhdr; - - if(!insert_pad_opt(ptrhdr, ptrhdrend, pad)){ - puts("Destination Options Header (Unfragmentable Part) Too Big"); - exit(EXIT_FAILURE); - } - - ptrhdr = ptrhdr + pad; - } - - *(dstoptuhdr[ndstoptuhdr]+1)= (hdrlen/8) - 1; - ndstoptuhdr++; - dstoptuhdr_f=1; - break; - - case 'H': /* Hop-by-Hop Options Header */ - if(nhbhopthdr >= MAX_HBH_OPT_HDR){ - puts("Too many Hop-by-Hop Options Headers"); - exit(EXIT_FAILURE); - } - - hdrlen= atoi(optarg); - - if(hdrlen < 8){ - puts("Bad length in Hop-by-Hop Options Header"); - exit(EXIT_FAILURE); - } - - hdrlen = ((hdrlen+7)/8) * 8; - hbhopthdrlen[nhbhopthdr]= hdrlen; - - if( (hbhopthdr[nhbhopthdr]= malloc(hdrlen)) == NULL){ - puts("Not enough memory for Hop-by-Hop Options Header"); - exit(EXIT_FAILURE); - } - - ptrhdr= hbhopthdr[nhbhopthdr] + 2; - ptrhdrend= hbhopthdr[nhbhopthdr] + hdrlen; - - - while( ptrhdr < ptrhdrend){ - - if( (ptrhdrend-ptrhdr)>257) - pad= 257; - else - pad= ptrhdrend-ptrhdr; - - if(!insert_pad_opt(ptrhdr, ptrhdrend, pad)){ - puts("Hop-by-Hop Options Header Too Big"); - exit(EXIT_FAILURE); - } - - ptrhdr = ptrhdr + pad; - } - - *(hbhopthdr[nhbhopthdr]+1)= (hdrlen/8) - 1; - nhbhopthdr++; - hbhopthdr_f=1; - break; - - case 'y': /* Fragment header */ - nfrags= atoi(optarg); - if(nfrags < 8){ - puts("Error in Fragmentation option: Fragment Size must be at least 8 bytes"); - exit(EXIT_FAILURE); - } - - fragh_f= 1; - break; - - case 'S': /* Source Ethernet address */ - if(ether_pton(optarg, &(idata.hsrcaddr), sizeof(idata.hsrcaddr)) == 0){ - puts("Error in Source link-layer address."); - exit(EXIT_FAILURE); - } - - idata.hsrcaddr_f = 1; - break; - - case 'D': /* Destination Ethernet Address */ - if(ether_pton(optarg, &(idata.hdstaddr), sizeof(idata.hdstaddr)) == 0){ - puts("Error in Source link-layer address."); - exit(EXIT_FAILURE); - } - - idata.hdstaddr_f = 1; - break; - - case 'P': /* Payload Size*/ - icmp6psize= atoi(optarg); - icmp6psize= (icmp6psize<<2) >> 2; /* The Redirected Header has a granularity of 8 bytes */ - icmp6psize_f= 1; - break; - - case 'q': /* IPv6 Payload Length */ - if((ul_res = strtoul(optarg, &endptr, 0)) == ULONG_MAX){ - perror("Error in 'TCP Sequence NUmber' parameter"); - exit(EXIT_FAILURE); - } - - if(endptr != optarg){ - ip6length = ul_res; - ip6length_f=1; - } - break; - - case 'Q': /* Jumbo Payload Length */ - if((ul_res = strtoul(optarg, &endptr, 0)) == ULONG_MAX){ - perror("Error in 'TCP Sequence NUmber' parameter"); - exit(EXIT_FAILURE); - } - - if(endptr != optarg){ - jplength = ul_res; - jplength_f=1; - } - - break; - - case 'l': /* "Loop mode */ - loop_f = 1; - break; - - case 'z': /* Sleep option */ - nsleep=atoi(optarg); - if(nsleep==0){ - puts("Invalid number of seconds in '-z' option"); - exit(EXIT_FAILURE); - } - - sleep_f=1; - break; - - case 'L': /* "Listen mode */ - listen_f = 1; - break; - - case 'v': /* Be verbose */ - idata.verbose_f++; - break; - - case 'h': /* Help */ - print_help(); - - exit(EXIT_FAILURE); - break; - - default: - usage(); - exit(EXIT_FAILURE); - break; - - } /* switch */ - } /* while(getopt) */ - - if(geteuid()) { - puts("jumbo6 needs root privileges to run."); - exit(EXIT_FAILURE); - } - - if(!idata.iface_f){ - if(idata.dstaddr_f && IN6_IS_ADDR_LINKLOCAL(&(idata.dstaddr))){ - puts("Must specify a network interface for link-local destinations"); - exit(EXIT_FAILURE); - } - else if(idata.listen_f){ - puts("Must specify a network interface when employing the 'listenging' mode"); - exit(EXIT_FAILURE); - } - } - - if(listen_f && loop_f){ - puts("'Error: listen' mode and 'loop' mode are incompatible"); - exit(EXIT_FAILURE); - } - - if(!idata.dstaddr_f && !listen_f){ /* Must specify IPv6 Destination Address if listening mode not used */ - puts("IPv6 Destination Address not specified (and listening mode not selected)"); - exit(EXIT_FAILURE); - } - - if(load_dst_and_pcap(&idata, LOAD_SRC_NXT_HOP) == FAILURE){ - puts("Error while learning Source Address and Next Hop"); - exit(EXIT_FAILURE); - } - - release_privileges(); - - srandom(time(NULL)); - - if((idata.ip6_local_flag && idata.ip6_global_flag) && !idata.srcaddr_f) - localaddr_f=1; - - if(!idata.ether_flag){ - randomize_ether_addr(&idata.ether); - idata.ether_flag=1; - } - - if(!idata.ip6_local_flag){ - ether_to_ipv6_linklocal(&idata.ether, &idata.ip6_local); - } - - if(!sleep_f) - nsleep=QUERY_TIMEOUT; - - if( !fragh_f && dstoptuhdr_f){ - puts("Dst. Options Header (Unfragmentable Part) set, but Fragmentation not specified"); - exit(EXIT_FAILURE); - } - - if(idata.verbose_f){ - print_attack_info(&idata); - } - - /* - Set filter for receiving Neighbor Solicitations, ICMPv6 Echo Responses, and ICMPv6 Parameter Problem - */ - if(pcap_compile(idata.pfd, &pcap_filter, PCAP_ICMPV6_NS_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1){ - printf("pcap_compile(): %s", pcap_geterr(idata.pfd)); - exit(EXIT_FAILURE); - } - - if(pcap_setfilter(idata.pfd, &pcap_filter) == -1){ - printf("pcap_setfilter(): %s", pcap_geterr(idata.pfd)); - exit(EXIT_FAILURE); - } - - pcap_freecode(&pcap_filter); - - /* Set initial contents of the attack packet */ - init_packet_data(&idata); - - /* Fire a packet if a IPv6 Destination Address was specified */ - if(idata.dstaddr_f){ - FD_ZERO(&sset); - FD_SET(idata.fd, &sset); - start= time(NULL); - - while(1){ - curtime=time(NULL); - - if(!loop_f && (curtime - start) >= QUERY_TIMEOUT){ - break; - } - - if((curtime - lastecho) >= nsleep){ - lastecho=curtime; - - puts("Sending ICMPv6 Echo Request....\n"); - - if(send_packet(&idata, NULL, NULL) == -1){ - puts("Error sending packet"); - exit(EXIT_FAILURE); - } - } - - rset= sset; +unsigned int dstopthdrs, dstoptuhdrs, hbhopthdrs; +char hbhopthdr_f = 0, dstoptuhdr_f = 0, dstopthdr_f = 0; +unsigned char *dstopthdr[MAX_DST_OPT_HDR], *dstoptuhdr[MAX_DST_OPT_U_HDR]; +unsigned char *hbhopthdr[MAX_HBH_OPT_HDR]; +unsigned int dstopthdrlen[MAX_DST_OPT_HDR], dstoptuhdrlen[MAX_DST_OPT_U_HDR]; +unsigned int hbhopthdrlen[MAX_HBH_OPT_HDR], m, pad; + +struct ip6_frag fraghdr, *fh; +struct ip6_hdr *fipv6; +unsigned char fragh_f = 0; +unsigned char fragbuffer[ETHER_HDR_LEN + MIN_IPV6_HLEN + MAX_IPV6_PAYLOAD]; +unsigned char *fragpart, *fptr, *fptrend, *ptrend, *ptrhdr, *ptrhdrend; +unsigned int hdrlen, ndstopthdr = 0, nhbhopthdr = 0, ndstoptuhdr = 0; +unsigned int nfrags, fragsize; +unsigned char *prev_nh, *startoffragment; + +struct iface_data idata; + +int main(int argc, char **argv) { + extern char *optarg; + char *endptr; /* Used by strtoul() */ + fd_set sset, rset; + struct timeval timeout; + struct target_ipv6 targetipv6; + int r, sel; + time_t curtime, start, lastecho = 0; + + static struct option longopts[] = {{"interface", required_argument, 0, 'i'}, + {"link-src-addr", required_argument, 0, 'S'}, + {"link-dst-addr", required_argument, 0, 'D'}, + {"src-addr", required_argument, 0, 's'}, + {"dst-addr", required_argument, 0, 'd'}, + {"hop-limit", required_argument, 0, 'A'}, + {"dst-opt-hdr", required_argument, 0, 'u'}, + {"dst-opt-u-hdr", required_argument, 0, 'U'}, + {"hbh-opt-hdr", required_argument, 0, 'H'}, + {"frag-hdr", required_argument, 0, 'y'}, + {"ipv6-length", required_argument, 0, 'q'}, + {"jumbo-length", required_argument, 0, 'Q'}, + {"payload-size", required_argument, 0, 'P'}, + {"loop", no_argument, 0, 'l'}, + {"sleep", required_argument, 0, 'z'}, + {"listen", no_argument, 0, 'L'}, + {"verbose", no_argument, 0, 'v'}, + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0}}; + + char shortopts[] = "i:s:d:A:u:U:H:y:S:D:q:Q:P:lz:Lvh"; + + char option; + + if (argc <= 1) { + usage(); + exit(EXIT_FAILURE); + } + + hoplimit = 64 + random() % 180; + init_iface_data(&idata); + + while ((r = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { + option = r; + + switch (option) { + case 'i': /* Interface */ + strncpy(idata.iface, optarg, IFACE_LENGTH - 1); + idata.iface[IFACE_LENGTH - 1] = 0; + idata.ifindex = if_nametoindex(idata.iface); + idata.iface_f = TRUE; + break; + + case 's': /* IPv6 Source Address */ + if (idata.srcaddr_f) { + puts("Error: Multiple '-s' options have been specified"); + exit(EXIT_FAILURE); + } + + if ((charptr = strtok_r(optarg, "/", &lasts)) == NULL) { + puts("Error in Source Address"); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, charptr, &(idata.srcaddr)) <= 0) { + puts("inet_pton(): Source Address not valid"); + exit(EXIT_FAILURE); + } + + idata.srcaddr_f = 1; + + if ((charptr = strtok_r(NULL, " ", &lasts)) != NULL) { + idata.srcpreflen = atoi(charptr); + + if (idata.srcpreflen > 128) { + puts("Prefix length error in IPv6 Source Address"); + exit(EXIT_FAILURE); + } + + sanitize_ipv6_prefix(&(idata.srcaddr), idata.srcpreflen); + idata.srcprefix_f = 1; + } + + break; + + case 'd': /* IPv6 Destination Address */ + strncpy(targetipv6.name, optarg, NI_MAXHOST); + targetipv6.name[NI_MAXHOST - 1] = 0; + targetipv6.flags = AI_CANONNAME; + + if ((r = get_ipv6_target(&targetipv6)) != 0) { + + if (r < 0) { + printf("Unknown Destination: %s\n", gai_strerror(targetipv6.res)); + } + else { + puts("Unknown Destination: No IPv6 address found for specified destination"); + } + + exit(EXIT_FAILURE); + } + + idata.dstaddr = targetipv6.ip6; + idata.dstaddr_f = 1; + break; + + case 'A': /* Hop Limit */ + hoplimit = atoi(optarg); + hoplimit_f = 1; + break; + + case 'u': /* Destinations Options Header */ + if (ndstopthdr >= MAX_DST_OPT_HDR) { + puts("Too many Destination Options Headers"); + exit(EXIT_FAILURE); + } + + hdrlen = atoi(optarg); + + if (hdrlen < 8) { + puts("Bad length in Destination Options Header"); + exit(EXIT_FAILURE); + } + + hdrlen = ((hdrlen + 7) / 8) * 8; + dstopthdrlen[ndstopthdr] = hdrlen; + + if ((dstopthdr[ndstopthdr] = malloc(hdrlen)) == NULL) { + puts("Not enough memory for Destination Options Header"); + exit(EXIT_FAILURE); + } + + ptrhdr = dstopthdr[ndstopthdr] + 2; + ptrhdrend = dstopthdr[ndstopthdr] + hdrlen; + + while (ptrhdr < ptrhdrend) { + + if ((ptrhdrend - ptrhdr) > 257) + pad = 257; + else + pad = ptrhdrend - ptrhdr; + + if (!insert_pad_opt(ptrhdr, ptrhdrend, pad)) { + puts("Destination Options Header Too Big"); + exit(EXIT_FAILURE); + } + + ptrhdr = ptrhdr + pad; + } + + *(dstopthdr[ndstopthdr] + 1) = (hdrlen / 8) - 1; + ndstopthdr++; + dstopthdr_f = 1; + break; + + case 'U': /* Destination Options Header (Unfragmentable Part) */ + if (ndstoptuhdr >= MAX_DST_OPT_U_HDR) { + puts("Too many Destination Options Headers (Unfragmentable Part)"); + exit(EXIT_FAILURE); + } + + hdrlen = atoi(optarg); + + if (hdrlen < 8) { + puts("Bad length in Destination Options Header (Unfragmentable Part)"); + exit(EXIT_FAILURE); + } + + hdrlen = ((hdrlen + 7) / 8) * 8; + dstoptuhdrlen[ndstoptuhdr] = hdrlen; + + if ((dstoptuhdr[ndstoptuhdr] = malloc(hdrlen)) == NULL) { + puts("Not enough memory for Destination Options Header (Unfragmentable Part)"); + exit(EXIT_FAILURE); + } + + ptrhdr = dstoptuhdr[ndstoptuhdr] + 2; + ptrhdrend = dstoptuhdr[ndstoptuhdr] + hdrlen; + + while (ptrhdr < ptrhdrend) { + + if ((ptrhdrend - ptrhdr) > 257) + pad = 257; + else + pad = ptrhdrend - ptrhdr; + + if (!insert_pad_opt(ptrhdr, ptrhdrend, pad)) { + puts("Destination Options Header (Unfragmentable Part) Too Big"); + exit(EXIT_FAILURE); + } + + ptrhdr = ptrhdr + pad; + } + + *(dstoptuhdr[ndstoptuhdr] + 1) = (hdrlen / 8) - 1; + ndstoptuhdr++; + dstoptuhdr_f = 1; + break; + + case 'H': /* Hop-by-Hop Options Header */ + if (nhbhopthdr >= MAX_HBH_OPT_HDR) { + puts("Too many Hop-by-Hop Options Headers"); + exit(EXIT_FAILURE); + } + + hdrlen = atoi(optarg); + + if (hdrlen < 8) { + puts("Bad length in Hop-by-Hop Options Header"); + exit(EXIT_FAILURE); + } + + hdrlen = ((hdrlen + 7) / 8) * 8; + hbhopthdrlen[nhbhopthdr] = hdrlen; + + if ((hbhopthdr[nhbhopthdr] = malloc(hdrlen)) == NULL) { + puts("Not enough memory for Hop-by-Hop Options Header"); + exit(EXIT_FAILURE); + } + + ptrhdr = hbhopthdr[nhbhopthdr] + 2; + ptrhdrend = hbhopthdr[nhbhopthdr] + hdrlen; + + while (ptrhdr < ptrhdrend) { + + if ((ptrhdrend - ptrhdr) > 257) + pad = 257; + else + pad = ptrhdrend - ptrhdr; + + if (!insert_pad_opt(ptrhdr, ptrhdrend, pad)) { + puts("Hop-by-Hop Options Header Too Big"); + exit(EXIT_FAILURE); + } + + ptrhdr = ptrhdr + pad; + } + + *(hbhopthdr[nhbhopthdr] + 1) = (hdrlen / 8) - 1; + nhbhopthdr++; + hbhopthdr_f = 1; + break; + + case 'y': /* Fragment header */ + nfrags = atoi(optarg); + if (nfrags < 8) { + puts("Error in Fragmentation option: Fragment Size must be at least 8 bytes"); + exit(EXIT_FAILURE); + } + + fragh_f = 1; + break; + + case 'S': /* Source Ethernet address */ + if (ether_pton(optarg, &(idata.hsrcaddr), sizeof(idata.hsrcaddr)) == 0) { + puts("Error in Source link-layer address."); + exit(EXIT_FAILURE); + } + + idata.hsrcaddr_f = 1; + break; + + case 'D': /* Destination Ethernet Address */ + if (ether_pton(optarg, &(idata.hdstaddr), sizeof(idata.hdstaddr)) == 0) { + puts("Error in Source link-layer address."); + exit(EXIT_FAILURE); + } + + idata.hdstaddr_f = 1; + break; + + case 'P': /* Payload Size*/ + icmp6psize = atoi(optarg); + icmp6psize = (icmp6psize << 2) >> 2; /* The Redirected Header has a granularity of 8 bytes */ + icmp6psize_f = 1; + break; + + case 'q': /* IPv6 Payload Length */ + if ((ul_res = strtoul(optarg, &endptr, 0)) == ULONG_MAX) { + perror("Error in 'TCP Sequence NUmber' parameter"); + exit(EXIT_FAILURE); + } + + if (endptr != optarg) { + ip6length = ul_res; + ip6length_f = 1; + } + break; + + case 'Q': /* Jumbo Payload Length */ + if ((ul_res = strtoul(optarg, &endptr, 0)) == ULONG_MAX) { + perror("Error in 'TCP Sequence NUmber' parameter"); + exit(EXIT_FAILURE); + } + + if (endptr != optarg) { + jplength = ul_res; + jplength_f = 1; + } + + break; + + case 'l': /* "Loop mode */ + loop_f = 1; + break; + + case 'z': /* Sleep option */ + nsleep = atoi(optarg); + if (nsleep == 0) { + puts("Invalid number of seconds in '-z' option"); + exit(EXIT_FAILURE); + } + + sleep_f = 1; + break; + + case 'L': /* "Listen mode */ + listen_f = 1; + break; + + case 'v': /* Be verbose */ + idata.verbose_f++; + break; + + case 'h': /* Help */ + print_help(); + + exit(EXIT_FAILURE); + break; + + default: + usage(); + exit(EXIT_FAILURE); + break; + + } /* switch */ + } /* while(getopt) */ + + if (geteuid()) { + puts("jumbo6 needs root privileges to run."); + exit(EXIT_FAILURE); + } + + if (!idata.iface_f) { + if (idata.dstaddr_f && IN6_IS_ADDR_LINKLOCAL(&(idata.dstaddr))) { + puts("Must specify a network interface for link-local destinations"); + exit(EXIT_FAILURE); + } + else if (idata.listen_f) { + puts("Must specify a network interface when employing the 'listenging' mode"); + exit(EXIT_FAILURE); + } + } + + if (listen_f && loop_f) { + puts("'Error: listen' mode and 'loop' mode are incompatible"); + exit(EXIT_FAILURE); + } + + if (!idata.dstaddr_f && !listen_f) { /* Must specify IPv6 Destination Address if listening mode not used */ + puts("IPv6 Destination Address not specified (and listening mode not selected)"); + exit(EXIT_FAILURE); + } + + if (load_dst_and_pcap(&idata, LOAD_SRC_NXT_HOP) == FAILURE) { + puts("Error while learning Source Address and Next Hop"); + exit(EXIT_FAILURE); + } + + release_privileges(); + + srandom(time(NULL)); + + if ((idata.ip6_local_flag && idata.ip6_global_flag) && !idata.srcaddr_f) + localaddr_f = 1; + + if (!idata.ether_flag) { + randomize_ether_addr(&idata.ether); + idata.ether_flag = 1; + } + + if (!idata.ip6_local_flag) { + ether_to_ipv6_linklocal(&idata.ether, &idata.ip6_local); + } + + if (!sleep_f) + nsleep = QUERY_TIMEOUT; + + if (!fragh_f && dstoptuhdr_f) { + puts("Dst. Options Header (Unfragmentable Part) set, but Fragmentation not specified"); + exit(EXIT_FAILURE); + } + + if (idata.verbose_f) { + print_attack_info(&idata); + } + + /* + Set filter for receiving Neighbor Solicitations, ICMPv6 Echo Responses, and ICMPv6 Parameter Problem + */ + if (pcap_compile(idata.pfd, &pcap_filter, PCAP_ICMPV6_NS_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1) { + printf("pcap_compile(): %s", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } + + if (pcap_setfilter(idata.pfd, &pcap_filter) == -1) { + printf("pcap_setfilter(): %s", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } + + pcap_freecode(&pcap_filter); + + /* Set initial contents of the attack packet */ + init_packet_data(&idata); + + /* Fire a packet if a IPv6 Destination Address was specified */ + if (idata.dstaddr_f) { + FD_ZERO(&sset); + FD_SET(idata.fd, &sset); + start = time(NULL); + + while (1) { + curtime = time(NULL); + + if (!loop_f && (curtime - start) >= QUERY_TIMEOUT) { + break; + } + + if ((curtime - lastecho) >= nsleep) { + lastecho = curtime; + + puts("Sending ICMPv6 Echo Request....\n"); + + if (send_packet(&idata, NULL, NULL) == -1) { + puts("Error sending packet"); + exit(EXIT_FAILURE); + } + } + + rset = sset; #if !defined(sun) && !defined(__sun) - timeout.tv_usec=0; - timeout.tv_sec= nsleep; + timeout.tv_usec = 0; + timeout.tv_sec = nsleep; #else - timeout.tv_usec=10000; - timeout.tv_sec= 0; + timeout.tv_usec = 10000; + timeout.tv_sec = 0; #endif - if((sel=select(idata.fd+1, &rset, NULL, NULL, &timeout)) == -1){ - if(errno == EINTR){ - continue; - } - else{ - puts("Error in select()"); - exit(EXIT_FAILURE); - } - } + if ((sel = select(idata.fd + 1, &rset, NULL, NULL, &timeout)) == -1) { + if (errno == EINTR) { + continue; + } + else { + puts("Error in select()"); + exit(EXIT_FAILURE); + } + } #if defined(sun) || defined(__sun) - if(TRUE){ + if (TRUE) { #else - if(sel && FD_ISSET(idata.fd, &rset)){ + if (sel && FD_ISSET(idata.fd, &rset)) { #endif - /* Read a packet (Echo Reply, Neighbor Solicitation, or ICMPv6 Error */ - if((r=pcap_next_ex(idata.pfd, &pkthdr, &pktdata)) == -1){ - printf("pcap_next_ex(): %s", pcap_geterr(idata.pfd)); - exit(EXIT_FAILURE); - } - else if(r == 1 && pktdata != NULL){ - pkt_ether = (struct ether_header *) pktdata; - pkt_ipv6 = (struct ip6_hdr *)((char *) pkt_ether + ETHER_HDR_LEN); - pkt_icmp6 = (struct icmp6_hdr *) ((char *) pkt_ipv6 + sizeof(struct ip6_hdr)); - pkt_ns= (struct nd_neighbor_solicit *) pkt_icmp6; - pkt_end = (unsigned char *) pktdata + pkthdr->caplen; - - if( (pkt_end - pktdata) < (ETHER_HDR_LEN + MIN_IPV6_HLEN)) - continue; - - if(pkt_ipv6->ip6_nxt == IPPROTO_ICMPV6){ - if(pkt_icmp6->icmp6_type == ND_NEIGHBOR_SOLICIT){ - if( (pkt_end - (unsigned char *) pkt_ns) < sizeof(struct nd_neighbor_solicit)) - continue; - /* - If the addresses that we're using are not actually configured on the local system - (i.e., they are "spoofed", we must check whether it is a Neighbor Solicitation for - one of our addresses, and respond with a Neighbor Advertisement. Otherwise, the kernel - will take care of that. - */ - if(!localaddr_f && is_eq_in6_addr(&(pkt_ns->nd_ns_target), &idata.srcaddr)){ - if(send_neighbor_advert(&idata, idata.pfd, pktdata) == -1){ - puts("Error sending Neighbor Advertisement"); - exit(EXIT_FAILURE); - } - } - } - else if( (pkt_icmp6->icmp6_type == ICMP6_ECHO_REPLY) || (pkt_icmp6->icmp6_type == ICMP6_PARAM_PROB)){ - if( (pkt_end - (unsigned char *) pkt_icmp6) < sizeof(struct icmp6_hdr)) - continue; - /* - Do a preliminar validation check on the ICMPv6 packet (packet size, Source Address, - and Destination Address). - */ - if(!valid_icmp6_response(&idata, pkthdr, pktdata)){ - continue; - } - - switch(pkt_icmp6->icmp6_type){ - case ICMP6_ECHO_REPLY: - print_icmp6_echo(&idata, pkthdr, pktdata); - break; - - case ICMP6_PARAM_PROB: - print_icmp6_error(&idata, pkthdr, pktdata); - break; - } - } - } - } - } - } - - exit(EXIT_SUCCESS); - } - - if(!idata.dstaddr_f){ - puts("Error: Nothing to send! (Destination Address left unspecified)"); - exit(EXIT_FAILURE); - } - - exit(EXIT_SUCCESS); + /* Read a packet (Echo Reply, Neighbor Solicitation, or ICMPv6 Error */ + if ((r = pcap_next_ex(idata.pfd, &pkthdr, &pktdata)) == -1) { + printf("pcap_next_ex(): %s", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } + else if (r == 1 && pktdata != NULL) { + pkt_ether = (struct ether_header *)pktdata; + pkt_ipv6 = (struct ip6_hdr *)((char *)pkt_ether + ETHER_HDR_LEN); + pkt_icmp6 = (struct icmp6_hdr *)((char *)pkt_ipv6 + sizeof(struct ip6_hdr)); + pkt_ns = (struct nd_neighbor_solicit *)pkt_icmp6; + pkt_end = (unsigned char *)pktdata + pkthdr->caplen; + + if ((pkt_end - pktdata) < (ETHER_HDR_LEN + MIN_IPV6_HLEN)) + continue; + + if (pkt_ipv6->ip6_nxt == IPPROTO_ICMPV6) { + if (pkt_icmp6->icmp6_type == ND_NEIGHBOR_SOLICIT) { + if ((pkt_end - (unsigned char *)pkt_ns) < sizeof(struct nd_neighbor_solicit)) + continue; + /* + If the addresses that we're using are not actually configured on the local system + (i.e., they are "spoofed", we must check whether it is a Neighbor Solicitation for + one of our addresses, and respond with a Neighbor Advertisement. Otherwise, the + kernel will take care of that. + */ + if (!localaddr_f && is_eq_in6_addr(&(pkt_ns->nd_ns_target), &idata.srcaddr)) { + if (send_neighbor_advert(&idata, idata.pfd, pktdata) == -1) { + puts("Error sending Neighbor Advertisement"); + exit(EXIT_FAILURE); + } + } + } + else if ((pkt_icmp6->icmp6_type == ICMP6_ECHO_REPLY) || + (pkt_icmp6->icmp6_type == ICMP6_PARAM_PROB)) { + if ((pkt_end - (unsigned char *)pkt_icmp6) < sizeof(struct icmp6_hdr)) + continue; + /* + Do a preliminar validation check on the ICMPv6 packet (packet size, Source Address, + and Destination Address). + */ + if (!valid_icmp6_response(&idata, pkthdr, pktdata)) { + continue; + } + + switch (pkt_icmp6->icmp6_type) { + case ICMP6_ECHO_REPLY: + print_icmp6_echo(&idata, pkthdr, pktdata); + break; + + case ICMP6_PARAM_PROB: + print_icmp6_error(&idata, pkthdr, pktdata); + break; + } + } + } + } + } + } + + exit(EXIT_SUCCESS); + } + + if (!idata.dstaddr_f) { + puts("Error: Nothing to send! (Destination Address left unspecified)"); + exit(EXIT_FAILURE); + } + + exit(EXIT_SUCCESS); } - /* * Function: print_icmp6_info() * * Print information about a received ICMPv6 Echo Response packet */ -void print_icmp6_echo(struct iface_data *idata, struct pcap_pkthdr *pkthdr, const u_char *pktdata){ - struct ip6_hdr *pkt_ipv6; +void print_icmp6_echo(struct iface_data *idata, struct pcap_pkthdr *pkthdr, const u_char *pktdata) { + struct ip6_hdr *pkt_ipv6; - pkt_ipv6 = (struct ip6_hdr *) (pktdata + idata->linkhsize); + pkt_ipv6 = (struct ip6_hdr *)(pktdata + idata->linkhsize); - if(inet_ntop(AF_INET6, &(pkt_ipv6->ip6_src), pv6addr, sizeof(pv6addr)) == NULL){ - puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); - exit(EXIT_FAILURE); - } + if (inet_ntop(AF_INET6, &(pkt_ipv6->ip6_src), pv6addr, sizeof(pv6addr)) == NULL) { + puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); + exit(EXIT_FAILURE); + } - printf("Response from %s\n", pv6addr); + printf("Response from %s\n", pv6addr); } - /* * Function: print_icmp6_error() * * Print information about a received ICMPv6 error message */ -void print_icmp6_error(struct iface_data *idata, struct pcap_pkthdr *pkthdr, const u_char *pktdata){ - struct ip6_hdr *pkt_ipv6; - struct icmp6_hdr *pkt_icmp6; - +void print_icmp6_error(struct iface_data *idata, struct pcap_pkthdr *pkthdr, const u_char *pktdata) { + struct ip6_hdr *pkt_ipv6; + struct icmp6_hdr *pkt_icmp6; - pkt_ipv6 = (struct ip6_hdr *) (pktdata + idata->linkhsize); - pkt_icmp6= (struct icmp6_hdr *) ((unsigned char *) pkt_ipv6 + sizeof(struct ip6_hdr)); + pkt_ipv6 = (struct ip6_hdr *)(pktdata + idata->linkhsize); + pkt_icmp6 = (struct icmp6_hdr *)((unsigned char *)pkt_ipv6 + sizeof(struct ip6_hdr)); - if(inet_ntop(AF_INET6, &(pkt_ipv6->ip6_src), pv6addr, sizeof(pv6addr)) == NULL){ - puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); - exit(EXIT_FAILURE); - } + if (inet_ntop(AF_INET6, &(pkt_ipv6->ip6_src), pv6addr, sizeof(pv6addr)) == NULL) { + puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); + exit(EXIT_FAILURE); + } - printf("Response from %s: ICMPv6 Parameter Problem ", pv6addr); + printf("Response from %s: ICMPv6 Parameter Problem ", pv6addr); - switch(pkt_icmp6->icmp6_code){ - case ICMP6_PARAMPROB_HEADER: - printf("Code 0 (Erroneous Header field), Pointer: %lu\n", (LUI) ntohl(pkt_icmp6->icmp6_pptr)); - break; + switch (pkt_icmp6->icmp6_code) { + case ICMP6_PARAMPROB_HEADER: + printf("Code 0 (Erroneous Header field), Pointer: %lu\n", (LUI)ntohl(pkt_icmp6->icmp6_pptr)); + break; - case ICMP6_PARAMPROB_NEXTHEADER: - printf("Code 1 (Unrecognized Next Header type), Pointer: %lu\n", (LUI) ntohl(pkt_icmp6->icmp6_pptr)); - break; + case ICMP6_PARAMPROB_NEXTHEADER: + printf("Code 1 (Unrecognized Next Header type), Pointer: %lu\n", (LUI)ntohl(pkt_icmp6->icmp6_pptr)); + break; - case ICMP6_PARAMPROB_OPTION: - printf("Unrecognized IPv6 option), Pointer: %lu\n", (LUI) ntohl(pkt_icmp6->icmp6_pptr)); - break; - } + case ICMP6_PARAMPROB_OPTION: + printf("Unrecognized IPv6 option), Pointer: %lu\n", (LUI)ntohl(pkt_icmp6->icmp6_pptr)); + break; + } } - /* * Function: init_packet_data() * * Initialize the contents of the attack packet (Ethernet header, IPv6 Header, and ICMPv6 header) * that are expected to remain constant for the specified attack. */ -void init_packet_data(struct iface_data *idata){ - struct dlt_null *dlt_null; - ethernet= (struct ether_header *) buffer; - dlt_null= (struct dlt_null *) buffer; - v6buffer = buffer + idata->linkhsize; - ipv6 = (struct ip6_hdr *) v6buffer; - - if(idata->type == DLT_EN10MB){ - ethernet->ether_type = htons(ETHERTYPE_IPV6); - - if(!(idata->flags & IFACE_LOOPBACK)){ - ethernet->src = idata->hsrcaddr; - ethernet->dst = idata->hdstaddr; - } - } - else if(idata->type == DLT_NULL){ - dlt_null->family= PF_INET6; - } -#if defined (__OpenBSD__) - else if(idata->type == DLT_LOOP){ - dlt_null->family= htonl(PF_INET6); - } +void init_packet_data(struct iface_data *idata) { + struct dlt_null *dlt_null; + ethernet = (struct ether_header *)buffer; + dlt_null = (struct dlt_null *)buffer; + v6buffer = buffer + idata->linkhsize; + ipv6 = (struct ip6_hdr *)v6buffer; + + if (idata->type == DLT_EN10MB) { + ethernet->ether_type = htons(ETHERTYPE_IPV6); + + if (!(idata->flags & IFACE_LOOPBACK)) { + ethernet->src = idata->hsrcaddr; + ethernet->dst = idata->hdstaddr; + } + } + else if (idata->type == DLT_NULL) { + dlt_null->family = PF_INET6; + } +#if defined(__OpenBSD__) + else if (idata->type == DLT_LOOP) { + dlt_null->family = htonl(PF_INET6); + } #endif - ipv6->ip6_flow=0; - ipv6->ip6_vfc= 0x60; - ipv6->ip6_hlim= hoplimit; - ipv6->ip6_src= idata->srcaddr; - ipv6->ip6_dst= idata->dstaddr; - - prev_nh = (unsigned char *) &(ipv6->ip6_nxt); - - ptr = (unsigned char *) v6buffer + MIN_IPV6_HLEN; - - /* - * We include a Hop by Hop Options header that will include the Jumbo Payload option. - * The user may specify additionaly HBH option headers. - */ - - *prev_nh = IPPROTO_HOPOPTS; - prev_nh = ptr; - - ptr++; - *ptr= 0; /* HBH len */ - ptr++; - *ptr= IP6OPT_JUMBO; /* Option type */ - ptr++; - *ptr= 4; /* Option length */ - ptr++; - jplengthptr= (uint32_t *) ptr; - ptr+=4; - - - if(hbhopthdr_f){ - hbhopthdrs=0; - - while(hbhopthdrs < nhbhopthdr){ - if((ptr+ hbhopthdrlen[hbhopthdrs]) > (v6buffer+ idata->mtu)){ - puts("Packet too large while processing HBH Opt. Header"); - exit(EXIT_FAILURE); - } - - *prev_nh = IPPROTO_HOPOPTS; - prev_nh = ptr; - memcpy(ptr, hbhopthdr[hbhopthdrs], hbhopthdrlen[hbhopthdrs]); - ptr = ptr + hbhopthdrlen[hbhopthdrs]; - hbhopthdrs++; - } - } - - if(dstoptuhdr_f){ - dstoptuhdrs=0; - - while(dstoptuhdrs < ndstoptuhdr){ - if((ptr+ dstoptuhdrlen[dstoptuhdrs]) > (v6buffer+ idata->mtu)){ - puts("Packet too large while processing Dest. Opt. Header (Unfrag. Part)"); - exit(EXIT_FAILURE); - } - - *prev_nh = IPPROTO_DSTOPTS; - prev_nh = ptr; - memcpy(ptr, dstoptuhdr[dstoptuhdrs], dstoptuhdrlen[dstoptuhdrs]); - ptr = ptr + dstoptuhdrlen[dstoptuhdrs]; - dstoptuhdrs++; - } - } - - /* Everything that follows is the Fragmentable Part of the packet */ - fragpart = ptr; - - if(fragh_f){ - /* Check that we are able to send the Unfragmentable Part, together with a - Fragment Header and a chunk data over our link layer - */ - if( (fragpart+sizeof(fraghdr)+nfrags) > (v6buffer+idata->mtu)){ - printf("Unfragmentable part too large for current MTU (%u bytes)\n", idata->mtu); - exit(EXIT_FAILURE); - } - - /* We prepare a separete Fragment Header, but we do not include it in the packet to be sent. - This Fragment Header will be used (an assembled with the rest of the packet by the - send_packet() function. - */ - memset(&fraghdr, 0, FRAG_HDR_SIZE); - *prev_nh = IPPROTO_FRAGMENT; - prev_nh = (unsigned char *) &fraghdr; - } - - if(dstopthdr_f){ - dstopthdrs=0; - - while(dstopthdrs < ndstopthdr){ - if((ptr+ dstopthdrlen[dstopthdrs]) > (v6buffer+idata->max_packet_size)){ - puts("Packet too large while processing Dest. Opt. Header (should be using the Frag. option?)"); - exit(EXIT_FAILURE); - } - - *prev_nh = IPPROTO_DSTOPTS; - prev_nh = ptr; - memcpy(ptr, dstopthdr[dstopthdrs], dstopthdrlen[dstopthdrs]); - ptr = ptr + dstopthdrlen[dstopthdrs]; - dstopthdrs++; - } - } - - - *prev_nh = IPPROTO_ICMPV6; - - icmp6 = (struct icmp6_hdr *) ptr; - icmp6->icmp6_type = ICMP6_ECHO_REQUEST; - icmp6->icmp6_code = 0; - icmp6->icmp6_cksum = 0; - icmp6->icmp6_data16[0]= htons(getpid()); /* Identifier */ - icmp6->icmp6_data16[1]= htons(random()); /* Sequence Number */ - - ptr+= sizeof(struct icmp6_hdr); - - for(i=0; i< (icmp6psize/4); i++){ - *(uint32_t *)ptr = random(); - ptr += sizeof(uint32_t); - } - - icmp6->icmp6_cksum = in_chksum(v6buffer, icmp6, ptr-((unsigned char *)icmp6), IPPROTO_ICMPV6); - - startofprefixes=ptr; + ipv6->ip6_flow = 0; + ipv6->ip6_vfc = 0x60; + ipv6->ip6_hlim = hoplimit; + ipv6->ip6_src = idata->srcaddr; + ipv6->ip6_dst = idata->dstaddr; + + prev_nh = (unsigned char *)&(ipv6->ip6_nxt); + + ptr = (unsigned char *)v6buffer + MIN_IPV6_HLEN; + + /* + * We include a Hop by Hop Options header that will include the Jumbo Payload option. + * The user may specify additionaly HBH option headers. + */ + + *prev_nh = IPPROTO_HOPOPTS; + prev_nh = ptr; + + ptr++; + *ptr = 0; /* HBH len */ + ptr++; + *ptr = IP6OPT_JUMBO; /* Option type */ + ptr++; + *ptr = 4; /* Option length */ + ptr++; + jplengthptr = (uint32_t *)ptr; + ptr += 4; + + if (hbhopthdr_f) { + hbhopthdrs = 0; + + while (hbhopthdrs < nhbhopthdr) { + if ((ptr + hbhopthdrlen[hbhopthdrs]) > (v6buffer + idata->mtu)) { + puts("Packet too large while processing HBH Opt. Header"); + exit(EXIT_FAILURE); + } + + *prev_nh = IPPROTO_HOPOPTS; + prev_nh = ptr; + memcpy(ptr, hbhopthdr[hbhopthdrs], hbhopthdrlen[hbhopthdrs]); + ptr = ptr + hbhopthdrlen[hbhopthdrs]; + hbhopthdrs++; + } + } + + if (dstoptuhdr_f) { + dstoptuhdrs = 0; + + while (dstoptuhdrs < ndstoptuhdr) { + if ((ptr + dstoptuhdrlen[dstoptuhdrs]) > (v6buffer + idata->mtu)) { + puts("Packet too large while processing Dest. Opt. Header (Unfrag. Part)"); + exit(EXIT_FAILURE); + } + + *prev_nh = IPPROTO_DSTOPTS; + prev_nh = ptr; + memcpy(ptr, dstoptuhdr[dstoptuhdrs], dstoptuhdrlen[dstoptuhdrs]); + ptr = ptr + dstoptuhdrlen[dstoptuhdrs]; + dstoptuhdrs++; + } + } + + /* Everything that follows is the Fragmentable Part of the packet */ + fragpart = ptr; + + if (fragh_f) { + /* Check that we are able to send the Unfragmentable Part, together with a + Fragment Header and a chunk data over our link layer + */ + if ((fragpart + sizeof(fraghdr) + nfrags) > (v6buffer + idata->mtu)) { + printf("Unfragmentable part too large for current MTU (%u bytes)\n", idata->mtu); + exit(EXIT_FAILURE); + } + + /* We prepare a separete Fragment Header, but we do not include it in the packet to be sent. + This Fragment Header will be used (an assembled with the rest of the packet by the + send_packet() function. + */ + memset(&fraghdr, 0, FRAG_HDR_SIZE); + *prev_nh = IPPROTO_FRAGMENT; + prev_nh = (unsigned char *)&fraghdr; + } + + if (dstopthdr_f) { + dstopthdrs = 0; + + while (dstopthdrs < ndstopthdr) { + if ((ptr + dstopthdrlen[dstopthdrs]) > (v6buffer + idata->max_packet_size)) { + puts("Packet too large while processing Dest. Opt. Header (should be using the Frag. option?)"); + exit(EXIT_FAILURE); + } + + *prev_nh = IPPROTO_DSTOPTS; + prev_nh = ptr; + memcpy(ptr, dstopthdr[dstopthdrs], dstopthdrlen[dstopthdrs]); + ptr = ptr + dstopthdrlen[dstopthdrs]; + dstopthdrs++; + } + } + + *prev_nh = IPPROTO_ICMPV6; + + icmp6 = (struct icmp6_hdr *)ptr; + icmp6->icmp6_type = ICMP6_ECHO_REQUEST; + icmp6->icmp6_code = 0; + icmp6->icmp6_cksum = 0; + icmp6->icmp6_data16[0] = htons(getpid()); /* Identifier */ + icmp6->icmp6_data16[1] = htons(random()); /* Sequence Number */ + + ptr += sizeof(struct icmp6_hdr); + + for (i = 0; i < (icmp6psize / 4); i++) { + *(uint32_t *)ptr = random(); + ptr += sizeof(uint32_t); + } + + icmp6->icmp6_cksum = in_chksum(v6buffer, icmp6, ptr - ((unsigned char *)icmp6), IPPROTO_ICMPV6); + + startofprefixes = ptr; } - - /* * Function: send_packet() * * Initialize the remaining fields of the Neighbor Advertisement Message, and * send the attack packet(s). */ -int send_packet(struct iface_data *idata, struct pcap_pkthdr *pkthdr, const u_char *pktdata){ - ptr= startofprefixes; - - if(!fragh_f){ - if(ip6length_f) - ipv6->ip6_plen= htons(ip6length); - else - ipv6->ip6_plen= htons(0); - - if(jplength_f) - *jplengthptr= htonl(jplength); - else - *jplengthptr= htonl((ptr - v6buffer) - MIN_IPV6_HLEN); - - if((nw=pcap_inject(idata->pfd, buffer, ptr - buffer)) == -1){ - printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); - exit(EXIT_FAILURE); - } - - if(nw != (ptr-buffer)){ - printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", \ - nw, (LUI) (ptr-buffer)); - exit(EXIT_FAILURE); - } - } - else{ - ptrend= ptr; - ptr= fragpart; - fptr = fragbuffer; - fipv6 = (struct ip6_hdr *) (fragbuffer + ETHER_HDR_LEN); - fptrend = fptr + ETHER_HDR_LEN+MIN_IPV6_HLEN+MAX_IPV6_PAYLOAD; - fjplengthptr= (uint32_t *) (fptr + sizeof(struct ether_header) + sizeof(struct ip6_hdr) + 3); - /* We copy everything from the Ethernet header till the end of the Unfragmentable part */ - memcpy(fptr, buffer, fragpart-buffer); - fptr = fptr + (fragpart-buffer); - - /* Check whether there is still room to add a Fragmentation Header */ - if( (fptr+FRAG_HDR_SIZE)> fptrend){ - puts("Unfragmentable Part is Too Large"); - exit(EXIT_FAILURE); - } - - /* Copy the Fragmentation Header */ - memcpy(fptr, (char *) &fraghdr, FRAG_HDR_SIZE); - fh= (struct ip6_frag *) fptr; - fh->ip6f_ident=random(); - startoffragment = fptr + FRAG_HDR_SIZE; - - /* - * Check that the selected fragment size is not larger than the largest - * fragment size that can be sent - */ - if(nfrags > (fptrend - fptr)) - nfrags= (fptrend-fptr); - - m=IP6F_MORE_FRAG; - - while((ptr< ptrend) && m==IP6F_MORE_FRAG){ - fptr= startoffragment; - - if( (ptrend-ptr) <= nfrags){ - fragsize= ptrend-ptr; - m=0; - } - else{ - fragsize = (nfrags + 7) & ntohs(IP6F_OFF_MASK); - } - - memcpy(fptr, ptr, fragsize); - fh->ip6f_offlg = (htons(ptr-fragpart) & IP6F_OFF_MASK) | m; - ptr+=fragsize; - fptr+=fragsize; - - fipv6->ip6_plen = htons((fptr - fragbuffer) - MIN_IPV6_HLEN - ETHER_HDR_LEN); - - if(ip6length_f) - fipv6->ip6_plen = htons(ip6length); - else - fipv6->ip6_plen= htons(0); - - if(jplength_f) - *fjplengthptr= htonl(jplength); - else - *fjplengthptr= htonl((fptr - fragbuffer) - MIN_IPV6_HLEN - ETHER_HDR_LEN); - - - if((nw=pcap_inject(idata->pfd, fragbuffer, fptr - fragbuffer)) == -1){ - printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); - exit(EXIT_FAILURE); - } - - if(nw != (fptr- fragbuffer)){ - printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", \ - nw, (LUI) (ptr-buffer)); - exit(EXIT_FAILURE); - } - } /* Sending fragments */ - } /* Sending fragmented datagram */ - - return(0); +int send_packet(struct iface_data *idata, struct pcap_pkthdr *pkthdr, const u_char *pktdata) { + ptr = startofprefixes; + + if (!fragh_f) { + if (ip6length_f) + ipv6->ip6_plen = htons(ip6length); + else + ipv6->ip6_plen = htons(0); + + if (jplength_f) + *jplengthptr = htonl(jplength); + else + *jplengthptr = htonl((ptr - v6buffer) - MIN_IPV6_HLEN); + + if ((nw = pcap_inject(idata->pfd, buffer, ptr - buffer)) == -1) { + printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); + exit(EXIT_FAILURE); + } + + if (nw != (ptr - buffer)) { + printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, (LUI)(ptr - buffer)); + exit(EXIT_FAILURE); + } + } + else { + ptrend = ptr; + ptr = fragpart; + fptr = fragbuffer; + fipv6 = (struct ip6_hdr *)(fragbuffer + ETHER_HDR_LEN); + fptrend = fptr + ETHER_HDR_LEN + MIN_IPV6_HLEN + MAX_IPV6_PAYLOAD; + fjplengthptr = (uint32_t *)(fptr + sizeof(struct ether_header) + sizeof(struct ip6_hdr) + 3); + /* We copy everything from the Ethernet header till the end of the Unfragmentable part */ + memcpy(fptr, buffer, fragpart - buffer); + fptr = fptr + (fragpart - buffer); + + /* Check whether there is still room to add a Fragmentation Header */ + if ((fptr + FRAG_HDR_SIZE) > fptrend) { + puts("Unfragmentable Part is Too Large"); + exit(EXIT_FAILURE); + } + + /* Copy the Fragmentation Header */ + memcpy(fptr, (char *)&fraghdr, FRAG_HDR_SIZE); + fh = (struct ip6_frag *)fptr; + fh->ip6f_ident = random(); + startoffragment = fptr + FRAG_HDR_SIZE; + + /* + * Check that the selected fragment size is not larger than the largest + * fragment size that can be sent + */ + if (nfrags > (fptrend - fptr)) + nfrags = (fptrend - fptr); + + m = IP6F_MORE_FRAG; + + while ((ptr < ptrend) && m == IP6F_MORE_FRAG) { + fptr = startoffragment; + + if ((ptrend - ptr) <= nfrags) { + fragsize = ptrend - ptr; + m = 0; + } + else { + fragsize = (nfrags + 7) & ntohs(IP6F_OFF_MASK); + } + + memcpy(fptr, ptr, fragsize); + fh->ip6f_offlg = (htons(ptr - fragpart) & IP6F_OFF_MASK) | m; + ptr += fragsize; + fptr += fragsize; + + fipv6->ip6_plen = htons((fptr - fragbuffer) - MIN_IPV6_HLEN - ETHER_HDR_LEN); + + if (ip6length_f) + fipv6->ip6_plen = htons(ip6length); + else + fipv6->ip6_plen = htons(0); + + if (jplength_f) + *fjplengthptr = htonl(jplength); + else + *fjplengthptr = htonl((fptr - fragbuffer) - MIN_IPV6_HLEN - ETHER_HDR_LEN); + + if ((nw = pcap_inject(idata->pfd, fragbuffer, fptr - fragbuffer)) == -1) { + printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); + exit(EXIT_FAILURE); + } + + if (nw != (fptr - fragbuffer)) { + printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, (LUI)(ptr - buffer)); + exit(EXIT_FAILURE); + } + } /* Sending fragments */ + } /* Sending fragmented datagram */ + + return (0); } - - /* * Function: usage() * * Prints the syntax of the jumbo6 tool */ -void usage(void){ - puts("usage: jumbo6 -d DST_ADDR [-i INTERFACE] [-S LINK_SRC_ADDR] [-D LINK-DST-ADDR]\n" - " [-s SRC_ADDR[/LEN]] [-A HOP_LIMIT] [-H HBH_OPT_HDR_SIZE] \n" - " [-U DST_OPT_U_HDR_SIZE] [-y FRAG_SIZE] [-u DST_OPT_HDR_SIZE]\n" - " [-q IPV6_LENGTH] [-Q JUMBO_LENGTH] [-P PAYLOAD_SIZE] [-j PREFIX[/LEN]]\n" - " [-k PREFIX[/LEN]] [-J LINK_ADDR] [-K LINK_ADDR] [-b PREFIX[/LEN]]\n" - " [-g PREFIX[/LEN]] [-B LINK_ADDR] [-G LINK_ADDR] [-L | -l] [-z SECONDS]\n" - " [-v] [-h]"); +void usage(void) { + puts("usage: jumbo6 -d DST_ADDR [-i INTERFACE] [-S LINK_SRC_ADDR] [-D LINK-DST-ADDR]\n" + " [-s SRC_ADDR[/LEN]] [-A HOP_LIMIT] [-H HBH_OPT_HDR_SIZE] \n" + " [-U DST_OPT_U_HDR_SIZE] [-y FRAG_SIZE] [-u DST_OPT_HDR_SIZE]\n" + " [-q IPV6_LENGTH] [-Q JUMBO_LENGTH] [-P PAYLOAD_SIZE] [-j PREFIX[/LEN]]\n" + " [-k PREFIX[/LEN]] [-J LINK_ADDR] [-K LINK_ADDR] [-b PREFIX[/LEN]]\n" + " [-g PREFIX[/LEN]] [-B LINK_ADDR] [-G LINK_ADDR] [-L | -l] [-z SECONDS]\n" + " [-v] [-h]"); } - /* * Function: print_help() * * Prints help information for the jumbo6 tool */ -void print_help(void){ - puts(SI6_TOOLKIT); - puts("jumbo6: Security assessment tool for attack vectors based on IPv6 jumbo packets\n"); +void print_help(void) { + puts(SI6_TOOLKIT); + puts("jumbo6: Security assessment tool for attack vectors based on IPv6 jumbo packets\n"); usage(); - + puts("\nOPTIONS:\n" - " --interface, -i Network interface\n" - " --link-src-addr, -S Link-layer Destination Address\n" - " --link-dst-addr, -D Link-layer Source Address\n" - " --src-addr, -s IPv6 Source Address\n" - " --dst-addr, -d IPv6 Destination Address\n" - " --hop-limit, -A IPv6 Hop Limit\n" - " --frag-hdr. -y Fragment Header\n" - " --dst-opt-hdr, -u Destination Options Header (Fragmentable Part)\n" - " --dst-opt-u-hdr, -U Destination Options Header (Unfragmentable Part)\n" - " --hbh-opt-hdr, -H Hop by Hop Options Header\n" - " --ipv6-length, -q IPv6 Payload Length\n" - " --jumbo-length, -Q Jumbo Payload Length\n" - " --payload-size, -P ICMPv6 payload size\n" - " --loop, -l Send periodic Jumbo messages\n" - " --sleep, -z Pause between sending Redirect messages\n" - " --listen, -L Listen to incoming packets\n" - " --verbose, -v Be verbose\n" - " --help, -h Print help for the jumbo6 tool\n" - "\n" - "Programmed by Fernando Gont on behalf of SI6 Networks \n" - "Please send any bug reports to \n" - ); + " --interface, -i Network interface\n" + " --link-src-addr, -S Link-layer Destination Address\n" + " --link-dst-addr, -D Link-layer Source Address\n" + " --src-addr, -s IPv6 Source Address\n" + " --dst-addr, -d IPv6 Destination Address\n" + " --hop-limit, -A IPv6 Hop Limit\n" + " --frag-hdr. -y Fragment Header\n" + " --dst-opt-hdr, -u Destination Options Header (Fragmentable Part)\n" + " --dst-opt-u-hdr, -U Destination Options Header (Unfragmentable Part)\n" + " --hbh-opt-hdr, -H Hop by Hop Options Header\n" + " --ipv6-length, -q IPv6 Payload Length\n" + " --jumbo-length, -Q Jumbo Payload Length\n" + " --payload-size, -P ICMPv6 payload size\n" + " --loop, -l Send periodic Jumbo messages\n" + " --sleep, -z Pause between sending Redirect messages\n" + " --listen, -L Listen to incoming packets\n" + " --verbose, -v Be verbose\n" + " --help, -h Print help for the jumbo6 tool\n" + "\n" + "Programmed by Fernando Gont on behalf of SI6 Networks \n" + "Please send any bug reports to \n"); } - /* * Function: print_attack_info() * * Prints attack details (when the verbose ("-v") option is specified). */ - -void print_attack_info(struct iface_data *idata){ - puts( "jumbo6: Security assessment tool for attack vectors based on IPv6 Jumbo Payloads\n"); - - if(idata->hsrcaddr_f){ - if(ether_ntop(&(idata->hsrcaddr), plinkaddr, sizeof(plinkaddr)) == 0){ - puts("ether_ntop(): Error converting address"); - exit(EXIT_FAILURE); - } - - printf("Ethernet Source Address: %s\n", plinkaddr); - } - else{ - if(idata->dstaddr_f){ - if(ether_ntop(&(idata->hsrcaddr), plinkaddr, sizeof(plinkaddr)) == 0){ - puts("ether_ntop(): Error converting address"); - exit(EXIT_FAILURE); - } - - printf("Ethernet Source Address: %s%s\n", plinkaddr, \ - ((idata->srcprefix_f)?" (randomized)":" (automatically selected)")); - } - else - puts("Ethernet Source Address: Automatically selected for each packet"); - } - - /* - Ethernet Destination Address only used if a IPv6 Destination Address or an - Ethernet Destination Address were specified. - */ - if(idata->dstaddr_f){ - if(ether_ntop(&(idata->hdstaddr), plinkaddr, sizeof(plinkaddr)) == 0){ - puts("ether_ntop(): Error converting address"); - exit(EXIT_FAILURE); - } - - printf("Ethernet Destination Address: %s%s\n", plinkaddr, \ - ((!idata->hdstaddr_f)?" (automatically selected)":"")); - } - - - if(idata->srcaddr_f){ - if(inet_ntop(AF_INET6, &(idata->srcaddr), psrcaddr, sizeof(psrcaddr)) == NULL){ - puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); - exit(EXIT_FAILURE); - } - - printf("IPv6 Source Address: %s%s\n", psrcaddr, ((idata->srcaddr_f != TRUE)?" (automatically selected)":"")); - } - - if(idata->dstaddr_f){ - if(inet_ntop(AF_INET6, &(idata->dstaddr), pdstaddr, sizeof(pdstaddr)) == NULL){ - puts("inet_ntop(): Error converting IPv6 Destination Address to presentation format"); - exit(EXIT_FAILURE); - } - - printf("IPv6 Destination Address: %s\n", pdstaddr); - } - - printf("IPv6 Hop Limit: %u%s\n", hoplimit, (hoplimit_f)?"":" (randomized)"); - - for(i=0; ihsrcaddr_f) { + if (ether_ntop(&(idata->hsrcaddr), plinkaddr, sizeof(plinkaddr)) == 0) { + puts("ether_ntop(): Error converting address"); + exit(EXIT_FAILURE); + } + + printf("Ethernet Source Address: %s\n", plinkaddr); + } + else { + if (idata->dstaddr_f) { + if (ether_ntop(&(idata->hsrcaddr), plinkaddr, sizeof(plinkaddr)) == 0) { + puts("ether_ntop(): Error converting address"); + exit(EXIT_FAILURE); + } + + printf("Ethernet Source Address: %s%s\n", plinkaddr, + ((idata->srcprefix_f) ? " (randomized)" : " (automatically selected)")); + } + else + puts("Ethernet Source Address: Automatically selected for each packet"); + } + + /* + Ethernet Destination Address only used if a IPv6 Destination Address or an + Ethernet Destination Address were specified. + */ + if (idata->dstaddr_f) { + if (ether_ntop(&(idata->hdstaddr), plinkaddr, sizeof(plinkaddr)) == 0) { + puts("ether_ntop(): Error converting address"); + exit(EXIT_FAILURE); + } + + printf("Ethernet Destination Address: %s%s\n", plinkaddr, + ((!idata->hdstaddr_f) ? " (automatically selected)" : "")); + } + + if (idata->srcaddr_f) { + if (inet_ntop(AF_INET6, &(idata->srcaddr), psrcaddr, sizeof(psrcaddr)) == NULL) { + puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); + exit(EXIT_FAILURE); + } + + printf("IPv6 Source Address: %s%s\n", psrcaddr, + ((idata->srcaddr_f != TRUE) ? " (automatically selected)" : "")); + } + + if (idata->dstaddr_f) { + if (inet_ntop(AF_INET6, &(idata->dstaddr), pdstaddr, sizeof(pdstaddr)) == NULL) { + puts("inet_ntop(): Error converting IPv6 Destination Address to presentation format"); + exit(EXIT_FAILURE); + } + + printf("IPv6 Destination Address: %s\n", pdstaddr); + } + + printf("IPv6 Hop Limit: %u%s\n", hoplimit, (hoplimit_f) ? "" : " (randomized)"); + + for (i = 0; i < ndstoptuhdr; i++) + printf("Destination Options Header (Unfragmentable part): %u bytes\n", dstoptuhdrlen[i]); + + for (i = 0; i < nhbhopthdr; i++) + printf("Hop by Hop Options Header: %u bytes\n", hbhopthdrlen[i]); + + for (i = 0; i < ndstopthdr; i++) + printf("Destination Options Header: %u bytes\n", dstopthdrlen[i]); + + if (fragh_f) + printf("Sending each packet in fragments of %u bytes (plus the Unfragmentable part)\n", nfrags); } - - - /* * Function: valid_icmp6_response() * * Checks whether the response to an ICMPv6 probe is valid */ -int valid_icmp6_response(struct iface_data *idata, struct pcap_pkthdr *pkthdr, const u_char *pktdata){ - - struct ether_header *pkt_ether; - struct ip6_hdr *pkt_ipv6; - struct icmp6_hdr *pkt_icmp6, *pkt_icmp6_icmp6; - unsigned char *pkt_end; - - pkt_ether = (struct ether_header *) pktdata; - pkt_ipv6 = (struct ip6_hdr *)((char *) pkt_ether + ETHER_HDR_LEN); - pkt_icmp6 = (struct icmp6_hdr *) ((char *) pkt_ipv6 + MIN_IPV6_HLEN); - pkt_icmp6_icmp6= (struct icmp6_hdr *) ((unsigned char *) pkt_icmp6 + sizeof(struct icmp6_hdr) +\ - sizeof(struct ip6_hdr) + MIN_HBH_LEN); - pkt_end = (unsigned char *) pktdata + pkthdr->caplen; - - switch(pkt_icmp6->icmp6_type){ - case ICMP6_ECHO_REPLY: - /* The packet length is the minimum of what we capured, and what is specified in the - IPv6 Total Lenght field - */ - if( pkt_end > ((unsigned char *)pkt_icmp6 + ntohs(pkt_ipv6->ip6_plen)) ) - pkt_end = (unsigned char *)pkt_icmp6 + ntohs(pkt_ipv6->ip6_plen); - - /* - Discard the packet if it is not of the minimum size to contain an ICMPv6 - header and the payload we included in the ICMPv6 Echo Request - */ - if( (pkt_end - (unsigned char *) pkt_icmp6) < (sizeof(struct icmp6_hdr) + \ - icmp6psize) ){ - return 0; - } - - if(pkt_icmp6->icmp6_data16[0] != htons(getpid())){ - return 0; - } - - break; - - case ICMP6_PARAM_PROB: - /* The packet length is the minimum of what we capured, and what is specified in the - IPv6 Total Lenght field - */ - if( pkt_end > ((unsigned char *)pkt_icmp6 + ntohs(pkt_ipv6->ip6_plen)) ) - pkt_end = (unsigned char *)pkt_icmp6 + ntohs(pkt_ipv6->ip6_plen); - - /* - Discard the packet if it is not of the minimum size to contain an ICMPv6 - header and the payload we included in the ICMPv6 Echo Request - */ - if( (pkt_end - (unsigned char *) pkt_icmp6) < (sizeof(struct icmp6_hdr) + \ - + sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) + \ - icmp6psize) ){ - return 0; - } - - if(pkt_icmp6_icmp6->icmp6_data16[0] != htons(getpid())){ - return 0; - } - - break; - - default: - return 0; - break; - } - - /* - Check that the Source Address of the Packet is "valid" - */ - if(IN6_IS_ADDR_UNSPECIFIED(&(pkt_ipv6->ip6_src))){ - return 0; - } - - if(IN6_IS_ADDR_LOOPBACK(&(pkt_ipv6->ip6_src))){ - return 0; - } - - if(IN6_IS_ADDR_MULTICAST(&(pkt_ipv6->ip6_src))){ - return 0; - } - - /* - Check that that the Destination Address of the incoming packet is one - of our addresses. - */ - if(!is_eq_in6_addr(&(idata->srcaddr), &(pkt_ipv6->ip6_dst))){ - return 0; - } - - /* Check that the ICMPv6 checksum is correct */ - if(in_chksum(pkt_ipv6, pkt_icmp6, pkt_end-((unsigned char *)pkt_icmp6), IPPROTO_ICMPV6) != 0){ - return 0; - } - - return 1; +int valid_icmp6_response(struct iface_data *idata, struct pcap_pkthdr *pkthdr, const u_char *pktdata) { + + struct ether_header *pkt_ether; + struct ip6_hdr *pkt_ipv6; + struct icmp6_hdr *pkt_icmp6, *pkt_icmp6_icmp6; + unsigned char *pkt_end; + + pkt_ether = (struct ether_header *)pktdata; + pkt_ipv6 = (struct ip6_hdr *)((char *)pkt_ether + ETHER_HDR_LEN); + pkt_icmp6 = (struct icmp6_hdr *)((char *)pkt_ipv6 + MIN_IPV6_HLEN); + pkt_icmp6_icmp6 = (struct icmp6_hdr *)((unsigned char *)pkt_icmp6 + sizeof(struct icmp6_hdr) + + sizeof(struct ip6_hdr) + MIN_HBH_LEN); + pkt_end = (unsigned char *)pktdata + pkthdr->caplen; + + switch (pkt_icmp6->icmp6_type) { + case ICMP6_ECHO_REPLY: + /* The packet length is the minimum of what we capured, and what is specified in the + IPv6 Total Lenght field + */ + if (pkt_end > ((unsigned char *)pkt_icmp6 + ntohs(pkt_ipv6->ip6_plen))) + pkt_end = (unsigned char *)pkt_icmp6 + ntohs(pkt_ipv6->ip6_plen); + + /* + Discard the packet if it is not of the minimum size to contain an ICMPv6 + header and the payload we included in the ICMPv6 Echo Request + */ + if ((pkt_end - (unsigned char *)pkt_icmp6) < (sizeof(struct icmp6_hdr) + icmp6psize)) { + return 0; + } + + if (pkt_icmp6->icmp6_data16[0] != htons(getpid())) { + return 0; + } + + break; + + case ICMP6_PARAM_PROB: + /* The packet length is the minimum of what we capured, and what is specified in the + IPv6 Total Lenght field + */ + if (pkt_end > ((unsigned char *)pkt_icmp6 + ntohs(pkt_ipv6->ip6_plen))) + pkt_end = (unsigned char *)pkt_icmp6 + ntohs(pkt_ipv6->ip6_plen); + + /* + Discard the packet if it is not of the minimum size to contain an ICMPv6 + header and the payload we included in the ICMPv6 Echo Request + */ + if ((pkt_end - (unsigned char *)pkt_icmp6) < + (sizeof(struct icmp6_hdr) + +sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) + icmp6psize)) { + return 0; + } + + if (pkt_icmp6_icmp6->icmp6_data16[0] != htons(getpid())) { + return 0; + } + + break; + + default: + return 0; + break; + } + + /* + Check that the Source Address of the Packet is "valid" + */ + if (IN6_IS_ADDR_UNSPECIFIED(&(pkt_ipv6->ip6_src))) { + return 0; + } + + if (IN6_IS_ADDR_LOOPBACK(&(pkt_ipv6->ip6_src))) { + return 0; + } + + if (IN6_IS_ADDR_MULTICAST(&(pkt_ipv6->ip6_src))) { + return 0; + } + + /* + Check that that the Destination Address of the incoming packet is one + of our addresses. + */ + if (!is_eq_in6_addr(&(idata->srcaddr), &(pkt_ipv6->ip6_dst))) { + return 0; + } + + /* Check that the ICMPv6 checksum is correct */ + if (in_chksum(pkt_ipv6, pkt_icmp6, pkt_end - ((unsigned char *)pkt_icmp6), IPPROTO_ICMPV6) != 0) { + return 0; + } + + return 1; } - diff --git a/tools/jumbo6.h b/tools/jumbo6.h index b0bfb3f..0f8cf7c 100644 --- a/tools/jumbo6.h +++ b/tools/jumbo6.h @@ -3,5 +3,4 @@ * */ -#define QUERY_TIMEOUT 2 - +#define QUERY_TIMEOUT 2 diff --git a/tools/libipv6.c b/tools/libipv6.c index 8240e24..7c569e3 100644 --- a/tools/libipv6.c +++ b/tools/libipv6.c @@ -17,95 +17,92 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . - * + * * Build with: make libipv6 - * + * * It requires that the libpcap library be installed on your system. * * Please send any bug reports to Fernando Gont */ -#include #include -#include #include +#include +#include -#include #include -#include -#include -#include +#include #include #include -#include +#include +#include +#include +#include #ifdef __linux__ - #include - #include - #include - #include /* For datalink structure */ -#elif defined (__FreeBSD__) || defined(__NetBSD__) || defined (__OpenBSD__) || defined(__APPLE__) || defined(__FreeBSD_kernel__) || defined(__sun) || defined(sun) - #include - #include +#include +#include +#include +#include /* For datalink structure */ +#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) || \ + defined(__FreeBSD_kernel__) || defined(__sun) || defined(sun) +#include +#include #endif -#include -#include #include -#include #include -#include -#include -#include #include #include -#include #include +#include +#include +#include +#include +#include +#include +#include -#include "libipv6.h" #include "ipv6toolkit.h" - +#include "libipv6.h" /* IPv6 Address Resolution */ -static sigjmp_buf env; -static unsigned int canjump; - - +static sigjmp_buf env; +static unsigned int canjump; #ifdef __linux__ /* Netlink requests */ -struct nlrequest{ +struct nlrequest { struct nlmsghdr nl; - struct rtmsg rt; - char buf[MAX_NLPAYLOAD]; + struct rtmsg rt; + char buf[MAX_NLPAYLOAD]; }; #endif - /* * Function: is_service_port() * * Check whether a short int is in the list of service ports (in hexadecmal or decimal "notations") */ -unsigned int is_service_port(uint16_t port){ - unsigned int i; - uint16_t service_ports_hex[]={0x21, 0x22, 0x23, 0x25, 0x49, 0x53, 0x80, 0x110, 0x123, 0x179, 0x220, 0x389, \ - 0x443, 0x547, 0x993, 0x995, 0x1194, 0x3306, 0x5060, 0x5061, 0x5432, 0x6446, 0x8080}; - uint16_t service_ports_dec[]={21, 22, 23, 25, 49, 53, 80, 110, 123, 179, 220, 389, \ - 443, 547, 993, 995, 1194, 3306, 5060, 5061, 5432, 6446, 8080}; - - - for(i=0; i< (sizeof(service_ports_hex)/sizeof(uint16_t)); i++){ - if(port == service_ports_hex[i]) - return(1); - } - - for(i=0; i< (sizeof(service_ports_hex)/sizeof(uint16_t)); i++){ - if(port == service_ports_dec[i]) - return(1); - } - - return(0); +unsigned int is_service_port(uint16_t port) { + unsigned int i; + uint16_t service_ports_hex[] = {0x21, 0x22, 0x23, 0x25, 0x49, 0x53, 0x80, 0x110, + 0x123, 0x179, 0x220, 0x389, 0x443, 0x547, 0x993, 0x995, + 0x1194, 0x3306, 0x5060, 0x5061, 0x5432, 0x6446, 0x8080}; + uint16_t service_ports_dec[] = {21, 22, 23, 25, 49, 53, 80, 110, 123, 179, 220, 389, + 443, 547, 993, 995, 1194, 3306, 5060, 5061, 5432, 6446, 8080}; + + for (i = 0; i < (sizeof(service_ports_hex) / sizeof(uint16_t)); i++) { + if (port == service_ports_hex[i]) + return (1); + } + + for (i = 0; i < (sizeof(service_ports_hex) / sizeof(uint16_t)); i++) { + if (port == service_ports_dec[i]) + return (1); + } + + return (0); } /* @@ -114,411 +111,409 @@ unsigned int is_service_port(uint16_t port){ * Counts the number of zero-bytes in an IPv6 Interface ID */ -unsigned int zero_byte_iid(struct in6_addr *ipv6){ - unsigned int i, nonzero=0; +unsigned int zero_byte_iid(struct in6_addr *ipv6) { + unsigned int i, nonzero = 0; - for(i=8; i<=15; i++){ - if(ipv6->s6_addr[i] == 0) - nonzero++; - } + for (i = 8; i <= 15; i++) { + if (ipv6->s6_addr[i] == 0) + nonzero++; + } - return(nonzero); + return (nonzero); } - /* * Function: decode_ipv6_address() * * Decodes/analyzes an IPv6 address */ -void decode_ipv6_address(struct decode6 *addr){ - uint16_t scope; - - if(IN6_IS_ADDR_UNSPECIFIED(&(addr->ip6))){ - addr->type= IPV6_UNSPEC; - addr->subtype= IPV6_UNSPEC; - addr->scope= SCOPE_UNSPECIFIED; - } - else if(IN6_IS_ADDR_MULTICAST(&(addr->ip6))){ - addr->type= IPV6_MULTICAST; - addr->iidtype= IID_UNSPECIFIED; - addr->iidsubtype= IID_UNSPECIFIED; - - if((addr->ip6.s6_addr32[0] & htonl(0xff000000)) == htonl(0xff000000)){ - if((addr->ip6.s6_addr32[0] & htonl(0xfff00000)) == htonl(0xff000000)){ - addr->subtype= MCAST_PERMANENT; - } - else if((addr->ip6.s6_addr32[0] & htonl(0xfff00000)) == htonl(0xff100000)){ - addr->subtype= MCAST_NONPERMANENT; - } - else if((addr->ip6.s6_addr32[0] & htonl(0xfff00000)) == htonl(0xff200000)){ - addr->subtype= MCAST_INVALID; - } - else if((addr->ip6.s6_addr32[0] & htonl(0xfff00000)) == htonl(0xff300000)){ - addr->subtype= MCAST_UNICASTBASED; - } - else if((addr->ip6.s6_addr32[0] & htonl(0xfff00000)) == htonl(0xff400000)){ - addr->subtype= MCAST_INVALID; - } - else if((addr->ip6.s6_addr32[0] & htonl(0xfff00000)) == htonl(0xff500000)){ - addr->subtype= MCAST_INVALID; - } - else if((addr->ip6.s6_addr32[0] & htonl(0xfff00000)) == htonl(0xff600000)){ - addr->subtype= MCAST_INVALID; - } - else if((addr->ip6.s6_addr32[0] & htonl(0xfff00000)) == htonl(0xff700000)){ - addr->subtype= MCAST_EMBEDRP; - } - - scope= (htonl(addr->ip6.s6_addr32[0]) & 0x000f0000) >> 16; - - switch(scope){ - case 0: - addr->scope= SCOPE_RESERVED; - break; - - case 1: - addr->scope= SCOPE_INTERFACE; - break; - - case 2: - addr->scope= SCOPE_LINK; - break; - - case 3: - addr->scope= SCOPE_RESERVED; - break; - - case 4: - addr->scope= SCOPE_ADMIN; - break; - - case 5: - addr->scope= SCOPE_SITE; - break; - - case 8: - addr->scope= SCOPE_ORGANIZATION; - break; - - case 0Xe: - addr->scope= SCOPE_GLOBAL; - break; - - default: - addr->scope= SCOPE_UNASSIGNED; - break; - } - } - else{ - addr->subtype= MCAST_UNKNOWN; - } - } - else{ - addr->type= IPV6_UNICAST; - addr->iidtype= IID_UNSPECIFIED; - addr->iidsubtype= IID_UNSPECIFIED; - - if(IN6_IS_ADDR_LOOPBACK(&(addr->ip6))){ - addr->subtype= UCAST_LOOPBACK; - addr->scope= SCOPE_INTERFACE; - } - else if(IN6_IS_ADDR_V4MAPPED(&(addr->ip6))){ - addr->subtype= UCAST_V4MAPPED; - addr->scope= SCOPE_UNSPECIFIED; - } - else if(IN6_IS_ADDR_V4COMPAT(&(addr->ip6))){ - addr->subtype= UCAST_V4COMPAT; - addr->scope= SCOPE_UNSPECIFIED; - } - else if(IN6_IS_ADDR_LINKLOCAL(&(addr->ip6))){ - addr->subtype= UCAST_LINKLOCAL; - addr->scope= SCOPE_LINK; - } - else if(IN6_IS_ADDR_SITELOCAL(&(addr->ip6))){ - addr->subtype= UCAST_SITELOCAL; - addr->scope= SCOPE_SITE; - } - else if(IN6_IS_ADDR_UNIQUELOCAL(&(addr->ip6))){ - addr->subtype= UCAST_UNIQUELOCAL; - addr->scope= SCOPE_GLOBAL; - } - else if(IN6_IS_ADDR_6TO4(&(addr->ip6))){ - addr->subtype= UCAST_6TO4; - addr->scope= SCOPE_GLOBAL; - } - else if(IN6_IS_ADDR_TEREDO(&(addr->ip6)) || IN6_IS_ADDR_TEREDO_LEGACY(&(addr->ip6))){ - addr->subtype= UCAST_TEREDO; - addr->scope= SCOPE_GLOBAL; - addr->iidtype=IID_TEREDO; - - /* If the U or G bytes are set, the IID type is unknown */ - if(ntohl(addr->ip6.s6_addr32[2]) & 0x03000000){ - addr->iidsubtype= IID_TEREDO_UNKNOWN; - } - else if(ntohs(addr->ip6.s6_addr32[2]) & 0x3cff0000){ - addr->iidsubtype= IID_TEREDO_RFC5991; - } - else{ - addr->iidsubtype= IID_TEREDO_RFC4380; - } - } - else{ - addr->subtype= UCAST_GLOBAL; - addr->scope= SCOPE_GLOBAL; - } - - /* - - XXX: We used to exclude loopback and Teredo from the analysis of IID. Now we do it for all. The user can - use filters to exclude specific address types. - - if(addr->subtype==UCAST_GLOBAL || addr->subtype==UCAST_V4MAPPED || addr->subtype==UCAST_V4COMPAT || \ - addr->subtype==UCAST_LINKLOCAL || addr->subtype==UCAST_SITELOCAL || addr->subtype==UCAST_UNIQUELOCAL ||\ - addr->subtype == UCAST_6TO4){ - */ - - if( (addr->ip6.s6_addr32[2] & htonl(0x020000ff)) == htonl(0x020000ff) && - (addr->ip6.s6_addr32[3] & htonl(0xff000000)) == htonl(0xfe000000)){ - addr->iidtype= IID_MACDERIVED; - addr->iidsubtype= (ntohl(addr->ip6.s6_addr32[2]) >> 8) & 0xfffdffff; - } - else if((addr->ip6.s6_addr32[2] & htonl(0xfdffffff)) == htonl(0x00005efe)){ - /* We assume the u bit can be 0 o 1, but the i/g bit must be 0 */ - addr->iidtype= IID_ISATAP; - } - else if(addr->ip6.s6_addr32[2] == 0 && (addr->ip6.s6_addr32[3] & htonl(0xff000000)) != 0 && (ntohl(addr->ip6.s6_addr32[3]) & 0x0000ffff) != 0){ - addr->iidtype= IID_EMBEDDEDIPV4; - addr->iidsubtype= IID_EMBEDDEDIPV4_32; - } - else if(addr->ip6.s6_addr32[2] == 0 && \ - ((addr->ip6.s6_addr32[3] & htonl(0xff000000)) == 0 && is_service_port(ntohl(addr->ip6.s6_addr32[3]) & 0x0000ffff))){ - addr->iidtype= IID_EMBEDDEDPORT; - addr->iidsubtype= IID_EMBEDDEDPORT; - } - else if(addr->ip6.s6_addr32[2] == 0 && \ - ((addr->ip6.s6_addr32[3] & htonl(0x0000ff00)) == 0 && is_service_port(ntohl(addr->ip6.s6_addr32[3]) >> 16))){ - addr->iidtype= IID_EMBEDDEDPORT; - addr->iidsubtype= IID_EMBEDDEDPORTREV; - } - else if(addr->ip6.s6_addr32[2] == 0 && (addr->ip6.s6_addr32[3] & htonl(0xff000000)) == 0 && (ntohl(addr->ip6.s6_addr32[3]) & 0x0000ffff) != 0){ - addr->iidtype= IID_LOWBYTE; - } - else if( (ntohl(addr->ip6.s6_addr32[2]) >> 16) <= 0x255 && (ntohl(addr->ip6.s6_addr32[2]) & 0x0000ffff) <= 0x255 && \ - (ntohl(addr->ip6.s6_addr32[3]) >> 16) <= 0x255 && (ntohl(addr->ip6.s6_addr32[3]) & 0x0000ffff) <= 0x255){ - addr->iidtype= IID_EMBEDDEDIPV4; - addr->iidsubtype= IID_EMBEDDEDIPV4_64; - } - else if( zero_byte_iid(&(addr->ip6)) > 2 ){ - addr->iidtype= IID_PATTERN_BYTES; - } - else{ - addr->iidtype= IID_RANDOM; - } - } +void decode_ipv6_address(struct decode6 *addr) { + uint16_t scope; + + if (IN6_IS_ADDR_UNSPECIFIED(&(addr->ip6))) { + addr->type = IPV6_UNSPEC; + addr->subtype = IPV6_UNSPEC; + addr->scope = SCOPE_UNSPECIFIED; + } + else if (IN6_IS_ADDR_MULTICAST(&(addr->ip6))) { + addr->type = IPV6_MULTICAST; + addr->iidtype = IID_UNSPECIFIED; + addr->iidsubtype = IID_UNSPECIFIED; + + if ((addr->ip6.s6_addr32[0] & htonl(0xff000000)) == htonl(0xff000000)) { + if ((addr->ip6.s6_addr32[0] & htonl(0xfff00000)) == htonl(0xff000000)) { + addr->subtype = MCAST_PERMANENT; + } + else if ((addr->ip6.s6_addr32[0] & htonl(0xfff00000)) == htonl(0xff100000)) { + addr->subtype = MCAST_NONPERMANENT; + } + else if ((addr->ip6.s6_addr32[0] & htonl(0xfff00000)) == htonl(0xff200000)) { + addr->subtype = MCAST_INVALID; + } + else if ((addr->ip6.s6_addr32[0] & htonl(0xfff00000)) == htonl(0xff300000)) { + addr->subtype = MCAST_UNICASTBASED; + } + else if ((addr->ip6.s6_addr32[0] & htonl(0xfff00000)) == htonl(0xff400000)) { + addr->subtype = MCAST_INVALID; + } + else if ((addr->ip6.s6_addr32[0] & htonl(0xfff00000)) == htonl(0xff500000)) { + addr->subtype = MCAST_INVALID; + } + else if ((addr->ip6.s6_addr32[0] & htonl(0xfff00000)) == htonl(0xff600000)) { + addr->subtype = MCAST_INVALID; + } + else if ((addr->ip6.s6_addr32[0] & htonl(0xfff00000)) == htonl(0xff700000)) { + addr->subtype = MCAST_EMBEDRP; + } + + scope = (htonl(addr->ip6.s6_addr32[0]) & 0x000f0000) >> 16; + + switch (scope) { + case 0: + addr->scope = SCOPE_RESERVED; + break; + + case 1: + addr->scope = SCOPE_INTERFACE; + break; + + case 2: + addr->scope = SCOPE_LINK; + break; + + case 3: + addr->scope = SCOPE_RESERVED; + break; + + case 4: + addr->scope = SCOPE_ADMIN; + break; + + case 5: + addr->scope = SCOPE_SITE; + break; + + case 8: + addr->scope = SCOPE_ORGANIZATION; + break; + + case 0Xe: + addr->scope = SCOPE_GLOBAL; + break; + + default: + addr->scope = SCOPE_UNASSIGNED; + break; + } + } + else { + addr->subtype = MCAST_UNKNOWN; + } + } + else { + addr->type = IPV6_UNICAST; + addr->iidtype = IID_UNSPECIFIED; + addr->iidsubtype = IID_UNSPECIFIED; + + if (IN6_IS_ADDR_LOOPBACK(&(addr->ip6))) { + addr->subtype = UCAST_LOOPBACK; + addr->scope = SCOPE_INTERFACE; + } + else if (IN6_IS_ADDR_V4MAPPED(&(addr->ip6))) { + addr->subtype = UCAST_V4MAPPED; + addr->scope = SCOPE_UNSPECIFIED; + } + else if (IN6_IS_ADDR_V4COMPAT(&(addr->ip6))) { + addr->subtype = UCAST_V4COMPAT; + addr->scope = SCOPE_UNSPECIFIED; + } + else if (IN6_IS_ADDR_LINKLOCAL(&(addr->ip6))) { + addr->subtype = UCAST_LINKLOCAL; + addr->scope = SCOPE_LINK; + } + else if (IN6_IS_ADDR_SITELOCAL(&(addr->ip6))) { + addr->subtype = UCAST_SITELOCAL; + addr->scope = SCOPE_SITE; + } + else if (IN6_IS_ADDR_UNIQUELOCAL(&(addr->ip6))) { + addr->subtype = UCAST_UNIQUELOCAL; + addr->scope = SCOPE_GLOBAL; + } + else if (IN6_IS_ADDR_6TO4(&(addr->ip6))) { + addr->subtype = UCAST_6TO4; + addr->scope = SCOPE_GLOBAL; + } + else if (IN6_IS_ADDR_TEREDO(&(addr->ip6)) || IN6_IS_ADDR_TEREDO_LEGACY(&(addr->ip6))) { + addr->subtype = UCAST_TEREDO; + addr->scope = SCOPE_GLOBAL; + addr->iidtype = IID_TEREDO; + + /* If the U or G bytes are set, the IID type is unknown */ + if (ntohl(addr->ip6.s6_addr32[2]) & 0x03000000) { + addr->iidsubtype = IID_TEREDO_UNKNOWN; + } + else if (ntohs(addr->ip6.s6_addr32[2]) & 0x3cff0000) { + addr->iidsubtype = IID_TEREDO_RFC5991; + } + else { + addr->iidsubtype = IID_TEREDO_RFC4380; + } + } + else { + addr->subtype = UCAST_GLOBAL; + addr->scope = SCOPE_GLOBAL; + } + + /* + + XXX: We used to exclude loopback and Teredo from the analysis of IID. Now we do it for all. The user can + use filters to exclude specific address types. + + if(addr->subtype==UCAST_GLOBAL || addr->subtype==UCAST_V4MAPPED || addr->subtype==UCAST_V4COMPAT || \ + addr->subtype==UCAST_LINKLOCAL || addr->subtype==UCAST_SITELOCAL || addr->subtype==UCAST_UNIQUELOCAL ||\ + addr->subtype == UCAST_6TO4){ + */ + + if ((addr->ip6.s6_addr32[2] & htonl(0x020000ff)) == htonl(0x020000ff) && + (addr->ip6.s6_addr32[3] & htonl(0xff000000)) == htonl(0xfe000000)) { + addr->iidtype = IID_MACDERIVED; + addr->iidsubtype = (ntohl(addr->ip6.s6_addr32[2]) >> 8) & 0xfffdffff; + } + else if ((addr->ip6.s6_addr32[2] & htonl(0xfdffffff)) == htonl(0x00005efe)) { + /* We assume the u bit can be 0 o 1, but the i/g bit must be 0 */ + addr->iidtype = IID_ISATAP; + } + else if (addr->ip6.s6_addr32[2] == 0 && (addr->ip6.s6_addr32[3] & htonl(0xff000000)) != 0 && + (ntohl(addr->ip6.s6_addr32[3]) & 0x0000ffff) != 0) { + addr->iidtype = IID_EMBEDDEDIPV4; + addr->iidsubtype = IID_EMBEDDEDIPV4_32; + } + else if (addr->ip6.s6_addr32[2] == 0 && ((addr->ip6.s6_addr32[3] & htonl(0xff000000)) == 0 && + is_service_port(ntohl(addr->ip6.s6_addr32[3]) & 0x0000ffff))) { + addr->iidtype = IID_EMBEDDEDPORT; + addr->iidsubtype = IID_EMBEDDEDPORT; + } + else if (addr->ip6.s6_addr32[2] == 0 && ((addr->ip6.s6_addr32[3] & htonl(0x0000ff00)) == 0 && + is_service_port(ntohl(addr->ip6.s6_addr32[3]) >> 16))) { + addr->iidtype = IID_EMBEDDEDPORT; + addr->iidsubtype = IID_EMBEDDEDPORTREV; + } + else if (addr->ip6.s6_addr32[2] == 0 && (addr->ip6.s6_addr32[3] & htonl(0xff000000)) == 0 && + (ntohl(addr->ip6.s6_addr32[3]) & 0x0000ffff) != 0) { + addr->iidtype = IID_LOWBYTE; + } + else if ((ntohl(addr->ip6.s6_addr32[2]) >> 16) <= 0x255 && + (ntohl(addr->ip6.s6_addr32[2]) & 0x0000ffff) <= 0x255 && + (ntohl(addr->ip6.s6_addr32[3]) >> 16) <= 0x255 && + (ntohl(addr->ip6.s6_addr32[3]) & 0x0000ffff) <= 0x255) { + addr->iidtype = IID_EMBEDDEDIPV4; + addr->iidsubtype = IID_EMBEDDEDIPV4_64; + } + else if (zero_byte_iid(&(addr->ip6)) > 2) { + addr->iidtype = IID_PATTERN_BYTES; + } + else { + addr->iidtype = IID_RANDOM; + } + } } - /* * Function: dns_decode() * * Decode a domain name from DNS wire format to an ASCII string */ -int dns_decode(unsigned char *start, unsigned int size, unsigned char *ptr, \ - char *out, unsigned int outsize, unsigned char **next){ - unsigned char *end; - char *w; - unsigned int clabels=0, nlabels=0; - end= start+size; - w= out; - - while(nlabels <= MAX_DNS_LABELS){ - switch((*ptr & 0xc0)){ - case 0x00: - /* No compression */ - - /* Check wether the label spans past the end of the packet */ - if((ptr + *ptr) >= end) - return(-1); - - /* Check whether there is room to write this label */ - if( (w+ *ptr + 1) >=(out+outsize)) - return(-1); - - /* Check whether this is a zero-label */ - if(*ptr == 0){ - ptr++; - - /* Check whether there is a single-label domain */ - if(ptr < end){ - if(*ptr == 0) - ptr++; - } - - if(w == out){ - *w='.'; - w++; - } - - *w=0x00; /* null-terminate the string */ - - /* If we're past a compressed label, '*next' already contains the right value */ - if(!clabels){ - if(ptr >= end) - *next= NULL; - else - *next=ptr; - } - - return(0); - } - else{ - memcpy(w, (ptr+1), *ptr); - w= w + *ptr; - *w= '.'; - w++; - ptr= ptr+ (*ptr + 1); - - if(ptr >= end) - return(-1); - } - - break; - - case 0xc0: - /* Compression */ - - /* A compressed label ocuppies two bytes */ - if( (ptr+1) >= end) - return(-1); - - /* The next domain is the one follong the two-byte compressed label */ - if(!clabels){ - *next= ptr+2; - - if(*next >= end) - *next= NULL; - } - - clabels++; - - if(clabels > MAX_DNS_CLABELS){ - return(-1); - } - - ptr= start + ((((unsigned short int)(*ptr & 0x3c))<< 8) + *(ptr+1)); - break; - - default: - return(-1); - } - } - - return(0); +int dns_decode(unsigned char *start, unsigned int size, unsigned char *ptr, char *out, unsigned int outsize, + unsigned char **next) { + unsigned char *end; + char *w; + unsigned int clabels = 0, nlabels = 0; + end = start + size; + w = out; + + while (nlabels <= MAX_DNS_LABELS) { + switch ((*ptr & 0xc0)) { + case 0x00: + /* No compression */ + + /* Check wether the label spans past the end of the packet */ + if ((ptr + *ptr) >= end) + return (-1); + + /* Check whether there is room to write this label */ + if ((w + *ptr + 1) >= (out + outsize)) + return (-1); + + /* Check whether this is a zero-label */ + if (*ptr == 0) { + ptr++; + + /* Check whether there is a single-label domain */ + if (ptr < end) { + if (*ptr == 0) + ptr++; + } + + if (w == out) { + *w = '.'; + w++; + } + + *w = 0x00; /* null-terminate the string */ + + /* If we're past a compressed label, '*next' already contains the right value */ + if (!clabels) { + if (ptr >= end) + *next = NULL; + else + *next = ptr; + } + + return (0); + } + else { + memcpy(w, (ptr + 1), *ptr); + w = w + *ptr; + *w = '.'; + w++; + ptr = ptr + (*ptr + 1); + + if (ptr >= end) + return (-1); + } + + break; + + case 0xc0: + /* Compression */ + + /* A compressed label ocuppies two bytes */ + if ((ptr + 1) >= end) + return (-1); + + /* The next domain is the one follong the two-byte compressed label */ + if (!clabels) { + *next = ptr + 2; + + if (*next >= end) + *next = NULL; + } + + clabels++; + + if (clabels > MAX_DNS_CLABELS) { + return (-1); + } + + ptr = start + ((((unsigned short int)(*ptr & 0x3c)) << 8) + *(ptr + 1)); + break; + + default: + return (-1); + } + } + + return (0); } - - /* * dns_str2wire() * * Converts a DNS name to DNS wire format (uncompressed) */ -int dns_str2wire(char *str, unsigned int slen, char *wire, unsigned int wlen){ - char *label, *src, *dst; - unsigned int llen; - - if(wlen < slen) - return(-1); - - src= str; - dst= wire; - - while(1){ - - llen=0; - label= src; - - while(*src != 0 && *src != '.' && src < (str + slen)){ - src++; - llen++; - } - - *dst= llen; - dst++; - memcpy(dst, label, llen); - dst+= llen; - - if(*src == 0){ - *dst= 0; - dst++; - break; - } - else if(src >= (str + slen)){ - return(-1); - } - else{ - src++; - } - } - - return(dst-wire); +int dns_str2wire(char *str, unsigned int slen, char *wire, unsigned int wlen) { + char *label, *src, *dst; + unsigned int llen; + + if (wlen < slen) + return (-1); + + src = str; + dst = wire; + + while (1) { + + llen = 0; + label = src; + + while (*src != 0 && *src != '.' && src < (str + slen)) { + src++; + llen++; + } + + *dst = llen; + dst++; + memcpy(dst, label, llen); + dst += llen; + + if (*src == 0) { + *dst = 0; + dst++; + break; + } + else if (src >= (str + slen)) { + return (-1); + } + else { + src++; + } + } + + return (dst - wire); } - /* * Function: inet_ntof() * * Convert binary IPv6 address into printable formt (an ASCII string) of fixed length */ -const char * inet_ntof(int family, const void *src, char *dst, socklen_t size){ - unsigned int r; - const struct in6_addr *v6; +const char *inet_ntof(int family, const void *src, char *dst, socklen_t size) { + unsigned int r; + const struct in6_addr *v6; - v6= src; + v6 = src; - if(family != AF_INET6) - return NULL; + if (family != AF_INET6) + return NULL; - if(size < INET6_ADDRSTRLEN) - return NULL; + if (size < INET6_ADDRSTRLEN) + return NULL; - r=snprintf(dst, size, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x", ntohl(v6->s6_addr32[0]) >> 16, ntohl(v6->s6_addr32[0]) & 0x0000ffff,\ - ntohl(v6->s6_addr32[1]) >> 16, ntohl(v6->s6_addr32[1]) & 0x0000ffff,\ - ntohl(v6->s6_addr32[2]) >> 16, ntohl(v6->s6_addr32[2]) & 0x0000ffff,\ - ntohl(v6->s6_addr32[3]) >> 16, ntohl(v6->s6_addr32[3]) & 0x0000ffff); + r = snprintf(dst, size, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x", ntohl(v6->s6_addr32[0]) >> 16, + ntohl(v6->s6_addr32[0]) & 0x0000ffff, ntohl(v6->s6_addr32[1]) >> 16, + ntohl(v6->s6_addr32[1]) & 0x0000ffff, ntohl(v6->s6_addr32[2]) >> 16, + ntohl(v6->s6_addr32[2]) & 0x0000ffff, ntohl(v6->s6_addr32[3]) >> 16, + ntohl(v6->s6_addr32[3]) & 0x0000ffff); - if(r == 39) - return dst; - else - return NULL; + if (r == 39) + return dst; + else + return NULL; } - /* * Function: ether_multicast() * * Obtains the Ethernet multicast address corresponding to an IPv6 multicast address. */ -struct ether_addr ether_multicast(const struct in6_addr *ipv6addr){ - unsigned int i; - struct ether_addr ether; +struct ether_addr ether_multicast(const struct in6_addr *ipv6addr) { + unsigned int i; + struct ether_addr ether; - ether.a[0]=0x33; - ether.a[1]=0x33; + ether.a[0] = 0x33; + ether.a[1] = 0x33; - for(i=2;i<6;i++) - ether.a[i]= ipv6addr->s6_addr[i+10]; + for (i = 2; i < 6; i++) + ether.a[i] = ipv6addr->s6_addr[i + 10]; - return ether; + return ether; } - /* * Function: inet_ntof() * @@ -528,50 +523,48 @@ struct ether_addr ether_multicast(const struct in6_addr *ipv6addr){ /* inet_ntof(AF_INET6, &(addr.ip6), pv6addr, sizeof(pv6addr)) == NULL */ /* const char * inet_ntof(int addrfamily, const void *src, char *dst, socklen_t size){ - unsigned int r; - const struct in6_addr *p; + unsigned int r; + const struct in6_addr *p; - if(addrfamily != AF_INET6 || size < INET_ADDRSTRLEN){ - return(NULL); - } + if(addrfamily != AF_INET6 || size < INET_ADDRSTRLEN){ + return(NULL); + } - p= src; + p= src; - r=snprintf(dst, size, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%x04", ntohs(p->s6_addr16[0]), ntohs(p->s6_addr16[1]), ntohs(p->s6_addr16[2]),\ - ntohs(p->s6_addr16[3]), ntohs(p->s6_addr16[4]), ntohs(p->s6_addr16[5]), ntohs(p->s6_addr16[6]),\ - ntohs(p->s6_addr16[7])); + r=snprintf(dst, size, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%x04", ntohs(p->s6_addr16[0]), ntohs(p->s6_addr16[1]), +ntohs(p->s6_addr16[2]),\ + ntohs(p->s6_addr16[3]), ntohs(p->s6_addr16[4]), +ntohs(p->s6_addr16[5]), ntohs(p->s6_addr16[6]),\ ntohs(p->s6_addr16[7])); - if(r != 39) - return NULL; + if(r != 39) + return NULL; - return dst; + return dst; } */ - - /* * Function: ether_ntop() * * Convert binary Ethernet Address into printable foramt (an ASCII string) */ -int ether_ntop(const struct ether_addr *ether, char *ascii, size_t s){ - unsigned int r; +int ether_ntop(const struct ether_addr *ether, char *ascii, size_t s) { + unsigned int r; - if(s < ETHER_ADDR_PLEN) - return 0; + if (s < ETHER_ADDR_PLEN) + return 0; - r=snprintf(ascii, s, "%02x:%02x:%02x:%02x:%02x:%02x", ether->a[0], ether->a[1], ether->a[2], ether->a[3], \ - ether->a[4], ether->a[5]); + r = snprintf(ascii, s, "%02x:%02x:%02x:%02x:%02x:%02x", ether->a[0], ether->a[1], ether->a[2], ether->a[3], + ether->a[4], ether->a[5]); - if(r != 17) - return 0; + if (r != 17) + return 0; - return 1; + return 1; } - /* * Function: ether_to_ipv6_linklocal() * @@ -579,46 +572,43 @@ int ether_ntop(const struct ether_addr *ether, char *ascii, size_t s){ * an Ethernet address. */ -void ether_to_ipv6_linklocal(struct ether_addr *etheraddr, struct in6_addr *ipv6addr){ - ipv6addr->s6_addr32[0]= htonl(0xfe800000); /* Link-local unicast prefix */ - ipv6addr->s6_addr32[1]= htonl(0x00000000); - - ipv6addr->s6_addr[8]= etheraddr->a[0] | 0x02; - ipv6addr->s6_addr[9]= etheraddr->a[1]; - ipv6addr->s6_addr[10]= etheraddr->a[2]; - ipv6addr->s6_addr[11]= 0xff; - ipv6addr->s6_addr[12]= 0xfe; - ipv6addr->s6_addr[13]= etheraddr->a[3]; - ipv6addr->s6_addr[14]= etheraddr->a[4]; - ipv6addr->s6_addr[15]= etheraddr->a[5]; +void ether_to_ipv6_linklocal(struct ether_addr *etheraddr, struct in6_addr *ipv6addr) { + ipv6addr->s6_addr32[0] = htonl(0xfe800000); /* Link-local unicast prefix */ + ipv6addr->s6_addr32[1] = htonl(0x00000000); + + ipv6addr->s6_addr[8] = etheraddr->a[0] | 0x02; + ipv6addr->s6_addr[9] = etheraddr->a[1]; + ipv6addr->s6_addr[10] = etheraddr->a[2]; + ipv6addr->s6_addr[11] = 0xff; + ipv6addr->s6_addr[12] = 0xfe; + ipv6addr->s6_addr[13] = etheraddr->a[3]; + ipv6addr->s6_addr[14] = etheraddr->a[4]; + ipv6addr->s6_addr[15] = etheraddr->a[5]; } - - /* * Function: ether_pton() * * Convert a string (printable Ethernet Address) into binary format */ -int ether_pton(const char *ascii, struct ether_addr *etheraddr, unsigned int s){ - unsigned int i, a[6]; +int ether_pton(const char *ascii, struct ether_addr *etheraddr, unsigned int s) { + unsigned int i, a[6]; - if(s < ETHER_ADDR_LEN) - return 0; - - if(ascii){ - if( sscanf(ascii,"%x:%x:%x:%x:%x:%x", &a[0], &a[1], &a[2], &a[3], &a[4], &a[5]) == 6){ - for(i=0;i<6;i++) - etheraddr->a[i]= a[i]; + if (s < ETHER_ADDR_LEN) + return 0; - return 1; - } - } + if (ascii) { + if (sscanf(ascii, "%x:%x:%x:%x:%x:%x", &a[0], &a[1], &a[2], &a[3], &a[4], &a[5]) == 6) { + for (i = 0; i < 6; i++) + etheraddr->a[i] = a[i]; - return 0; -} + return 1; + } + } + return 0; +} /* * Function: find_ipv6_router_full() @@ -626,347 +616,340 @@ int ether_pton(const char *ascii, struct ether_addr *etheraddr, unsigned int s){ * Finds a local router (by means of Neighbor Discovery) */ -int find_ipv6_router_full(pcap_t *pfd, struct iface_data *idata){ - struct pcap_pkthdr *pkthdr; - struct bpf_program pcap_filter; - const u_char *pktdata; - struct ether_header *pkt_ether; - struct ip6_hdr *pkt_ipv6; - struct nd_router_advert *pkt_ra; - unsigned char *pkt_end; - unsigned char *prev_nh; - volatile unsigned char *ptr; - volatile unsigned char *p; - int nw; - - unsigned char buffer[65556]; - unsigned int rs_max_packet_size; - struct ether_header *ether; - unsigned char *v6buffer; - struct ip6_hdr *ipv6; - struct nd_router_solicit *rs; - struct nd_opt_slla *sllaopt; - struct nd_opt_prefix_info *pio; - volatile unsigned int tries=0; - volatile unsigned int foundrouter=0; - struct sigaction new_sig, old_sig; - unsigned char error_f=0; - int result; - - rs_max_packet_size = idata->mtu; - ether = (struct ether_header *) buffer; - v6buffer = buffer + sizeof(struct ether_header); - ipv6 = (struct ip6_hdr *) v6buffer; - - if(pcap_compile(pfd, &pcap_filter, PCAP_ICMPV6_RANS_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1){ - if(idata->verbose_f>1) - printf("pcap_compile(): %s", pcap_geterr(pfd)); - - return(-1); - } - - if(pcap_setfilter(pfd, &pcap_filter) == -1){ - if(idata->verbose_f > 1) - printf("pcap_setfilter(): %s", pcap_geterr(pfd)); - - return(-1); - } +int find_ipv6_router_full(pcap_t *pfd, struct iface_data *idata) { + struct pcap_pkthdr *pkthdr; + struct bpf_program pcap_filter; + const u_char *pktdata; + struct ether_header *pkt_ether; + struct ip6_hdr *pkt_ipv6; + struct nd_router_advert *pkt_ra; + unsigned char *pkt_end; + unsigned char *prev_nh; + volatile unsigned char *ptr; + volatile unsigned char *p; + int nw; + + unsigned char buffer[65556]; + unsigned int rs_max_packet_size; + struct ether_header *ether; + unsigned char *v6buffer; + struct ip6_hdr *ipv6; + struct nd_router_solicit *rs; + struct nd_opt_slla *sllaopt; + struct nd_opt_prefix_info *pio; + volatile unsigned int tries = 0; + volatile unsigned int foundrouter = 0; + struct sigaction new_sig, old_sig; + unsigned char error_f = 0; + int result; - pcap_freecode(&pcap_filter); - - ipv6->ip6_flow=0; - ipv6->ip6_vfc= 0x60; - ipv6->ip6_hlim= 255; - ipv6->ip6_src= idata->ip6_local; - - if ( inet_pton(AF_INET6, ALL_ROUTERS_MULTICAST_ADDR, &(ipv6->ip6_dst)) <= 0){ - if(idata->verbose_f>1) - puts("inet_pton(): Error converting All Routers address from presentation to network format"); - - return(-1); - } - - ether->src = idata->ether; - - if(ether_pton(ETHER_ALLROUTERS_LINK_ADDR, &(ether->dst), sizeof(struct ether_addr)) == 0){ - if(idata->verbose_f>1) - puts("ether_pton(): Error converting all-nodes multicast address"); - - return(-1); - } + rs_max_packet_size = idata->mtu; + ether = (struct ether_header *)buffer; + v6buffer = buffer + sizeof(struct ether_header); + ipv6 = (struct ip6_hdr *)v6buffer; - ether->ether_type = htons(ETHERTYPE_IPV6); - - prev_nh = (unsigned char *) &(ipv6->ip6_nxt); - *prev_nh = IPPROTO_ICMPV6; - - ptr = (unsigned char *) v6buffer + MIN_IPV6_HLEN; - - if( (ptr+sizeof(struct nd_router_solicit)) > (v6buffer+rs_max_packet_size)){ - if(idata->verbose_f>1) - puts("Packet too large while inserting Router Solicitation header"); - - return(-1); - } - - rs= (struct nd_router_solicit *) (ptr); - - rs->nd_rs_type = ND_ROUTER_SOLICIT; - rs->nd_rs_code = 0; - rs->nd_rs_reserved = 0; - - ptr += sizeof(struct nd_router_solicit); - sllaopt = (struct nd_opt_slla *) ptr; - - if( (ptr+sizeof(struct nd_opt_slla)) > (v6buffer+rs_max_packet_size)){ - if(idata->verbose_f>1) - puts("RS message too large while processing source link-layer address opt."); - - return(-1); - } - - sllaopt->type= ND_OPT_SOURCE_LINKADDR; - sllaopt->length= SLLA_OPT_LEN; - memcpy(sllaopt->address, &(idata->ether.a), ETH_ALEN); - ptr += sizeof(struct nd_opt_slla); - - ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); - rs->nd_rs_cksum = 0; - rs->nd_rs_cksum = in_chksum(v6buffer, rs, ptr-((unsigned char *)rs), IPPROTO_ICMPV6); - - /* We set the signal handler, and the anchor for siglongjump() */ - canjump=0; - memset(&new_sig, 0, sizeof(struct sigaction)); - sigemptyset(&new_sig.sa_mask); - new_sig.sa_handler= &sig_alarm; - - alarm(0); - - if( sigaction(SIGALRM, &new_sig, &old_sig) == -1){ - if(idata->verbose_f>1) - puts("Error setting up 'Alarm' signal"); - - return(-1); - } - - if(sigsetjmp(env, 1) != 0) - tries++; - - canjump=1; - - while(tries<3 && !foundrouter && !error_f){ - if((nw=pcap_inject(pfd, buffer, ptr - buffer)) == -1){ - if(idata->verbose_f>1) - printf("pcap_inject(): %s\n", pcap_geterr(pfd)); - - error_f=1; - break; - } - - if(nw != (ptr-buffer)){ - if(idata->verbose_f>1) - printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, \ - (LUI) (ptr-buffer)); + if (pcap_compile(pfd, &pcap_filter, PCAP_ICMPV6_RANS_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1) { + if (idata->verbose_f > 1) + printf("pcap_compile(): %s", pcap_geterr(pfd)); - error_f=1; - break; - } + return (-1); + } - alarm(idata->local_timeout + 1); - - while(!foundrouter && !error_f){ - - do{ - if( (result=pcap_next_ex(pfd, &pkthdr, &pktdata)) == -1){ - if(idata->verbose_f>1) - printf("pcap_next_ex(): %s", pcap_geterr(pfd)); - - error_f=1; - break; - } - }while(result == 0 || pktdata == NULL); - - if(error_f) - break; - - pkt_ether = (struct ether_header *) pktdata; - pkt_ipv6 = (struct ip6_hdr *)((char *) pkt_ether + ETHER_HDR_LEN); - pkt_ra = (struct nd_router_advert *) ((char *) pkt_ipv6 + MIN_IPV6_HLEN); - pkt_end = (unsigned char *) pktdata + pkthdr->caplen; - - - /* The packet length is the minimum of what we capured, and what is specified in the - IPv6 Total Lenght field - */ - if( pkt_end > ((unsigned char *)pkt_ra + ntohs(pkt_ipv6->ip6_plen)) ) - pkt_end = (unsigned char *)pkt_ra + ntohs(pkt_ipv6->ip6_plen); - - /* - Discard the packet if it is not of the minimum size to contain a Router Advertisement - message with a source link-layer address option - */ - if( (pkt_end - (unsigned char *) pkt_ra) < (sizeof(struct nd_router_advert) + \ - sizeof(struct nd_opt_slla))) - continue; - - /* - Neighbor Discovery packets must have a Hop Limit of 255 - */ - if(pkt_ipv6->ip6_hlim != 255) - continue; - - /* - Check that the IPv6 Source Address of the Router Advertisement is an IPv6 link-local - address. - */ - if(!IN6_IS_ADDR_LINKLOCAL(&(pkt_ipv6->ip6_src))) - continue; - - /* - Check that that the Destination Address of the Router Advertisement is either the one - that we used for sending the Router Solicitation message or a multicast address - (typically the all-nodes) - */ - if(!is_eq_in6_addr(&(pkt_ipv6->ip6_dst), &(ipv6->ip6_src)) \ - && !IN6_IS_ADDR_MULTICAST(&(pkt_ipv6->ip6_dst))) - continue; - - /* Check that the ICMPv6 checksum is correct. If the received checksum is valid, - and we compute the checksum over the received packet (including the Checksum field) - the result is 0. Otherwise, the packet has been corrupted. - */ - if(in_chksum(pkt_ipv6, pkt_ra, pkt_end- (unsigned char *)pkt_ra, IPPROTO_ICMPV6) != 0) - continue; - - p= (unsigned char *) pkt_ra + sizeof(struct nd_router_advert); - - /* Process Router Advertisement options */ - while( (p+ *(p+1) * 8) <= pkt_end && *(p+1)!=0 && !error_f){ - switch(*p){ - case ND_OPT_SOURCE_LINKADDR: - if( (*(p+1) * 8) != sizeof(struct nd_opt_tlla)) - break; - - /* Got a response, so we shouln't time out */ - alarm(0); - - /* Save the link-layer address */ - idata->router_ether = *(struct ether_addr *) (p+2); - idata->router_ip6= pkt_ipv6->ip6_src; - foundrouter=1; - break; - - case ND_OPT_PREFIX_INFORMATION: - if(*(p+1) != 4) - break; - - pio= (struct nd_opt_prefix_info *) p; - - if((idata->prefix_ol.nprefix) < idata->prefix_ol.maxprefix){ - if( (pio->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK) && \ - (pio->nd_opt_pi_prefix_len <= 128) && !is_ip6_in_prefix_list(&(pio->nd_opt_pi_prefix), \ - &(idata->prefix_ol))){ - - if( (idata->prefix_ol.prefix[idata->prefix_ol.nprefix] = \ - malloc(sizeof(struct prefix_entry))) == NULL){ - if(idata->verbose_f>1) - puts("Error in malloc() while learning prefixes"); - - error_f=1; - break; - } - - (idata->prefix_ol.prefix[idata->prefix_ol.nprefix])->ip6= pio->nd_opt_pi_prefix; - (idata->prefix_ol.prefix[idata->prefix_ol.nprefix])->len= pio->nd_opt_pi_prefix_len; - sanitize_ipv6_prefix(&((idata->prefix_ol.prefix[idata->prefix_ol.nprefix])->ip6), \ - (idata->prefix_ol.prefix[idata->prefix_ol.nprefix])->len); - (idata->prefix_ol.nprefix)++; - } - } - - /* - We expect the autoconfiguration prefix to have a length between 32 and 64 bits. - We used to require it to be 64-bits long, but some routers have been found to advertise - 48-bit long prefixes. Hence, we have relaxed the allowed length. - */ - if(idata->prefix_ac.nprefix < idata->prefix_ac.maxprefix){ - if( (pio->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO) && \ - (pio->nd_opt_pi_prefix_len >= 32 && pio->nd_opt_pi_prefix_len <= 64) && \ - !is_ip6_in_prefix_list(&(pio->nd_opt_pi_prefix), &(idata->prefix_ac))){ - - if((idata->prefix_ac.prefix[idata->prefix_ac.nprefix] = \ - malloc(sizeof(struct prefix_entry))) == NULL){ - if(idata->verbose_f>1) - puts("Error in malloc() while learning prefixes"); - - error_f=1; - break; - } - - (idata->prefix_ac.prefix[idata->prefix_ac.nprefix])->ip6= \ - pio->nd_opt_pi_prefix; - - /* - If the prefix is valid, we assume it to be 64-bit long. In the past, we used - the length advertised by pio->nd_opt_pi_prefix_len. - */ - (idata->prefix_ac.prefix[idata->prefix_ac.nprefix])->len= 64; - - sanitize_ipv6_prefix(&((idata->prefix_ac.prefix[idata->prefix_ac.nprefix])->ip6), \ - (idata->prefix_ac.prefix[idata->prefix_ac.nprefix])->len); - - if(!idata->ip6_global_flag && idata->ip6_global.nprefix < idata->ip6_global.maxprefix){ - - if( (idata->ip6_global.prefix[idata->ip6_global.nprefix] = \ - malloc(sizeof(struct prefix_entry))) == NULL){ - if(idata->verbose_f>1) - puts("Error in malloc() creating local SLAAC addresses"); - - error_f=1; - break; - } - - generate_slaac_address(&(idata->prefix_ac.prefix[idata->prefix_ac.nprefix]->ip6), \ - &(idata->ether), &((idata->ip6_global.prefix[idata->ip6_global.nprefix])->ip6)); - (idata->ip6_global.prefix[idata->ip6_global.nprefix])->len = 64; - (idata->ip6_global.nprefix)++; - } - (idata->prefix_ac.nprefix)++; - } - } - - break; - - default: - break; - } - - p= p + *(p+1) * 8; - } /* Processing options */ - - } /* Processing packets */ - - } /* Resending Router Solicitations */ - - /* If we added at least one global address, we set the corresponding flag to 1 */ - if(idata->ip6_global.nprefix) - idata->ip6_global_flag=1; - - if( sigaction(SIGALRM, &old_sig, NULL) == -1){ - if(idata->verbose_f>1) - puts("Error setting up 'Alarm' signal"); - - return(-1); - } - - if(foundrouter) - return 1; - else - return 0; -} + if (pcap_setfilter(pfd, &pcap_filter) == -1) { + if (idata->verbose_f > 1) + printf("pcap_setfilter(): %s", pcap_geterr(pfd)); + + return (-1); + } + + pcap_freecode(&pcap_filter); + + ipv6->ip6_flow = 0; + ipv6->ip6_vfc = 0x60; + ipv6->ip6_hlim = 255; + ipv6->ip6_src = idata->ip6_local; + + if (inet_pton(AF_INET6, ALL_ROUTERS_MULTICAST_ADDR, &(ipv6->ip6_dst)) <= 0) { + if (idata->verbose_f > 1) + puts("inet_pton(): Error converting All Routers address from presentation to network format"); + + return (-1); + } + + ether->src = idata->ether; + + if (ether_pton(ETHER_ALLROUTERS_LINK_ADDR, &(ether->dst), sizeof(struct ether_addr)) == 0) { + if (idata->verbose_f > 1) + puts("ether_pton(): Error converting all-nodes multicast address"); + + return (-1); + } + + ether->ether_type = htons(ETHERTYPE_IPV6); + + prev_nh = (unsigned char *)&(ipv6->ip6_nxt); + *prev_nh = IPPROTO_ICMPV6; + + ptr = (unsigned char *)v6buffer + MIN_IPV6_HLEN; + + if ((ptr + sizeof(struct nd_router_solicit)) > (v6buffer + rs_max_packet_size)) { + if (idata->verbose_f > 1) + puts("Packet too large while inserting Router Solicitation header"); + + return (-1); + } + + rs = (struct nd_router_solicit *)(ptr); + + rs->nd_rs_type = ND_ROUTER_SOLICIT; + rs->nd_rs_code = 0; + rs->nd_rs_reserved = 0; + + ptr += sizeof(struct nd_router_solicit); + sllaopt = (struct nd_opt_slla *)ptr; + + if ((ptr + sizeof(struct nd_opt_slla)) > (v6buffer + rs_max_packet_size)) { + if (idata->verbose_f > 1) + puts("RS message too large while processing source link-layer address opt."); + + return (-1); + } + + sllaopt->type = ND_OPT_SOURCE_LINKADDR; + sllaopt->length = SLLA_OPT_LEN; + memcpy(sllaopt->address, &(idata->ether.a), ETH_ALEN); + ptr += sizeof(struct nd_opt_slla); + + ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); + rs->nd_rs_cksum = 0; + rs->nd_rs_cksum = in_chksum(v6buffer, rs, ptr - ((unsigned char *)rs), IPPROTO_ICMPV6); + + /* We set the signal handler, and the anchor for siglongjump() */ + canjump = 0; + memset(&new_sig, 0, sizeof(struct sigaction)); + sigemptyset(&new_sig.sa_mask); + new_sig.sa_handler = &sig_alarm; + + alarm(0); + + if (sigaction(SIGALRM, &new_sig, &old_sig) == -1) { + if (idata->verbose_f > 1) + puts("Error setting up 'Alarm' signal"); + + return (-1); + } + if (sigsetjmp(env, 1) != 0) + tries++; + canjump = 1; + while (tries < 3 && !foundrouter && !error_f) { + if ((nw = pcap_inject(pfd, buffer, ptr - buffer)) == -1) { + if (idata->verbose_f > 1) + printf("pcap_inject(): %s\n", pcap_geterr(pfd)); + + error_f = 1; + break; + } + + if (nw != (ptr - buffer)) { + if (idata->verbose_f > 1) + printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, (LUI)(ptr - buffer)); + + error_f = 1; + break; + } + + alarm(idata->local_timeout + 1); + + while (!foundrouter && !error_f) { + + do { + if ((result = pcap_next_ex(pfd, &pkthdr, &pktdata)) == -1) { + if (idata->verbose_f > 1) + printf("pcap_next_ex(): %s", pcap_geterr(pfd)); + + error_f = 1; + break; + } + } while (result == 0 || pktdata == NULL); + + if (error_f) + break; + + pkt_ether = (struct ether_header *)pktdata; + pkt_ipv6 = (struct ip6_hdr *)((char *)pkt_ether + ETHER_HDR_LEN); + pkt_ra = (struct nd_router_advert *)((char *)pkt_ipv6 + MIN_IPV6_HLEN); + pkt_end = (unsigned char *)pktdata + pkthdr->caplen; + + /* The packet length is the minimum of what we capured, and what is specified in the + IPv6 Total Lenght field + */ + if (pkt_end > ((unsigned char *)pkt_ra + ntohs(pkt_ipv6->ip6_plen))) + pkt_end = (unsigned char *)pkt_ra + ntohs(pkt_ipv6->ip6_plen); + + /* + Discard the packet if it is not of the minimum size to contain a Router Advertisement + message with a source link-layer address option + */ + if ((pkt_end - (unsigned char *)pkt_ra) < (sizeof(struct nd_router_advert) + sizeof(struct nd_opt_slla))) + continue; + + /* + Neighbor Discovery packets must have a Hop Limit of 255 + */ + if (pkt_ipv6->ip6_hlim != 255) + continue; + + /* + Check that the IPv6 Source Address of the Router Advertisement is an IPv6 link-local + address. + */ + if (!IN6_IS_ADDR_LINKLOCAL(&(pkt_ipv6->ip6_src))) + continue; + + /* + Check that that the Destination Address of the Router Advertisement is either the one + that we used for sending the Router Solicitation message or a multicast address + (typically the all-nodes) + */ + if (!is_eq_in6_addr(&(pkt_ipv6->ip6_dst), &(ipv6->ip6_src)) && !IN6_IS_ADDR_MULTICAST(&(pkt_ipv6->ip6_dst))) + continue; + + /* Check that the ICMPv6 checksum is correct. If the received checksum is valid, + and we compute the checksum over the received packet (including the Checksum field) + the result is 0. Otherwise, the packet has been corrupted. + */ + if (in_chksum(pkt_ipv6, pkt_ra, pkt_end - (unsigned char *)pkt_ra, IPPROTO_ICMPV6) != 0) + continue; + + p = (unsigned char *)pkt_ra + sizeof(struct nd_router_advert); + + /* Process Router Advertisement options */ + while ((p + *(p + 1) * 8) <= pkt_end && *(p + 1) != 0 && !error_f) { + switch (*p) { + case ND_OPT_SOURCE_LINKADDR: + if ((*(p + 1) * 8) != sizeof(struct nd_opt_tlla)) + break; + + /* Got a response, so we shouln't time out */ + alarm(0); + + /* Save the link-layer address */ + idata->router_ether = *(struct ether_addr *)(p + 2); + idata->router_ip6 = pkt_ipv6->ip6_src; + foundrouter = 1; + break; + + case ND_OPT_PREFIX_INFORMATION: + if (*(p + 1) != 4) + break; + + pio = (struct nd_opt_prefix_info *)p; + + if ((idata->prefix_ol.nprefix) < idata->prefix_ol.maxprefix) { + if ((pio->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK) && + (pio->nd_opt_pi_prefix_len <= 128) && + !is_ip6_in_prefix_list(&(pio->nd_opt_pi_prefix), &(idata->prefix_ol))) { + + if ((idata->prefix_ol.prefix[idata->prefix_ol.nprefix] = + malloc(sizeof(struct prefix_entry))) == NULL) { + if (idata->verbose_f > 1) + puts("Error in malloc() while learning prefixes"); + + error_f = 1; + break; + } + + (idata->prefix_ol.prefix[idata->prefix_ol.nprefix])->ip6 = pio->nd_opt_pi_prefix; + (idata->prefix_ol.prefix[idata->prefix_ol.nprefix])->len = pio->nd_opt_pi_prefix_len; + sanitize_ipv6_prefix(&((idata->prefix_ol.prefix[idata->prefix_ol.nprefix])->ip6), + (idata->prefix_ol.prefix[idata->prefix_ol.nprefix])->len); + (idata->prefix_ol.nprefix)++; + } + } + + /* + We expect the autoconfiguration prefix to have a length between 32 and 64 bits. + We used to require it to be 64-bits long, but some routers have been found to advertise + 48-bit long prefixes. Hence, we have relaxed the allowed length. + */ + if (idata->prefix_ac.nprefix < idata->prefix_ac.maxprefix) { + if ((pio->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO) && + (pio->nd_opt_pi_prefix_len >= 32 && pio->nd_opt_pi_prefix_len <= 64) && + !is_ip6_in_prefix_list(&(pio->nd_opt_pi_prefix), &(idata->prefix_ac))) { + + if ((idata->prefix_ac.prefix[idata->prefix_ac.nprefix] = + malloc(sizeof(struct prefix_entry))) == NULL) { + if (idata->verbose_f > 1) + puts("Error in malloc() while learning prefixes"); + + error_f = 1; + break; + } + + (idata->prefix_ac.prefix[idata->prefix_ac.nprefix])->ip6 = pio->nd_opt_pi_prefix; + + /* + If the prefix is valid, we assume it to be 64-bit long. In the past, we used + the length advertised by pio->nd_opt_pi_prefix_len. + */ + (idata->prefix_ac.prefix[idata->prefix_ac.nprefix])->len = 64; + + sanitize_ipv6_prefix(&((idata->prefix_ac.prefix[idata->prefix_ac.nprefix])->ip6), + (idata->prefix_ac.prefix[idata->prefix_ac.nprefix])->len); + + if (!idata->ip6_global_flag && idata->ip6_global.nprefix < idata->ip6_global.maxprefix) { + + if ((idata->ip6_global.prefix[idata->ip6_global.nprefix] = + malloc(sizeof(struct prefix_entry))) == NULL) { + if (idata->verbose_f > 1) + puts("Error in malloc() creating local SLAAC addresses"); + + error_f = 1; + break; + } + + generate_slaac_address(&(idata->prefix_ac.prefix[idata->prefix_ac.nprefix]->ip6), + &(idata->ether), + &((idata->ip6_global.prefix[idata->ip6_global.nprefix])->ip6)); + (idata->ip6_global.prefix[idata->ip6_global.nprefix])->len = 64; + (idata->ip6_global.nprefix)++; + } + (idata->prefix_ac.nprefix)++; + } + } + + break; + + default: + break; + } + + p = p + *(p + 1) * 8; + } /* Processing options */ + + } /* Processing packets */ + + } /* Resending Router Solicitations */ + + /* If we added at least one global address, we set the corresponding flag to 1 */ + if (idata->ip6_global.nprefix) + idata->ip6_global_flag = 1; + + if (sigaction(SIGALRM, &old_sig, NULL) == -1) { + if (idata->verbose_f > 1) + puts("Error setting up 'Alarm' signal"); + + return (-1); + } + + if (foundrouter) + return 1; + else + return 0; +} /* * Function match_ipv6() @@ -974,434 +957,420 @@ int find_ipv6_router_full(pcap_t *pfd, struct iface_data *idata){ * Finds if an IPv6 address matches a prefix in a list of prefixes. */ -unsigned int match_ipv6(struct in6_addr *prefixlist, uint8_t *prefixlen, unsigned int nprefix, - struct in6_addr *ipv6addr){ +unsigned int match_ipv6(struct in6_addr *prefixlist, uint8_t *prefixlen, unsigned int nprefix, + struct in6_addr *ipv6addr) { - unsigned int i, j; - struct in6_addr dummyipv6_1, dummyipv6_2; - - for(i=0; ia[j] != addrlist[i].a[j]) - break; + for (i = 0; i < naddr; i++) { + for (j = 0; j < 6; j++) + if (linkaddr->a[j] != addrlist[i].a[j]) + break; - if(j==6) - return 1; - } + if (j == 6) + return 1; + } - return 0; + return 0; } - - -/* +/* * Function: in_chksum() * * Calculate the 16-bit ICMPv6 checksum */ -uint16_t in_chksum(void *ptr_ipv6, void *ptr_icmpv6, size_t len, uint8_t proto){ - struct ipv6pseudohdr pseudohdr; - struct ip6_hdr *v6packet; - size_t nleft; - unsigned int sum = 0; - uint16_t *w; - uint16_t answer = 0; - - v6packet=ptr_ipv6; - - memset(&pseudohdr, 0, sizeof(struct ipv6pseudohdr)); - pseudohdr.srcaddr= v6packet->ip6_src; - pseudohdr.dstaddr= v6packet->ip6_dst; - pseudohdr.len = htons(len); - pseudohdr.nh = proto; - - nleft=40; - w= (uint16_t *) &pseudohdr; - - while(nleft > 1){ - sum += *w++; - nleft -= 2; - } - - nleft= len; - w= (uint16_t *) ptr_icmpv6; - - while(nleft > 1){ - sum += *w++; - nleft -= 2; - } - - if(nleft == 1){ - *(unsigned char *) (&answer) = *(unsigned char *) w; - sum += answer; - } - - sum = (sum >> 16) + (sum & 0xffff); - sum += (sum >> 16); - answer = ~sum; - return(answer); +uint16_t in_chksum(void *ptr_ipv6, void *ptr_icmpv6, size_t len, uint8_t proto) { + struct ipv6pseudohdr pseudohdr; + struct ip6_hdr *v6packet; + size_t nleft; + unsigned int sum = 0; + uint16_t *w; + uint16_t answer = 0; + + v6packet = ptr_ipv6; + + memset(&pseudohdr, 0, sizeof(struct ipv6pseudohdr)); + pseudohdr.srcaddr = v6packet->ip6_src; + pseudohdr.dstaddr = v6packet->ip6_dst; + pseudohdr.len = htons(len); + pseudohdr.nh = proto; + + nleft = 40; + w = (uint16_t *)&pseudohdr; + + while (nleft > 1) { + sum += *w++; + nleft -= 2; + } + + nleft = len; + w = (uint16_t *)ptr_icmpv6; + + while (nleft > 1) { + sum += *w++; + nleft -= 2; + } + + if (nleft == 1) { + *(unsigned char *)(&answer) = *(unsigned char *)w; + sum += answer; + } + + sum = (sum >> 16) + (sum & 0xffff); + sum += (sum >> 16); + answer = ~sum; + return (answer); } - - /* * Function: inset_pad_opt() * * Insert a padding option (Pad1 or PadN) into an IPv6 extension header */ -int insert_pad_opt(unsigned char *ptrhdr, const unsigned char *ptrhdrend, unsigned int padn){ - unsigned char *ptr; - - if( (ptrhdrend - ptrhdr) < padn) - return 0; - - if(padn == 1){ - *ptrhdr= 0x00; - return 1; - } - else{ - ptr=ptrhdr; - *ptr= 0x01; - ptr++; - *ptr= padn-2; - ptr+=2; - - while(ptr < (ptrhdr+padn)){ - *ptr= 0x00; - ptr++; - } - return 1; - } +int insert_pad_opt(unsigned char *ptrhdr, const unsigned char *ptrhdrend, unsigned int padn) { + unsigned char *ptr; + + if ((ptrhdrend - ptrhdr) < padn) + return 0; + + if (padn == 1) { + *ptrhdr = 0x00; + return 1; + } + else { + ptr = ptrhdr; + *ptr = 0x01; + ptr++; + *ptr = padn - 2; + ptr += 2; + + while (ptr < (ptrhdr + padn)) { + *ptr = 0x00; + ptr++; + } + return 1; + } } - /* * Function: ipv6_to_ether() * * Obtains the Ethernet address corresponding to an IPv6 address (by means of Neighbor Discovery) */ -int ipv6_to_ether(pcap_t *pfd, struct iface_data *idata, struct in6_addr *targetaddr, struct ether_addr *result_ether){ - struct bpf_program pcap_filter; - struct pcap_pkthdr *pkthdr; - const u_char *pktdata; - struct ether_header *pkt_ether; - struct ip6_hdr *pkt_ipv6; - struct nd_neighbor_advert *pkt_na; - unsigned char *pkt_end, *prev_nh; - volatile unsigned char *ptr, *p; - - unsigned char buffer[65556]; - unsigned int ns_max_packet_size; - struct ether_header *ether; - unsigned char *v6buffer; - struct ip6_hdr *ipv6; - struct nd_neighbor_solicit *ns; - struct nd_opt_slla *sllaopt; - volatile unsigned int tries=0; - unsigned int foundaddr=0; - struct sigaction new_sig, old_sig; - int result; - unsigned char error_f=0; - int nw; - - ns_max_packet_size = idata->mtu; - - ether = (struct ether_header *) buffer; - v6buffer = buffer + sizeof(struct ether_header); - ipv6 = (struct ip6_hdr *) v6buffer; - - if(pcap_compile(idata->pfd, &pcap_filter, PCAP_ICMPV6_NA_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1){ - if(idata->verbose_f>1) - printf("pcap_compile(): %s", pcap_geterr(idata->pfd)); - - return(-1); - } - - if(pcap_setfilter(idata->pfd, &pcap_filter) == -1){ - if(idata->verbose_f>1) - printf("pcap_setfilter(): %s", pcap_geterr(idata->pfd)); - - return(-1); - } - - pcap_freecode(&pcap_filter); - - ipv6->ip6_flow=0; - ipv6->ip6_vfc= 0x60; - ipv6->ip6_hlim= 255; - ipv6->ip6_src= idata->ip6_local; - ipv6->ip6_dst= solicited_node(targetaddr); - - ether->src = idata->ether; - ether->dst = ether_multicast(&(ipv6->ip6_dst)); - ether->ether_type = htons(ETHERTYPE_IPV6); - - prev_nh = (unsigned char *) &(ipv6->ip6_nxt); - *prev_nh = IPPROTO_ICMPV6; - - ptr = (unsigned char *) v6buffer + MIN_IPV6_HLEN; - - if( (ptr+sizeof(struct nd_neighbor_solicit)) > (v6buffer+ns_max_packet_size)){ - if(idata->verbose_f>1) - puts("Packet too large while inserting Neighbor Solicitation header"); - - return(-1); - } - - ns= (struct nd_neighbor_solicit *) (ptr); - - ns->nd_ns_type = ND_NEIGHBOR_SOLICIT; - ns->nd_ns_code = 0; - ns->nd_ns_reserved = 0; - ns->nd_ns_target = *targetaddr; - - ptr += sizeof(struct nd_neighbor_solicit); - sllaopt = (struct nd_opt_slla *) ptr; - - if( (ptr+sizeof(struct nd_opt_slla)) > (v6buffer+ns_max_packet_size)){ - if(idata->verbose_f>1) - puts("NS message too large while processing source link-layer address opt."); - - return(-1); - } - - sllaopt->type= ND_OPT_SOURCE_LINKADDR; - sllaopt->length= SLLA_OPT_LEN; - memcpy(sllaopt->address, &(idata->ether.a), ETH_ALEN); - ptr += sizeof(struct nd_opt_slla); - - ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); - ns->nd_ns_cksum = 0; - ns->nd_ns_cksum = in_chksum(v6buffer, ns, ptr-((unsigned char *)ns), IPPROTO_ICMPV6); - - /* We set the signal handler, and the anchor for siglongjump() */ - canjump=0; - memset(&new_sig, 0, sizeof(struct sigaction)); - sigemptyset(&new_sig.sa_mask); - new_sig.sa_handler= &sig_alarm; - - alarm(0); - - if( sigaction(SIGALRM, &new_sig, &old_sig) == -1){ - if(idata->verbose_f>1) - puts("Error setting up 'Alarm' signal"); - - return(-1); - } - - if(sigsetjmp(env, 1) != 0) - tries++; - - canjump=1; - - while(tries<3 && !foundaddr && !error_f){ - if((nw=pcap_inject(idata->pfd, buffer, ptr - buffer)) == -1){ - if(idata->verbose_f>1) - printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); +int ipv6_to_ether(pcap_t *pfd, struct iface_data *idata, struct in6_addr *targetaddr, struct ether_addr *result_ether) { + struct bpf_program pcap_filter; + struct pcap_pkthdr *pkthdr; + const u_char *pktdata; + struct ether_header *pkt_ether; + struct ip6_hdr *pkt_ipv6; + struct nd_neighbor_advert *pkt_na; + unsigned char *pkt_end, *prev_nh; + volatile unsigned char *ptr, *p; + + unsigned char buffer[65556]; + unsigned int ns_max_packet_size; + struct ether_header *ether; + unsigned char *v6buffer; + struct ip6_hdr *ipv6; + struct nd_neighbor_solicit *ns; + struct nd_opt_slla *sllaopt; + volatile unsigned int tries = 0; + unsigned int foundaddr = 0; + struct sigaction new_sig, old_sig; + int result; + unsigned char error_f = 0; + int nw; + + ns_max_packet_size = idata->mtu; + + ether = (struct ether_header *)buffer; + v6buffer = buffer + sizeof(struct ether_header); + ipv6 = (struct ip6_hdr *)v6buffer; + + if (pcap_compile(idata->pfd, &pcap_filter, PCAP_ICMPV6_NA_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1) { + if (idata->verbose_f > 1) + printf("pcap_compile(): %s", pcap_geterr(idata->pfd)); + + return (-1); + } + + if (pcap_setfilter(idata->pfd, &pcap_filter) == -1) { + if (idata->verbose_f > 1) + printf("pcap_setfilter(): %s", pcap_geterr(idata->pfd)); + + return (-1); + } + + pcap_freecode(&pcap_filter); + + ipv6->ip6_flow = 0; + ipv6->ip6_vfc = 0x60; + ipv6->ip6_hlim = 255; + ipv6->ip6_src = idata->ip6_local; + ipv6->ip6_dst = solicited_node(targetaddr); + + ether->src = idata->ether; + ether->dst = ether_multicast(&(ipv6->ip6_dst)); + ether->ether_type = htons(ETHERTYPE_IPV6); + + prev_nh = (unsigned char *)&(ipv6->ip6_nxt); + *prev_nh = IPPROTO_ICMPV6; + + ptr = (unsigned char *)v6buffer + MIN_IPV6_HLEN; + + if ((ptr + sizeof(struct nd_neighbor_solicit)) > (v6buffer + ns_max_packet_size)) { + if (idata->verbose_f > 1) + puts("Packet too large while inserting Neighbor Solicitation header"); + + return (-1); + } + + ns = (struct nd_neighbor_solicit *)(ptr); + + ns->nd_ns_type = ND_NEIGHBOR_SOLICIT; + ns->nd_ns_code = 0; + ns->nd_ns_reserved = 0; + ns->nd_ns_target = *targetaddr; + + ptr += sizeof(struct nd_neighbor_solicit); + sllaopt = (struct nd_opt_slla *)ptr; + + if ((ptr + sizeof(struct nd_opt_slla)) > (v6buffer + ns_max_packet_size)) { + if (idata->verbose_f > 1) + puts("NS message too large while processing source link-layer address opt."); + + return (-1); + } + + sllaopt->type = ND_OPT_SOURCE_LINKADDR; + sllaopt->length = SLLA_OPT_LEN; + memcpy(sllaopt->address, &(idata->ether.a), ETH_ALEN); + ptr += sizeof(struct nd_opt_slla); + + ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); + ns->nd_ns_cksum = 0; + ns->nd_ns_cksum = in_chksum(v6buffer, ns, ptr - ((unsigned char *)ns), IPPROTO_ICMPV6); + + /* We set the signal handler, and the anchor for siglongjump() */ + canjump = 0; + memset(&new_sig, 0, sizeof(struct sigaction)); + sigemptyset(&new_sig.sa_mask); + new_sig.sa_handler = &sig_alarm; - error_f=1; - break; - } + alarm(0); + + if (sigaction(SIGALRM, &new_sig, &old_sig) == -1) { + if (idata->verbose_f > 1) + puts("Error setting up 'Alarm' signal"); - if(nw != (ptr-buffer)){ - if(idata->verbose_f>1) - printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, \ - (LUI) (ptr-buffer)); - error_f=1; - break; - } + return (-1); + } - alarm(idata->local_timeout); - - while(!foundaddr && !error_f){ - do{ - if( (result=pcap_next_ex(idata->pfd, &pkthdr, &pktdata)) == -1){ - if(idata->verbose_f>1) - printf("pcap_next_ex(): %s", pcap_geterr(pfd)); + if (sigsetjmp(env, 1) != 0) + tries++; - error_f=1; - break; - } - }while(result == 0 || pktdata == NULL); + canjump = 1; - if(error_f) - break; + while (tries < 3 && !foundaddr && !error_f) { + if ((nw = pcap_inject(idata->pfd, buffer, ptr - buffer)) == -1) { + if (idata->verbose_f > 1) + printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); + + error_f = 1; + break; + } + + if (nw != (ptr - buffer)) { + if (idata->verbose_f > 1) + printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, (LUI)(ptr - buffer)); + error_f = 1; + break; + } + + alarm(idata->local_timeout); + + while (!foundaddr && !error_f) { + do { + if ((result = pcap_next_ex(idata->pfd, &pkthdr, &pktdata)) == -1) { + if (idata->verbose_f > 1) + printf("pcap_next_ex(): %s", pcap_geterr(pfd)); + + error_f = 1; + break; + } + } while (result == 0 || pktdata == NULL); + + if (error_f) + break; #ifdef DEBUG - puts("DEBUG: ipv6_to_ether(): Got NA"); + puts("DEBUG: ipv6_to_ether(): Got NA"); #endif - pkt_ether = (struct ether_header *) pktdata; - pkt_ipv6 = (struct ip6_hdr *)((char *) pkt_ether + ETHER_HDR_LEN); - pkt_na = (struct nd_neighbor_advert *) ((char *) pkt_ipv6 + MIN_IPV6_HLEN); - pkt_end = (unsigned char *) pktdata + pkthdr->caplen; - - /* The packet length is the minimum of what we capured, and what is specified in the - IPv6 Total Lenght field - */ - if( pkt_end > ((unsigned char *)pkt_na + ntohs(pkt_ipv6->ip6_plen)) ) - pkt_end = (unsigned char *)pkt_na + ntohs(pkt_ipv6->ip6_plen); - - /* - Discard the packet if it is not of the minimum size to contain a Neighbor Advertisement - message with a source link-layer address option - */ - if( (pkt_end - (unsigned char *) pkt_na) < (sizeof(struct nd_neighbor_advert) + \ - sizeof(struct nd_opt_tlla))){ + pkt_ether = (struct ether_header *)pktdata; + pkt_ipv6 = (struct ip6_hdr *)((char *)pkt_ether + ETHER_HDR_LEN); + pkt_na = (struct nd_neighbor_advert *)((char *)pkt_ipv6 + MIN_IPV6_HLEN); + pkt_end = (unsigned char *)pktdata + pkthdr->caplen; + + /* The packet length is the minimum of what we capured, and what is specified in the + IPv6 Total Lenght field + */ + if (pkt_end > ((unsigned char *)pkt_na + ntohs(pkt_ipv6->ip6_plen))) + pkt_end = (unsigned char *)pkt_na + ntohs(pkt_ipv6->ip6_plen); + + /* + Discard the packet if it is not of the minimum size to contain a Neighbor Advertisement + message with a source link-layer address option + */ + if ((pkt_end - (unsigned char *)pkt_na) < + (sizeof(struct nd_neighbor_advert) + sizeof(struct nd_opt_tlla))) { #ifdef DEBUG - puts("DEBUG: ipv6_to_ether(): NA too small"); + puts("DEBUG: ipv6_to_ether(): NA too small"); #endif - continue; - } - /* - Neighbor Discovery packets must have a Hop Limit of 255 - */ - if(pkt_ipv6->ip6_hlim != 255){ + continue; + } + /* + Neighbor Discovery packets must have a Hop Limit of 255 + */ + if (pkt_ipv6->ip6_hlim != 255) { #ifdef DEBUG - puts("DEBUG: ipv6_to_ether(): NA Hop Limit != 255"); + puts("DEBUG: ipv6_to_ether(): NA Hop Limit != 255"); #endif - continue; - } - - /* - Check that that the Destination Address of the Neighbor Advertisement is the one - that we used for sending the Neighbor Solicitation message - */ - if(!is_eq_in6_addr(&(pkt_ipv6->ip6_dst), &(ipv6->ip6_src))){ + continue; + } + + /* + Check that that the Destination Address of the Neighbor Advertisement is the one + that we used for sending the Neighbor Solicitation message + */ + if (!is_eq_in6_addr(&(pkt_ipv6->ip6_dst), &(ipv6->ip6_src))) { #ifdef DEBUG - puts("DEBUG: ipv6_to_ether(): NA Dst != NS Src"); + puts("DEBUG: ipv6_to_ether(): NA Dst != NS Src"); #endif - continue; - } + continue; + } - /* Check that the ICMPv6 checksum is correct */ - if(in_chksum(pkt_ipv6, pkt_na, pkt_end-((unsigned char *)pkt_na), IPPROTO_ICMPV6) != 0){ + /* Check that the ICMPv6 checksum is correct */ + if (in_chksum(pkt_ipv6, pkt_na, pkt_end - ((unsigned char *)pkt_na), IPPROTO_ICMPV6) != 0) { #ifdef DEBUG - puts("DEBUG: ipv6_to_ether(): NA Checksum invalid"); + puts("DEBUG: ipv6_to_ether(): NA Checksum invalid"); #endif - continue; - } + continue; + } - /* Check that the ICMPv6 Target Address is the one we had asked for */ - if(!is_eq_in6_addr(&(pkt_na->nd_na_target), targetaddr)){ + /* Check that the ICMPv6 Target Address is the one we had asked for */ + if (!is_eq_in6_addr(&(pkt_na->nd_na_target), targetaddr)) { #ifdef DEBUG - puts("DEBUG: ipv6_to_ether(): NA Tgt != NS Tgt"); + puts("DEBUG: ipv6_to_ether(): NA Tgt != NS Tgt"); #endif - continue; - } + continue; + } - p= (unsigned char *) pkt_na + sizeof(struct nd_neighbor_advert); + p = (unsigned char *)pkt_na + sizeof(struct nd_neighbor_advert); - /* Process Neighbor Advertisement options */ - while( (p+sizeof(struct nd_opt_tlla)) <= pkt_end && (*(p+1) != 0)){ - if(*p == ND_OPT_TARGET_LINKADDR){ + /* Process Neighbor Advertisement options */ + while ((p + sizeof(struct nd_opt_tlla)) <= pkt_end && (*(p + 1) != 0)) { + if (*p == ND_OPT_TARGET_LINKADDR) { #ifdef DEBUG - puts("DEBUG: ipv6_to_ether(): Found TLLA in NA"); + puts("DEBUG: ipv6_to_ether(): Found TLLA in NA"); #endif - if( (*(p+1) * 8) != sizeof(struct nd_opt_tlla)) - break; + if ((*(p + 1) * 8) != sizeof(struct nd_opt_tlla)) + break; - /* Got a response, so we shouln't time out */ - alarm(0); + /* Got a response, so we shouln't time out */ + alarm(0); - /* Save the link-layer address */ - *result_ether= *(struct ether_addr *) (p+2); - foundaddr=1; - break; - } + /* Save the link-layer address */ + *result_ether = *(struct ether_addr *)(p + 2); + foundaddr = 1; + break; + } - p= p + *(p+1) * 8; - } /* Processing options */ + p = p + *(p + 1) * 8; + } /* Processing options */ - } /* Processing packets */ + } /* Processing packets */ - } /* Resending Neighbor Solicitations */ + } /* Resending Neighbor Solicitations */ - alarm(0); + alarm(0); - if( sigaction(SIGALRM, &old_sig, NULL) == -1){ - if(idata->verbose_f>1) - puts("Error setting up 'Alarm' signal"); + if (sigaction(SIGALRM, &old_sig, NULL) == -1) { + if (idata->verbose_f > 1) + puts("Error setting up 'Alarm' signal"); - return(-1); - } + return (-1); + } - if(foundaddr) - return 1; - else - return 0; + if (foundaddr) + return 1; + else + return 0; } - /* * Function: solicited_node() * * Obtains the Solicited-node multicast address corresponding to an IPv6 address. */ -struct in6_addr solicited_node(const struct in6_addr *ipv6addr){ - struct in6_addr solicited; +struct in6_addr solicited_node(const struct in6_addr *ipv6addr) { + struct in6_addr solicited; - solicited.s6_addr32[0]= htonl(0xff020000); - solicited.s6_addr32[1]= htonl(0); - solicited.s6_addr32[2]= htonl(0x00000001); - solicited.s6_addr32[3]= htonl(0xff000000) | ipv6addr->s6_addr32[3]; + solicited.s6_addr32[0] = htonl(0xff020000); + solicited.s6_addr32[1] = htonl(0); + solicited.s6_addr32[2] = htonl(0x00000001); + solicited.s6_addr32[3] = htonl(0xff000000) | ipv6addr->s6_addr32[3]; - return solicited; + return solicited; } - - /* * Function: is_eq_in6_addr() * * Compares two IPv6 addresses. Returns 0 if they are equal. */ -int is_eq_in6_addr(struct in6_addr *ip1, struct in6_addr *ip2){ - unsigned int i; +int is_eq_in6_addr(struct in6_addr *ip1, struct in6_addr *ip2) { + unsigned int i; - for(i=0; i<4; i++) - if(ip1->s6_addr32[i] != ip2->s6_addr32[i]) - return FALSE; + for (i = 0; i < 4; i++) + if (ip1->s6_addr32[i] != ip2->s6_addr32[i]) + return FALSE; - return TRUE; + return TRUE; } - - /* * Function: generate_slaac_address() * @@ -1409,362 +1378,358 @@ int is_eq_in6_addr(struct in6_addr *ip1, struct in6_addr *ip2){ * a IPv6 prefix and an Ethernet address. */ -void generate_slaac_address(struct in6_addr *prefix, struct ether_addr *etheraddr, struct in6_addr *ipv6addr){ - unsigned int i; +void generate_slaac_address(struct in6_addr *prefix, struct ether_addr *etheraddr, struct in6_addr *ipv6addr) { + unsigned int i; - for(i=0;i<2;i++) - ipv6addr->s6_addr32[i]= prefix->s6_addr32[i]; + for (i = 0; i < 2; i++) + ipv6addr->s6_addr32[i] = prefix->s6_addr32[i]; - ipv6addr->s6_addr[8]= etheraddr->a[0] | 0x02; - ipv6addr->s6_addr[9]= etheraddr->a[1]; - ipv6addr->s6_addr[10]= etheraddr->a[2]; - ipv6addr->s6_addr[11]= 0xff; - ipv6addr->s6_addr[12]= 0xfe; - ipv6addr->s6_addr[13]= etheraddr->a[3]; - ipv6addr->s6_addr[14]= etheraddr->a[4]; - ipv6addr->s6_addr[15]= etheraddr->a[5]; + ipv6addr->s6_addr[8] = etheraddr->a[0] | 0x02; + ipv6addr->s6_addr[9] = etheraddr->a[1]; + ipv6addr->s6_addr[10] = etheraddr->a[2]; + ipv6addr->s6_addr[11] = 0xff; + ipv6addr->s6_addr[12] = 0xfe; + ipv6addr->s6_addr[13] = etheraddr->a[3]; + ipv6addr->s6_addr[14] = etheraddr->a[4]; + ipv6addr->s6_addr[15] = etheraddr->a[5]; } - - /* * Function: get_if_addrs() * * Obtains Ethernet and IPv6 addresses of a network interface card */ -int get_if_addrs(struct iface_data *idata){ - struct ifaddrs *ifptr, *ptr; - struct sockaddr_in6 *sockin6ptr; +int get_if_addrs(struct iface_data *idata) { + struct ifaddrs *ifptr, *ptr; + struct sockaddr_in6 *sockin6ptr; #ifdef __linux__ - struct sockaddr_ll *sockpptr; -#elif defined (__FreeBSD__) || defined(__NetBSD__) || defined (__OpenBSD__) || defined(__APPLE__) || defined(__FreeBSD_kernel__) - struct sockaddr_dl *sockpptr; + struct sockaddr_ll *sockpptr; +#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) || \ + defined(__FreeBSD_kernel__) + struct sockaddr_dl *sockpptr; #endif - if(getifaddrs(&ifptr) != 0){ - if(idata->verbose_f > 1){ - printf("Error while learning addresses of the %s interface\n", idata->iface); - } - return(-1); - } + if (getifaddrs(&ifptr) != 0) { + if (idata->verbose_f > 1) { + printf("Error while learning addresses of the %s interface\n", idata->iface); + } + return (-1); + } - for(ptr=ifptr; ptr != NULL; ptr= ptr->ifa_next){ - if(ptr->ifa_addr == NULL) - continue; + for (ptr = ifptr; ptr != NULL; ptr = ptr->ifa_next) { + if (ptr->ifa_addr == NULL) + continue; #ifdef __linux__ - if( !(idata->ether_flag) && ((ptr->ifa_addr)->sa_family == AF_PACKET)){ - if(strncmp(idata->iface, ptr->ifa_name, IFACE_LENGTH) == 0){ - sockpptr = (struct sockaddr_ll *) (ptr->ifa_addr); - if(sockpptr->sll_halen == ETHER_ADDR_LEN){ - memcpy((idata->ether).a, sockpptr->sll_addr, ETHER_ADDR_LEN); - idata->ether_flag=TRUE; - } - } - } -#elif defined (__FreeBSD__) || defined(__NetBSD__) || defined (__OpenBSD__) || defined(__APPLE__) || defined(__FreeBSD_kernel__) - if( !(idata->ether_flag) && ((ptr->ifa_addr)->sa_family == AF_LINK)){ - if(strncmp(idata->iface, ptr->ifa_name, IFACE_LENGTH) == 0){ - sockpptr = (struct sockaddr_dl *) (ptr->ifa_addr); - if(sockpptr->sdl_alen == ETHER_ADDR_LEN){ - memcpy((idata->ether).a, (sockpptr->sdl_data + sockpptr->sdl_nlen), ETHER_ADDR_LEN); - idata->ether_flag=TRUE; - } - } - } + if (!(idata->ether_flag) && ((ptr->ifa_addr)->sa_family == AF_PACKET)) { + if (strncmp(idata->iface, ptr->ifa_name, IFACE_LENGTH) == 0) { + sockpptr = (struct sockaddr_ll *)(ptr->ifa_addr); + if (sockpptr->sll_halen == ETHER_ADDR_LEN) { + memcpy((idata->ether).a, sockpptr->sll_addr, ETHER_ADDR_LEN); + idata->ether_flag = TRUE; + } + } + } +#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) || \ + defined(__FreeBSD_kernel__) + if (!(idata->ether_flag) && ((ptr->ifa_addr)->sa_family == AF_LINK)) { + if (strncmp(idata->iface, ptr->ifa_name, IFACE_LENGTH) == 0) { + sockpptr = (struct sockaddr_dl *)(ptr->ifa_addr); + if (sockpptr->sdl_alen == ETHER_ADDR_LEN) { + memcpy((idata->ether).a, (sockpptr->sdl_data + sockpptr->sdl_nlen), ETHER_ADDR_LEN); + idata->ether_flag = TRUE; + } + } + } #endif - else if((ptr->ifa_addr)->sa_family == AF_INET6){ - sockin6ptr= (struct sockaddr_in6 *) (ptr->ifa_addr); - - if( !(idata->ip6_local_flag) && IN6_IS_ADDR_LINKLOCAL(&(sockin6ptr->sin6_addr))){ - if(strncmp(idata->iface, ptr->ifa_name, IFACE_LENGTH) == 0){ - idata->ip6_local = sockin6ptr->sin6_addr; -#if defined (__FreeBSD__) || defined(__NetBSD__) || defined (__OpenBSD__) || defined(__APPLE__) || defined(__FreeBSD_kernel__) - /* BSDs store the interface index in s6_addr16[1], so we must clear it */ - idata->ip6_local.s6_addr16[1] =0; - idata->ip6_local.s6_addr16[2] =0; - idata->ip6_local.s6_addr16[3] =0; + else if ((ptr->ifa_addr)->sa_family == AF_INET6) { + sockin6ptr = (struct sockaddr_in6 *)(ptr->ifa_addr); + + if (!(idata->ip6_local_flag) && IN6_IS_ADDR_LINKLOCAL(&(sockin6ptr->sin6_addr))) { + if (strncmp(idata->iface, ptr->ifa_name, IFACE_LENGTH) == 0) { + idata->ip6_local = sockin6ptr->sin6_addr; +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) || \ + defined(__FreeBSD_kernel__) + /* BSDs store the interface index in s6_addr16[1], so we must clear it */ + idata->ip6_local.s6_addr16[1] = 0; + idata->ip6_local.s6_addr16[2] = 0; + idata->ip6_local.s6_addr16[3] = 0; #endif - idata->ip6_local_flag= TRUE; - } - } - else if(!IN6_IS_ADDR_LINKLOCAL(&(sockin6ptr->sin6_addr))){ - if(strncmp(idata->iface, ptr->ifa_name, IFACE_LENGTH) == 0){ - if(IN6_IS_ADDR_LOOPBACK(&(sockin6ptr->sin6_addr))) - idata->flags = IFACE_LOOPBACK; - - if(!is_ip6_in_prefix_list( &(sockin6ptr->sin6_addr), &(idata->ip6_global))){ - if(idata->ip6_global.nprefix < idata->ip6_global.maxprefix){ - if( (idata->ip6_global.prefix[idata->ip6_global.nprefix] = \ - malloc(sizeof(struct prefix_entry))) == NULL){ - if(idata->verbose_f > 1) - puts("Error while storing Source Address"); - - freeifaddrs(ifptr); - return(-1); - } - - (idata->ip6_global.prefix[idata->ip6_global.nprefix])->len = 64; - (idata->ip6_global.prefix[idata->ip6_global.nprefix])->ip6 = sockin6ptr->sin6_addr; - idata->ip6_global.nprefix++; - idata->ip6_global_flag= TRUE; - } - } - } - } - } -/* else if((ptr->ifa_addr)->sa_family == AF_INET){ - if(strncmp(idata->iface, ptr->ifa_name, IFACE_LENGTH) == 0){ - idata->ip6_local = sockin6ptr->sin6_addr; - - } - } -*/ - } - - freeifaddrs(ifptr); - return(0); + idata->ip6_local_flag = TRUE; + } + } + else if (!IN6_IS_ADDR_LINKLOCAL(&(sockin6ptr->sin6_addr))) { + if (strncmp(idata->iface, ptr->ifa_name, IFACE_LENGTH) == 0) { + if (IN6_IS_ADDR_LOOPBACK(&(sockin6ptr->sin6_addr))) + idata->flags = IFACE_LOOPBACK; + + if (!is_ip6_in_prefix_list(&(sockin6ptr->sin6_addr), &(idata->ip6_global))) { + if (idata->ip6_global.nprefix < idata->ip6_global.maxprefix) { + if ((idata->ip6_global.prefix[idata->ip6_global.nprefix] = + malloc(sizeof(struct prefix_entry))) == NULL) { + if (idata->verbose_f > 1) + puts("Error while storing Source Address"); + + freeifaddrs(ifptr); + return (-1); + } + + (idata->ip6_global.prefix[idata->ip6_global.nprefix])->len = 64; + (idata->ip6_global.prefix[idata->ip6_global.nprefix])->ip6 = sockin6ptr->sin6_addr; + idata->ip6_global.nprefix++; + idata->ip6_global_flag = TRUE; + } + } + } + } + } + /* else if((ptr->ifa_addr)->sa_family == AF_INET){ + if(strncmp(idata->iface, ptr->ifa_name, IFACE_LENGTH) == 0){ + idata->ip6_local = sockin6ptr->sin6_addr; + + } + } + */ + } + + freeifaddrs(ifptr); + return (0); } - /* * Function: is_ip6_in_address_list() * * Checks whether an IPv6 address is present in an address list. */ -int is_ip6_in_address_list(struct prefix_list *plist, struct in6_addr *target){ - unsigned int i, j; +int is_ip6_in_address_list(struct prefix_list *plist, struct in6_addr *target) { + unsigned int i, j; - for(i=0; i < plist->nprefix; i++){ - for(j=0; j<4; j++){ - if(target->s6_addr32[j] != (plist->prefix[i])->ip6.s6_addr32[j]) - break; - } + for (i = 0; i < plist->nprefix; i++) { + for (j = 0; j < 4; j++) { + if (target->s6_addr32[j] != (plist->prefix[i])->ip6.s6_addr32[j]) + break; + } - if(j == 4) - return TRUE; - } + if (j == 4) + return TRUE; + } - return FALSE; + return FALSE; } - - - /* * Function: is_ip6_in_prefix_list() * * Checks whether an IPv6 address is present in an address list. */ -int is_ip6_in_prefix_list(struct in6_addr *target, struct prefix_list *plist){ - unsigned int i, j, full32, rest32; - uint32_t mask32; - - for(i=0; i < plist->nprefix; i++){ - full32=(plist->prefix[i])->len / 32; - rest32=(plist->prefix[i])->len % 32; - mask32 = 0xffffffff; - - for(j=0; j < full32; j++) - if(target->s6_addr32[j] != (plist->prefix[i])->ip6.s6_addr32[j]) - break; - - if(j == full32){ - if(rest32 == 0) - return TRUE; - else{ - mask32 = mask32 << (32 - rest32); - - if( (target->s6_addr32[full32] & htonl(mask32)) == ((plist->prefix[i])->ip6.s6_addr32[full32] & htonl(mask32))) - return TRUE; - } - } - } - - return FALSE; +int is_ip6_in_prefix_list(struct in6_addr *target, struct prefix_list *plist) { + unsigned int i, j, full32, rest32; + uint32_t mask32; + + for (i = 0; i < plist->nprefix; i++) { + full32 = (plist->prefix[i])->len / 32; + rest32 = (plist->prefix[i])->len % 32; + mask32 = 0xffffffff; + + for (j = 0; j < full32; j++) + if (target->s6_addr32[j] != (plist->prefix[i])->ip6.s6_addr32[j]) + break; + + if (j == full32) { + if (rest32 == 0) + return TRUE; + else { + mask32 = mask32 << (32 - rest32); + + if ((target->s6_addr32[full32] & htonl(mask32)) == + ((plist->prefix[i])->ip6.s6_addr32[full32] & htonl(mask32))) + return TRUE; + } + } + } + + return FALSE; } - /* * Function: is_time_elapsed() * * Checks whether a specific amount of time has elapsed. (i.e., whether curtime >= lastprobe + delta */ -int is_time_elapsed(struct timeval *curtime, struct timeval *lastprobe, unsigned long delta){ - if( curtime->tv_sec > (lastprobe->tv_sec + delta / 1000000) ){ - return(1); - }else if( curtime->tv_sec == (lastprobe->tv_sec + delta / 1000000)){ - if( curtime->tv_usec >= (lastprobe->tv_usec + delta % 1000000) ){ - return(1); - } - } - - return(0); +int is_time_elapsed(struct timeval *curtime, struct timeval *lastprobe, unsigned long delta) { + if (curtime->tv_sec > (lastprobe->tv_sec + delta / 1000000)) { + return (1); + } + else if (curtime->tv_sec == (lastprobe->tv_sec + delta / 1000000)) { + if (curtime->tv_usec >= (lastprobe->tv_usec + delta % 1000000)) { + return (1); + } + } + + return (0); } - /* * Function: print_filters() * * Prints the filters that will be applied to incoming packets. */ -void print_filters(struct iface_data *idata, struct filters *filters){ - unsigned int i; - char plinkaddr[ETHER_ADDR_PLEN]; - char pv6addr[INET6_ADDRSTRLEN]; - - if(filters->nblocksrc){ - printf("Block filter for IPv6 Source Address: "); - - for(i=0; i< filters->nblocksrc; i++){ - if(inet_ntop(AF_INET6, &(filters->blocksrc[i]), pv6addr, sizeof(pv6addr)) == NULL){ - puts("inet_ntop(): Error converting IPv6 Src. Addr. filter to presentation format"); - exit(EXIT_FAILURE); - } - - printf("%s/%u ", pv6addr, filters->blocksrclen[i]); - } - printf("\n"); - } - - if(filters->nblockdst){ - printf("Block filter for IPv6 Destination Address: "); - - for(i=0; i< filters->nblockdst; i++){ - if(inet_ntop(AF_INET6, &(filters->blockdst[i]), pv6addr, sizeof(pv6addr)) == NULL){ - puts("inet_ntop(): Error converting IPv6 Dst. Addr. filter to presentation format"); - exit(EXIT_FAILURE); - } - - printf("%s/%u ", pv6addr, filters->blockdstlen[i]); - } - printf("\n"); - } - - if(filters->nblocktarget){ - printf("Block filter for Target Address: "); - - for(i=0; i< filters->nblocktarget; i++){ - if(inet_ntop(AF_INET6, &(filters->blocktarget[i]), pv6addr, sizeof(pv6addr)) == NULL){ - puts("inet_ntop(): Error converting Target Addr. filter to presentation format"); - exit(EXIT_FAILURE); - } - - printf("%s/%u ", pv6addr, filters->blocktargetlen[i]); - } - printf("\n"); - } - - if(idata->type == DLT_EN10MB && !(idata->flags & IFACE_LOOPBACK)){ - if(filters->nblocklinksrc){ - printf("Block filter for link-layer Source Address: "); - - for(i=0; i < filters->nblocklinksrc; i++){ - if(ether_ntop(&(filters->blocklinksrc[i]), plinkaddr, sizeof(plinkaddr)) == 0){ - puts("ether_ntop(): Error converting address"); - exit(EXIT_FAILURE); - } - - printf("%s ", plinkaddr); - } - printf("\n"); - } - - if(filters->nblocklinkdst){ - printf("Block filter for link-layer Destination Address: "); - - for(i=0; i < filters->nblocklinkdst; i++){ - if(ether_ntop(&(filters->blocklinkdst[i]), plinkaddr, sizeof(plinkaddr)) == 0){ - puts("ether_ntop(): Error converting address"); - exit(EXIT_FAILURE); - } - - printf("%s ", plinkaddr); - } - printf("\n"); - } - } - - if(filters->nacceptsrc){ - printf("Accept filter for IPv6 Source Address: "); - - for(i=0; i < filters->nacceptsrc; i++){ - if(inet_ntop(AF_INET6, &(filters->acceptsrc[i]), pv6addr, sizeof(pv6addr)) == NULL){ - puts("inet_ntop(): Error converting IPv6 Src. Addr. filter to presentation format"); - exit(EXIT_FAILURE); - } - - printf("%s/%u ", pv6addr, filters->acceptsrclen[i]); - } - printf("\n"); - } - - if(filters->nacceptdst){ - printf("Accept filter for IPv6 Destination Address: "); - - for(i=0; i < filters->nacceptdst; i++){ - if(inet_ntop(AF_INET6, &(filters->acceptdst[i]), pv6addr, sizeof(pv6addr)) == NULL){ - puts("inet_ntop(): Error converting IPv6 Dst. Addr. filter to presentation format"); - exit(EXIT_FAILURE); - } - - printf("%s/%u ", pv6addr, filters->acceptdstlen[i]); - } - printf("\n"); - } - - if(filters->naccepttarget){ - printf("Accept filter for Target Address: "); - - for(i=0; i < filters->naccepttarget; i++){ - if(inet_ntop(AF_INET6, &(filters->accepttarget[i]), pv6addr, sizeof(pv6addr)) == NULL){ - puts("inet_ntop(): Error converting Target Addr. filter to presentation format"); - exit(EXIT_FAILURE); - } - - printf("%s/%u ", pv6addr, filters->accepttargetlen[i]); - } - printf("\n"); - } - - if(idata->type == DLT_EN10MB && !(idata->flags & IFACE_LOOPBACK)){ - if(filters->nacceptlinksrc){ - printf("Accept filter for link-layer Source Address: "); - - for(i=0; i < filters->nacceptlinksrc; i++){ - if(ether_ntop(&(filters->acceptlinksrc[i]), plinkaddr, sizeof(plinkaddr)) == 0){ - puts("ether_ntop(): Error converting address"); - exit(EXIT_FAILURE); - } - - printf("%s ", plinkaddr); - } - printf("\n"); - } - - if(filters->nacceptlinkdst){ - printf("Accept filter for link-layer Destination Address: "); - - for(i=0; i < filters->nacceptlinkdst; i++){ - if(ether_ntop(&(filters->acceptlinkdst[i]), plinkaddr, sizeof(plinkaddr)) == 0){ - puts("ether_ntop(): Error converting address"); - exit(EXIT_FAILURE); - } - - printf("%s ", plinkaddr); - } - printf("\n"); - } - } +void print_filters(struct iface_data *idata, struct filters *filters) { + unsigned int i; + char plinkaddr[ETHER_ADDR_PLEN]; + char pv6addr[INET6_ADDRSTRLEN]; + + if (filters->nblocksrc) { + printf("Block filter for IPv6 Source Address: "); + + for (i = 0; i < filters->nblocksrc; i++) { + if (inet_ntop(AF_INET6, &(filters->blocksrc[i]), pv6addr, sizeof(pv6addr)) == NULL) { + puts("inet_ntop(): Error converting IPv6 Src. Addr. filter to presentation format"); + exit(EXIT_FAILURE); + } + + printf("%s/%u ", pv6addr, filters->blocksrclen[i]); + } + printf("\n"); + } + + if (filters->nblockdst) { + printf("Block filter for IPv6 Destination Address: "); + + for (i = 0; i < filters->nblockdst; i++) { + if (inet_ntop(AF_INET6, &(filters->blockdst[i]), pv6addr, sizeof(pv6addr)) == NULL) { + puts("inet_ntop(): Error converting IPv6 Dst. Addr. filter to presentation format"); + exit(EXIT_FAILURE); + } + + printf("%s/%u ", pv6addr, filters->blockdstlen[i]); + } + printf("\n"); + } + + if (filters->nblocktarget) { + printf("Block filter for Target Address: "); + + for (i = 0; i < filters->nblocktarget; i++) { + if (inet_ntop(AF_INET6, &(filters->blocktarget[i]), pv6addr, sizeof(pv6addr)) == NULL) { + puts("inet_ntop(): Error converting Target Addr. filter to presentation format"); + exit(EXIT_FAILURE); + } + + printf("%s/%u ", pv6addr, filters->blocktargetlen[i]); + } + printf("\n"); + } + + if (idata->type == DLT_EN10MB && !(idata->flags & IFACE_LOOPBACK)) { + if (filters->nblocklinksrc) { + printf("Block filter for link-layer Source Address: "); + + for (i = 0; i < filters->nblocklinksrc; i++) { + if (ether_ntop(&(filters->blocklinksrc[i]), plinkaddr, sizeof(plinkaddr)) == 0) { + puts("ether_ntop(): Error converting address"); + exit(EXIT_FAILURE); + } + + printf("%s ", plinkaddr); + } + printf("\n"); + } + + if (filters->nblocklinkdst) { + printf("Block filter for link-layer Destination Address: "); + + for (i = 0; i < filters->nblocklinkdst; i++) { + if (ether_ntop(&(filters->blocklinkdst[i]), plinkaddr, sizeof(plinkaddr)) == 0) { + puts("ether_ntop(): Error converting address"); + exit(EXIT_FAILURE); + } + + printf("%s ", plinkaddr); + } + printf("\n"); + } + } + + if (filters->nacceptsrc) { + printf("Accept filter for IPv6 Source Address: "); + + for (i = 0; i < filters->nacceptsrc; i++) { + if (inet_ntop(AF_INET6, &(filters->acceptsrc[i]), pv6addr, sizeof(pv6addr)) == NULL) { + puts("inet_ntop(): Error converting IPv6 Src. Addr. filter to presentation format"); + exit(EXIT_FAILURE); + } + + printf("%s/%u ", pv6addr, filters->acceptsrclen[i]); + } + printf("\n"); + } + + if (filters->nacceptdst) { + printf("Accept filter for IPv6 Destination Address: "); + + for (i = 0; i < filters->nacceptdst; i++) { + if (inet_ntop(AF_INET6, &(filters->acceptdst[i]), pv6addr, sizeof(pv6addr)) == NULL) { + puts("inet_ntop(): Error converting IPv6 Dst. Addr. filter to presentation format"); + exit(EXIT_FAILURE); + } + + printf("%s/%u ", pv6addr, filters->acceptdstlen[i]); + } + printf("\n"); + } + + if (filters->naccepttarget) { + printf("Accept filter for Target Address: "); + + for (i = 0; i < filters->naccepttarget; i++) { + if (inet_ntop(AF_INET6, &(filters->accepttarget[i]), pv6addr, sizeof(pv6addr)) == NULL) { + puts("inet_ntop(): Error converting Target Addr. filter to presentation format"); + exit(EXIT_FAILURE); + } + + printf("%s/%u ", pv6addr, filters->accepttargetlen[i]); + } + printf("\n"); + } + + if (idata->type == DLT_EN10MB && !(idata->flags & IFACE_LOOPBACK)) { + if (filters->nacceptlinksrc) { + printf("Accept filter for link-layer Source Address: "); + + for (i = 0; i < filters->nacceptlinksrc; i++) { + if (ether_ntop(&(filters->acceptlinksrc[i]), plinkaddr, sizeof(plinkaddr)) == 0) { + puts("ether_ntop(): Error converting address"); + exit(EXIT_FAILURE); + } + + printf("%s ", plinkaddr); + } + printf("\n"); + } + + if (filters->nacceptlinkdst) { + printf("Accept filter for link-layer Destination Address: "); + + for (i = 0; i < filters->nacceptlinkdst; i++) { + if (ether_ntop(&(filters->acceptlinkdst[i]), plinkaddr, sizeof(plinkaddr)) == 0) { + puts("ether_ntop(): Error converting address"); + exit(EXIT_FAILURE); + } + + printf("%s ", plinkaddr); + } + printf("\n"); + } + } } - /* * Function: print_filter_result() * @@ -1772,170 +1737,161 @@ void print_filters(struct iface_data *idata, struct filters *filters){ * accepted by a filter. */ -void print_filter_result(struct iface_data *idata, const u_char *pkt_data, unsigned char fresult){ - struct ip6_hdr *pkt_ipv6; - char psrcaddr[INET6_ADDRSTRLEN], pdstaddr[INET6_ADDRSTRLEN]; - - pkt_ipv6 = (struct ip6_hdr *)((char *) pkt_data + idata->linkhsize); +void print_filter_result(struct iface_data *idata, const u_char *pkt_data, unsigned char fresult) { + struct ip6_hdr *pkt_ipv6; + char psrcaddr[INET6_ADDRSTRLEN], pdstaddr[INET6_ADDRSTRLEN]; - if(inet_ntop(AF_INET6, &(pkt_ipv6->ip6_src), psrcaddr, sizeof(psrcaddr)) == NULL){ - puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); - exit(EXIT_FAILURE); - } + pkt_ipv6 = (struct ip6_hdr *)((char *)pkt_data + idata->linkhsize); - if(inet_ntop(AF_INET6, &(pkt_ipv6->ip6_dst), pdstaddr, sizeof(pdstaddr)) == NULL){ - puts("inet_ntop(): Error converting IPv6 Destination Address to presentation format"); - exit(EXIT_FAILURE); - } + if (inet_ntop(AF_INET6, &(pkt_ipv6->ip6_src), psrcaddr, sizeof(psrcaddr)) == NULL) { + puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); + exit(EXIT_FAILURE); + } - printf("Received IPv6 packet from %s to %s (%s)\n", psrcaddr, pdstaddr, \ - ((fresult == ACCEPTED)?"accepted":"blocked") ); + if (inet_ntop(AF_INET6, &(pkt_ipv6->ip6_dst), pdstaddr, sizeof(pdstaddr)) == NULL) { + puts("inet_ntop(): Error converting IPv6 Destination Address to presentation format"); + exit(EXIT_FAILURE); + } + printf("Received IPv6 packet from %s to %s (%s)\n", psrcaddr, pdstaddr, + ((fresult == ACCEPTED) ? "accepted" : "blocked")); } - - /* * randomize_ether_addr() * * Select a random Ethernet address. */ -void randomize_ether_addr(struct ether_addr *ethaddr){ - unsigned int i; +void randomize_ether_addr(struct ether_addr *ethaddr) { + unsigned int i; - for(i=0; i<6; i++) - ethaddr->a[i]= random(); + for (i = 0; i < 6; i++) + ethaddr->a[i] = random(); - ethaddr->a[0]= (ethaddr->a[0] & 0xfc) | 0x02; + ethaddr->a[0] = (ethaddr->a[0] & 0xfc) | 0x02; } - /* * randomize_ipv6_addr() * * Select a random IPv6 from a given prefix. */ -void randomize_ipv6_addr(struct in6_addr *ipv6addr, const struct in6_addr *prefix, uint8_t preflen){ - uint32_t mask; - uint8_t startrand; - unsigned int i; - struct in6_addr ripv6addr; +void randomize_ipv6_addr(struct in6_addr *ipv6addr, const struct in6_addr *prefix, uint8_t preflen) { + uint32_t mask; + uint8_t startrand; + unsigned int i; + struct in6_addr ripv6addr; - startrand= preflen/32; + startrand = preflen / 32; - /* 32-bit words from prefix that must be copied entirely into randomized address */ - for(i=0; i < startrand; i++) - ripv6addr.s6_addr32[i]= prefix->s6_addr32[i]; + /* 32-bit words from prefix that must be copied entirely into randomized address */ + for (i = 0; i < startrand; i++) + ripv6addr.s6_addr32[i] = prefix->s6_addr32[i]; - /* 32-bit word (if any) that must be partially randomized */ - if(preflen%32){ - mask=0xffffffff; - mask= mask>>(preflen%32); + /* 32-bit word (if any) that must be partially randomized */ + if (preflen % 32) { + mask = 0xffffffff; + mask = mask >> (preflen % 32); - ripv6addr.s6_addr32[startrand]= (prefix->s6_addr32[startrand] & htonl(~mask)) | \ - (random() & htonl(mask)) ; - startrand++; - } + ripv6addr.s6_addr32[startrand] = (prefix->s6_addr32[startrand] & htonl(~mask)) | (random() & htonl(mask)); + startrand++; + } - for(i=startrand; i<4; i++) - ripv6addr.s6_addr32[i]=random(); + for (i = startrand; i < 4; i++) + ripv6addr.s6_addr32[i] = random(); - *ipv6addr= ripv6addr; + *ipv6addr = ripv6addr; } - /* * randomize_port() * * Select a random port from a given port/mask */ -void randomize_port(uint16_t *port, uint16_t prefix, uint8_t preflen){ - uint32_t mask; +void randomize_port(uint16_t *port, uint16_t prefix, uint8_t preflen) { + uint32_t mask; - mask= 0x10000; - mask= mask >> preflen; + mask = 0x10000; + mask = mask >> preflen; - sanitize_port(&prefix, preflen); + sanitize_port(&prefix, preflen); - *port= (uint16_t) (prefix + random() % mask); + *port = (uint16_t)(prefix + random() % mask); } - /* * release_privileges() * * Releases superuser privileges by switching to the real uid and gid, or to nobody */ -void release_privileges(void){ - uid_t ruid; - gid_t rgid; - struct passwd *pwdptr; - - /* - If the real UID is not root, we setuid() and setgid() to that user and group, releasing superuser - privileges. Otherwise, if the real UID is 0, we try to setuid() to "nobody", releasing superuser - privileges. - */ - if( (ruid=getuid()) && (rgid=getgid())){ - if(setgid(rgid) == -1){ - puts("Error while releasing superuser privileges (changing to real GID)"); - exit(EXIT_FAILURE); - } - - if(setuid(ruid) == -1){ - puts("Error while releasing superuser privileges (changing to real UID)"); - exit(EXIT_FAILURE); - } - } - else{ - if((pwdptr=getpwnam("nobody"))){ - if(!pwdptr->pw_uid || !pwdptr->pw_gid){ - puts("User 'nobody' has incorrect privileges"); - exit(EXIT_FAILURE); - } - - if(setgid(pwdptr->pw_gid) == -1){ - puts("Error while releasing superuser privileges (changing to nobody's group)"); - exit(EXIT_FAILURE); - } - - if(setuid(pwdptr->pw_uid) == -1){ - puts("Error while releasing superuser privileges (changing to 'nobody')"); - exit(EXIT_FAILURE); - } - } - } +void release_privileges(void) { + uid_t ruid; + gid_t rgid; + struct passwd *pwdptr; + + /* + If the real UID is not root, we setuid() and setgid() to that user and group, releasing superuser + privileges. Otherwise, if the real UID is 0, we try to setuid() to "nobody", releasing superuser + privileges. + */ + if ((ruid = getuid()) && (rgid = getgid())) { + if (setgid(rgid) == -1) { + puts("Error while releasing superuser privileges (changing to real GID)"); + exit(EXIT_FAILURE); + } + + if (setuid(ruid) == -1) { + puts("Error while releasing superuser privileges (changing to real UID)"); + exit(EXIT_FAILURE); + } + } + else { + if ((pwdptr = getpwnam("nobody"))) { + if (!pwdptr->pw_uid || !pwdptr->pw_gid) { + puts("User 'nobody' has incorrect privileges"); + exit(EXIT_FAILURE); + } + + if (setgid(pwdptr->pw_gid) == -1) { + puts("Error while releasing superuser privileges (changing to nobody's group)"); + exit(EXIT_FAILURE); + } + + if (setuid(pwdptr->pw_uid) == -1) { + puts("Error while releasing superuser privileges (changing to 'nobody')"); + exit(EXIT_FAILURE); + } + } + } } - /* * sanitize_ipv6_prefix() * * Clears those bits in an IPv6 address that are not within a prefix length. */ -void sanitize_ipv6_prefix(struct in6_addr *ipv6addr, uint8_t prefixlen){ - unsigned int skip, i; - uint32_t mask; - - skip= (prefixlen+31)/32; - - if(prefixlen%32){ - mask=0; - for(i=0; i<(prefixlen%32); i++) - mask= (mask>>1) | 0x80000000; - - ipv6addr->s6_addr32[skip-1]= ipv6addr->s6_addr32[skip-1] & htonl(mask); - } - - for(i=skip;i<4;i++) - ipv6addr->s6_addr32[i]=0; -} +void sanitize_ipv6_prefix(struct in6_addr *ipv6addr, uint8_t prefixlen) { + unsigned int skip, i; + uint32_t mask; + + skip = (prefixlen + 31) / 32; + + if (prefixlen % 32) { + mask = 0; + for (i = 0; i < (prefixlen % 32); i++) + mask = (mask >> 1) | 0x80000000; + ipv6addr->s6_addr32[skip - 1] = ipv6addr->s6_addr32[skip - 1] & htonl(mask); + } + + for (i = skip; i < 4; i++) + ipv6addr->s6_addr32[i] = 0; +} /* * sanitize_port() @@ -1943,15 +1899,14 @@ void sanitize_ipv6_prefix(struct in6_addr *ipv6addr, uint8_t prefixlen){ * Clears those bits in a transport port that are not within a port mas. */ -void sanitize_port(uint16_t *port, uint8_t prefixlen){ - uint16_t mask; +void sanitize_port(uint16_t *port, uint8_t prefixlen) { + uint16_t mask; - mask= 0xffff; - mask= mask << (16 - prefixlen); - - *port = *port & mask; -} + mask = 0xffff; + mask = mask << (16 - prefixlen); + *port = *port & mask; +} /* * Handler for the ALARM signal. @@ -1959,421 +1914,412 @@ void sanitize_port(uint16_t *port, uint8_t prefixlen){ * Used for setting a timeout on libpcap reads */ -void sig_alarm(int num){ - if(canjump == 0) - return; +void sig_alarm(int num) { + if (canjump == 0) + return; - siglongjmp(env, 1); + siglongjmp(env, 1); } - /* * Function: src_addr_sel2() * * Selects a Source Address for a given Destination Address (old function) */ -struct in6_addr *sel_src_addr_ra(struct iface_data *idata, struct in6_addr *dst){ - uint32_t mask32; - unsigned int i, j, full32, rest32; - /* - If the destination address is a link-local address, we select our link-local - address as the Source Address. If the dst address is a global unicast address - we select our first matching address, or else our first global address. - Worst case scenario, we don't have global address and must use our link-local - address. - */ - if(IN6_IS_ADDR_LINKLOCAL(dst)){ - return( &(idata->ip6_local)); - } - else if(IN6_IS_ADDR_MC_LINKLOCAL(dst) || IN6_IS_ADDR_LINKLOCAL(dst)){ - return( &(idata->ip6_local)); - } - else if(idata->ip6_global_flag){ - for(i=0; i < idata->ip6_global.nprefix; i++){ - full32=(idata->ip6_global.prefix[i])->len / 32; - rest32=(idata->ip6_global.prefix[i])->len % 32; - mask32 = 0xffffffff; - - for(j=0; j < full32; j++) - if( dst->s6_addr32[j] != (idata->ip6_global.prefix[i])->ip6.s6_addr32[j]) - break; - - if( (j == full32) && rest32){ - mask32 = mask32 << (32 - rest32); - - if( (dst->s6_addr32[full32] & htonl(mask32)) == ((idata->ip6_global.prefix[i])->ip6.s6_addr32[full32] & htonl(mask32))) - return( &((idata->ip6_global.prefix[i])->ip6)); - } - } - - return( &((idata->ip6_global.prefix[0])->ip6)); - } - - /* else */ - return( &(idata->ip6_local)); +struct in6_addr *sel_src_addr_ra(struct iface_data *idata, struct in6_addr *dst) { + uint32_t mask32; + unsigned int i, j, full32, rest32; + /* + If the destination address is a link-local address, we select our link-local + address as the Source Address. If the dst address is a global unicast address + we select our first matching address, or else our first global address. + Worst case scenario, we don't have global address and must use our link-local + address. + */ + if (IN6_IS_ADDR_LINKLOCAL(dst)) { + return (&(idata->ip6_local)); + } + else if (IN6_IS_ADDR_MC_LINKLOCAL(dst) || IN6_IS_ADDR_LINKLOCAL(dst)) { + return (&(idata->ip6_local)); + } + else if (idata->ip6_global_flag) { + for (i = 0; i < idata->ip6_global.nprefix; i++) { + full32 = (idata->ip6_global.prefix[i])->len / 32; + rest32 = (idata->ip6_global.prefix[i])->len % 32; + mask32 = 0xffffffff; + + for (j = 0; j < full32; j++) + if (dst->s6_addr32[j] != (idata->ip6_global.prefix[i])->ip6.s6_addr32[j]) + break; + + if ((j == full32) && rest32) { + mask32 = mask32 << (32 - rest32); + + if ((dst->s6_addr32[full32] & htonl(mask32)) == + ((idata->ip6_global.prefix[i])->ip6.s6_addr32[full32] & htonl(mask32))) + return (&((idata->ip6_global.prefix[i])->ip6)); + } + } + + return (&((idata->ip6_global.prefix[0])->ip6)); + } + + /* else */ + return (&(idata->ip6_local)); } - - - /* * Function: send_neighbor_advertisement() * * Send a Neighbor advertisement in response to a Neighbor Solicitation message */ -int send_neighbor_advert(struct iface_data *idata, pcap_t *pfd, const u_char *pktdata){ - unsigned int i; - int nw; - struct ether_header *pkt_ether; - struct ip6_hdr *pkt_ipv6; - struct nd_neighbor_solicit *pkt_ns; - unsigned char *ptr; - struct ether_header *ethernet; - unsigned char *v6buffer; - struct ip6_hdr *ipv6; - struct nd_neighbor_advert *na; - struct nd_opt_tlla *tllaopt; - struct in6_addr *pkt_ipv6addr; - unsigned char wbuffer[2500]; - - if(idata->mtu > sizeof(wbuffer)){ - if(idata->verbose_f) - puts("send_neighbor_advert(): Internal buffer too small"); - - return(-1); - } - - ethernet= (struct ether_header *) wbuffer; - v6buffer = (unsigned char *) ethernet + sizeof(struct ether_header); - ipv6 = (struct ip6_hdr *) v6buffer; - na= (struct nd_neighbor_advert *) ((char *) v6buffer + MIN_IPV6_HLEN); - ptr = (unsigned char *) na; - - pkt_ether = (struct ether_header *) pktdata; - pkt_ipv6 = (struct ip6_hdr *)((char *) pkt_ether + ETHER_HDR_LEN); - pkt_ns = (struct nd_neighbor_solicit *) ((char *) pkt_ipv6 + MIN_IPV6_HLEN); - - ethernet->ether_type = htons(ETHERTYPE_IPV6); - ipv6->ip6_flow=0; - ipv6->ip6_vfc= 0x60; - ipv6->ip6_hlim= 255; - ipv6->ip6_nxt= IPPROTO_ICMPV6; - - if( (ptr+sizeof(struct nd_neighbor_advert)) > (v6buffer+idata->mtu)){ - if(idata->verbose_f) - puts("send_neighbor_advert(): Packet too large when sending Neighbor Advertisement"); - - return(-1); - } - - na->nd_na_type = ND_NEIGHBOR_ADVERT; - na->nd_na_code = 0; - ptr += sizeof(struct nd_neighbor_advert); - - if( (ptr+sizeof(struct nd_opt_tlla)) <= (v6buffer+idata->mtu) ){ - tllaopt = (struct nd_opt_tlla *) ptr; - tllaopt->type= ND_OPT_TARGET_LINKADDR; - tllaopt->length= TLLA_OPT_LEN; - memcpy(tllaopt->address, idata->ether.a, ETH_ALEN); - ptr += sizeof(struct nd_opt_tlla); - } - else{ - if(idata->verbose_f) - puts("send_neighbor_advert(): Packet Too Large while inserting TLLA option in NA message"); - - return(-1); - } - - /* If the IPv6 Source Address of the incoming Neighbor Solicitation is the unspecified - address (::), the Neighbor Advertisement must be directed to the IPv6 all-nodes - multicast address (and the Ethernet Destination address should be 33:33:33:00:00:01). - Otherwise, the Neighbor Advertisement is sent to the IPv6 Source Address (and - Ethernet Source Address) of the incoming Neighbor Solicitation message - */ - pkt_ipv6addr = &(pkt_ipv6->ip6_src); - - if(IN6_IS_ADDR_UNSPECIFIED(pkt_ipv6addr)){ - na->nd_na_flags_reserved = 0; - - if ( inet_pton(AF_INET6, ALL_NODES_MULTICAST_ADDR, &(ipv6->ip6_dst)) <= 0){ - if(idata->verbose_f) - puts("send_neighbor_advert(): Error converting all-nodes multicast address"); - - return(-1); - } - - if(ether_pton(ETHER_ALLNODES_LINK_ADDR, &(ethernet->dst), ETHER_ADDR_LEN) == 0){ - if(idata->verbose_f) - puts("send_neighbor_advert(): Error converting all-nodes link-local address"); - - return(-1); - } - } - else{ - ipv6->ip6_dst = pkt_ipv6->ip6_src; - ethernet->dst = pkt_ether->src; - - /* - Set the "Solicited" flag if NS was sent from an address other than the unspecified - address (i.e., the response will be unicast). - */ - - na->nd_na_flags_reserved = ND_NA_FLAG_OVERRIDE | ND_NA_FLAG_SOLICITED; - } - - ethernet->src = idata->ether; - - /* - If the Neighbor Solicitation message was directed to one of our unicast addresses, the IPv6 Source - Address is set to that address. Otherwise, we set the IPv6 Source Address to our link-local address. - */ - - pkt_ipv6addr = &(pkt_ipv6->ip6_dst); - - if(IN6_IS_ADDR_MULTICAST(pkt_ipv6addr)){ - ipv6->ip6_src = idata->ip6_local; - } - else{ - if(is_eq_in6_addr(pkt_ipv6addr, &(idata->ip6_local))){ - ipv6->ip6_src = idata->ip6_local; - } - else if(idata->ip6_global_flag){ - for(i=0; i < idata->ip6_global.nprefix; i++){ - if(is_eq_in6_addr(pkt_ipv6addr, &((idata->ip6_global.prefix[i])->ip6))){ - ipv6->ip6_src = (idata->ip6_global.prefix[i])->ip6; - break; - } - } - - if(i == idata->ip6_global.nprefix) - return 0; - } - else{ - return 0; - } - } - - na->nd_na_target= pkt_ns->nd_ns_target; - - na->nd_na_cksum = 0; - na->nd_na_cksum = in_chksum(v6buffer, na, ptr-((unsigned char *)na), IPPROTO_ICMPV6); - - ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); - - if((nw=pcap_inject(pfd, wbuffer, ptr - wbuffer)) == -1){ - if(idata->verbose_f) - printf("send_neighbor_advert(): pcap_inject(): %s", pcap_geterr(pfd)); - - return(-1); - } - - if(nw != (ptr-wbuffer)){ - if(idata->verbose_f) - printf("send_neighbor_advert(): pcap_inject(): only wrote %d bytes " - "(rather than %lu bytes)\n", nw, (LUI) (ptr-wbuffer)); - - return(-1); - } - - return 0; +int send_neighbor_advert(struct iface_data *idata, pcap_t *pfd, const u_char *pktdata) { + unsigned int i; + int nw; + struct ether_header *pkt_ether; + struct ip6_hdr *pkt_ipv6; + struct nd_neighbor_solicit *pkt_ns; + unsigned char *ptr; + struct ether_header *ethernet; + unsigned char *v6buffer; + struct ip6_hdr *ipv6; + struct nd_neighbor_advert *na; + struct nd_opt_tlla *tllaopt; + struct in6_addr *pkt_ipv6addr; + unsigned char wbuffer[2500]; + + if (idata->mtu > sizeof(wbuffer)) { + if (idata->verbose_f) + puts("send_neighbor_advert(): Internal buffer too small"); + + return (-1); + } + + ethernet = (struct ether_header *)wbuffer; + v6buffer = (unsigned char *)ethernet + sizeof(struct ether_header); + ipv6 = (struct ip6_hdr *)v6buffer; + na = (struct nd_neighbor_advert *)((char *)v6buffer + MIN_IPV6_HLEN); + ptr = (unsigned char *)na; + + pkt_ether = (struct ether_header *)pktdata; + pkt_ipv6 = (struct ip6_hdr *)((char *)pkt_ether + ETHER_HDR_LEN); + pkt_ns = (struct nd_neighbor_solicit *)((char *)pkt_ipv6 + MIN_IPV6_HLEN); + + ethernet->ether_type = htons(ETHERTYPE_IPV6); + ipv6->ip6_flow = 0; + ipv6->ip6_vfc = 0x60; + ipv6->ip6_hlim = 255; + ipv6->ip6_nxt = IPPROTO_ICMPV6; + + if ((ptr + sizeof(struct nd_neighbor_advert)) > (v6buffer + idata->mtu)) { + if (idata->verbose_f) + puts("send_neighbor_advert(): Packet too large when sending Neighbor Advertisement"); + + return (-1); + } + + na->nd_na_type = ND_NEIGHBOR_ADVERT; + na->nd_na_code = 0; + ptr += sizeof(struct nd_neighbor_advert); + + if ((ptr + sizeof(struct nd_opt_tlla)) <= (v6buffer + idata->mtu)) { + tllaopt = (struct nd_opt_tlla *)ptr; + tllaopt->type = ND_OPT_TARGET_LINKADDR; + tllaopt->length = TLLA_OPT_LEN; + memcpy(tllaopt->address, idata->ether.a, ETH_ALEN); + ptr += sizeof(struct nd_opt_tlla); + } + else { + if (idata->verbose_f) + puts("send_neighbor_advert(): Packet Too Large while inserting TLLA option in NA message"); + + return (-1); + } + + /* If the IPv6 Source Address of the incoming Neighbor Solicitation is the unspecified + address (::), the Neighbor Advertisement must be directed to the IPv6 all-nodes + multicast address (and the Ethernet Destination address should be 33:33:33:00:00:01). + Otherwise, the Neighbor Advertisement is sent to the IPv6 Source Address (and + Ethernet Source Address) of the incoming Neighbor Solicitation message + */ + pkt_ipv6addr = &(pkt_ipv6->ip6_src); + + if (IN6_IS_ADDR_UNSPECIFIED(pkt_ipv6addr)) { + na->nd_na_flags_reserved = 0; + + if (inet_pton(AF_INET6, ALL_NODES_MULTICAST_ADDR, &(ipv6->ip6_dst)) <= 0) { + if (idata->verbose_f) + puts("send_neighbor_advert(): Error converting all-nodes multicast address"); + + return (-1); + } + + if (ether_pton(ETHER_ALLNODES_LINK_ADDR, &(ethernet->dst), ETHER_ADDR_LEN) == 0) { + if (idata->verbose_f) + puts("send_neighbor_advert(): Error converting all-nodes link-local address"); + + return (-1); + } + } + else { + ipv6->ip6_dst = pkt_ipv6->ip6_src; + ethernet->dst = pkt_ether->src; + + /* + Set the "Solicited" flag if NS was sent from an address other than the unspecified + address (i.e., the response will be unicast). + */ + + na->nd_na_flags_reserved = ND_NA_FLAG_OVERRIDE | ND_NA_FLAG_SOLICITED; + } + + ethernet->src = idata->ether; + + /* + If the Neighbor Solicitation message was directed to one of our unicast addresses, the IPv6 Source + Address is set to that address. Otherwise, we set the IPv6 Source Address to our link-local address. + */ + + pkt_ipv6addr = &(pkt_ipv6->ip6_dst); + + if (IN6_IS_ADDR_MULTICAST(pkt_ipv6addr)) { + ipv6->ip6_src = idata->ip6_local; + } + else { + if (is_eq_in6_addr(pkt_ipv6addr, &(idata->ip6_local))) { + ipv6->ip6_src = idata->ip6_local; + } + else if (idata->ip6_global_flag) { + for (i = 0; i < idata->ip6_global.nprefix; i++) { + if (is_eq_in6_addr(pkt_ipv6addr, &((idata->ip6_global.prefix[i])->ip6))) { + ipv6->ip6_src = (idata->ip6_global.prefix[i])->ip6; + break; + } + } + + if (i == idata->ip6_global.nprefix) + return 0; + } + else { + return 0; + } + } + + na->nd_na_target = pkt_ns->nd_ns_target; + + na->nd_na_cksum = 0; + na->nd_na_cksum = in_chksum(v6buffer, na, ptr - ((unsigned char *)na), IPPROTO_ICMPV6); + + ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); + + if ((nw = pcap_inject(pfd, wbuffer, ptr - wbuffer)) == -1) { + if (idata->verbose_f) + printf("send_neighbor_advert(): pcap_inject(): %s", pcap_geterr(pfd)); + + return (-1); + } + + if (nw != (ptr - wbuffer)) { + if (idata->verbose_f) + printf("send_neighbor_advert(): pcap_inject(): only wrote %d bytes " + "(rather than %lu bytes)\n", + nw, (LUI)(ptr - wbuffer)); + + return (-1); + } + + return 0; } - /* * Function: string_escapes() * * Replace some escape sequences in a string */ -int string_escapes(char *data, unsigned int *datalen, unsigned int maxlen){ - char *org, *dst; - org=data; - dst=data; - - while(org < (data+ *datalen) && dst <= (data+maxlen)){ - if(*org == '\\'){ - if((org+1) < (data+ *datalen)){ - org++; - - switch(*org){ - case '\\': - *dst= '\\'; - break; - - case 'n': - *dst= CHAR_LF; - break; - - case 'r': - *dst= CHAR_CR; - break; - - default: - return 0; - } - } - else - *dst= *org; - } - else{ - if(org != dst) - *dst = *org; - } - - org++; - dst++; - } - - *datalen= dst - data; - return 1; +int string_escapes(char *data, unsigned int *datalen, unsigned int maxlen) { + char *org, *dst; + org = data; + dst = data; + + while (org < (data + *datalen) && dst <= (data + maxlen)) { + if (*org == '\\') { + if ((org + 1) < (data + *datalen)) { + org++; + + switch (*org) { + case '\\': + *dst = '\\'; + break; + + case 'n': + *dst = CHAR_LF; + break; + + case 'r': + *dst = CHAR_CR; + break; + + default: + return 0; + } + } + else + *dst = *org; + } + else { + if (org != dst) + *dst = *org; + } + + org++; + dst++; + } + + *datalen = dst - data; + return 1; } - - /* * Function: Strnlen() * * Our own version of strnlen(), since some OSes do not support it. */ -size_t Strnlen(const char *s, size_t maxlen){ - size_t i=0; +size_t Strnlen(const char *s, size_t maxlen) { + size_t i = 0; - while(i < maxlen && s[i] != 0) - i++; + while (i < maxlen && s[i] != 0) + i++; - if(i < maxlen) - return(i); - else - return(maxlen); + if (i < maxlen) + return (i); + else + return (maxlen); } - /* * Function: init_iface_data() * * Initializes the contents of "iface_data" structure */ -int init_iface_data(struct iface_data *idata){ - unsigned int i; +int init_iface_data(struct iface_data *idata) { + unsigned int i; - memset(idata, 0, sizeof(struct iface_data)); + memset(idata, 0, sizeof(struct iface_data)); - idata->mtu= ETH_DATA_LEN; - idata->local_retrans = 0; - idata->local_timeout = 1; + idata->mtu = ETH_DATA_LEN; + idata->local_retrans = 0; + idata->local_timeout = 1; - if( (idata->ip6_global.prefix= malloc(MAX_LOCAL_ADDRESSES * sizeof(struct prefix_entry *))) == NULL) - return(FAILURE); + if ((idata->ip6_global.prefix = malloc(MAX_LOCAL_ADDRESSES * sizeof(struct prefix_entry *))) == NULL) + return (FAILURE); - idata->ip6_global.nprefix=0; - idata->ip6_global.maxprefix= MAX_LOCAL_ADDRESSES; + idata->ip6_global.nprefix = 0; + idata->ip6_global.maxprefix = MAX_LOCAL_ADDRESSES; - if( (idata->prefix_ol.prefix= malloc(MAX_PREFIXES_ONLINK * sizeof(struct prefix_entry *))) == NULL) - return(FAILURE); + if ((idata->prefix_ol.prefix = malloc(MAX_PREFIXES_ONLINK * sizeof(struct prefix_entry *))) == NULL) + return (FAILURE); - idata->prefix_ol.nprefix= 0; - idata->prefix_ol.maxprefix= MAX_PREFIXES_ONLINK; + idata->prefix_ol.nprefix = 0; + idata->prefix_ol.maxprefix = MAX_PREFIXES_ONLINK; - if( (idata->prefix_ac.prefix= malloc(MAX_PREFIXES_AUTO * sizeof(struct prefix_entry *))) == NULL) - return(FAILURE); + if ((idata->prefix_ac.prefix = malloc(MAX_PREFIXES_AUTO * sizeof(struct prefix_entry *))) == NULL) + return (FAILURE); - idata->prefix_ac.nprefix= 0; - idata->prefix_ac.maxprefix= MAX_PREFIXES_AUTO; + idata->prefix_ac.nprefix = 0; + idata->prefix_ac.maxprefix = MAX_PREFIXES_AUTO; - if( ((idata->iflist).ifaces= malloc(sizeof(struct iface_entry) * MAX_IFACES)) == NULL) - return(FAILURE); + if (((idata->iflist).ifaces = malloc(sizeof(struct iface_entry) * MAX_IFACES)) == NULL) + return (FAILURE); - memset((idata->iflist).ifaces, 0, sizeof(struct iface_entry) * MAX_IFACES); + memset((idata->iflist).ifaces, 0, sizeof(struct iface_entry) * MAX_IFACES); - idata->iflist.nifaces=0; - idata->iflist.maxifaces= MAX_IFACES; + idata->iflist.nifaces = 0; + idata->iflist.maxifaces = MAX_IFACES; - for(i=0; iiflist).ifaces[i].ip6_global.prefix= malloc( sizeof(struct prefix_entry *) * MAX_LOCAL_ADDRESSES)) == NULL){ - return(FAILURE); - } + for (i = 0; i < MAX_IFACES; i++) { + if (((idata->iflist).ifaces[i].ip6_global.prefix = + malloc(sizeof(struct prefix_entry *) * MAX_LOCAL_ADDRESSES)) == NULL) { + return (FAILURE); + } - (idata->iflist).ifaces[i].ip6_global.maxprefix= MAX_LOCAL_ADDRESSES; + (idata->iflist).ifaces[i].ip6_global.maxprefix = MAX_LOCAL_ADDRESSES; - if( ((idata->iflist).ifaces[i].ip6_local.prefix= malloc( sizeof(struct prefix_entry *) * MAX_LOCAL_ADDRESSES)) == NULL){ - return(FAILURE); - } + if (((idata->iflist).ifaces[i].ip6_local.prefix = + malloc(sizeof(struct prefix_entry *) * MAX_LOCAL_ADDRESSES)) == NULL) { + return (FAILURE); + } - (idata->iflist).ifaces[i].ip6_local.maxprefix= MAX_LOCAL_ADDRESSES; - } + (idata->iflist).ifaces[i].ip6_local.maxprefix = MAX_LOCAL_ADDRESSES; + } - return SUCCESS; + return SUCCESS; } - - - /* * Function: init_filters() * * Initializes a filters structure, and allocates memory for the filter data. */ -int init_filters(struct filters *filters){ - memset(filters, 0, sizeof(struct filters)); +int init_filters(struct filters *filters) { + memset(filters, 0, sizeof(struct filters)); - if( (filters->blocksrc= malloc(sizeof(struct in6_addr) * MAX_BLOCK_SRC)) == NULL) - return(-1); + if ((filters->blocksrc = malloc(sizeof(struct in6_addr) * MAX_BLOCK_SRC)) == NULL) + return (-1); - if( (filters->blockdst= malloc(sizeof(struct in6_addr) * MAX_BLOCK_DST)) == NULL) - return(-1); + if ((filters->blockdst = malloc(sizeof(struct in6_addr) * MAX_BLOCK_DST)) == NULL) + return (-1); - if( (filters->blocktarget= malloc(sizeof(struct in6_addr) * MAX_BLOCK_TARGET)) == NULL) - return(-1); + if ((filters->blocktarget = malloc(sizeof(struct in6_addr) * MAX_BLOCK_TARGET)) == NULL) + return (-1); - if( (filters->blocklinksrc= malloc(sizeof(struct ether_addr) * MAX_BLOCK_LINK_SRC)) == NULL) - return(-1); + if ((filters->blocklinksrc = malloc(sizeof(struct ether_addr) * MAX_BLOCK_LINK_SRC)) == NULL) + return (-1); - if( (filters->blocklinkdst= malloc(sizeof(struct ether_addr) * MAX_BLOCK_LINK_DST)) == NULL) - return(-1); + if ((filters->blocklinkdst = malloc(sizeof(struct ether_addr) * MAX_BLOCK_LINK_DST)) == NULL) + return (-1); - if( (filters->blocksrclen= malloc(sizeof(uint8_t) * MAX_BLOCK_SRC)) == NULL) - return(-1); + if ((filters->blocksrclen = malloc(sizeof(uint8_t) * MAX_BLOCK_SRC)) == NULL) + return (-1); - if( (filters->blockdstlen= malloc(sizeof(uint8_t) * MAX_BLOCK_DST)) == NULL) - return(-1); + if ((filters->blockdstlen = malloc(sizeof(uint8_t) * MAX_BLOCK_DST)) == NULL) + return (-1); - if( (filters->blocktargetlen= malloc(sizeof(uint8_t) * MAX_BLOCK_TARGET)) == NULL) - return(-1); + if ((filters->blocktargetlen = malloc(sizeof(uint8_t) * MAX_BLOCK_TARGET)) == NULL) + return (-1); - if( (filters->acceptsrc= malloc(sizeof(struct in6_addr) * MAX_ACCEPT_SRC)) == NULL) - return(-1); + if ((filters->acceptsrc = malloc(sizeof(struct in6_addr) * MAX_ACCEPT_SRC)) == NULL) + return (-1); - if( (filters->acceptdst= malloc(sizeof(struct in6_addr) * MAX_ACCEPT_DST)) == NULL) - return(-1); + if ((filters->acceptdst = malloc(sizeof(struct in6_addr) * MAX_ACCEPT_DST)) == NULL) + return (-1); - if( (filters->accepttarget= malloc(sizeof(struct in6_addr) * MAX_ACCEPT_TARGET)) == NULL) - return(-1); + if ((filters->accepttarget = malloc(sizeof(struct in6_addr) * MAX_ACCEPT_TARGET)) == NULL) + return (-1); - if( (filters->acceptlinksrc= malloc(sizeof(struct ether_addr) * MAX_ACCEPT_LINK_SRC)) == NULL) - return(-1); + if ((filters->acceptlinksrc = malloc(sizeof(struct ether_addr) * MAX_ACCEPT_LINK_SRC)) == NULL) + return (-1); - if( (filters->acceptlinkdst= malloc(sizeof(struct ether_addr) * MAX_ACCEPT_LINK_DST)) == NULL) - return(-1); + if ((filters->acceptlinkdst = malloc(sizeof(struct ether_addr) * MAX_ACCEPT_LINK_DST)) == NULL) + return (-1); - if( (filters->acceptsrclen= malloc(sizeof(uint8_t) * MAX_ACCEPT_SRC)) == NULL) - return(-1); + if ((filters->acceptsrclen = malloc(sizeof(uint8_t) * MAX_ACCEPT_SRC)) == NULL) + return (-1); - if( (filters->acceptdstlen= malloc(sizeof(uint8_t) * MAX_ACCEPT_DST)) == NULL) - return(-1); + if ((filters->acceptdstlen = malloc(sizeof(uint8_t) * MAX_ACCEPT_DST)) == NULL) + return (-1); - if( (filters->accepttargetlen= malloc(sizeof(uint8_t) * MAX_ACCEPT_TARGET)) == NULL) - return(-1); + if ((filters->accepttargetlen = malloc(sizeof(uint8_t) * MAX_ACCEPT_TARGET)) == NULL) + return (-1); - return(0); + return (0); } - - /* * Function: sel_next_hop_ra() * @@ -2381,1784 +2327,1762 @@ int init_filters(struct filters *filters){ * */ -int sel_next_hop_ra(struct iface_data *idata){ - /* - Select link-layer destination address - - + If the underlying interface is loopback or tunnel, there is no need - to select a link-layer destination address - + If a link-layer Destination Address has been specified, we do not need to - select one - + If the destination address is link-local, there is no need to perform - next-hop determination - + Otherwise we need to learn the local router or do ND as a last ressort - */ - if((idata->type == DLT_EN10MB && (!(idata->flags & IFACE_LOOPBACK) && !(idata->flags & IFACE_TUNNEL))) && \ - (!(idata->hdstaddr_f) && idata->dstaddr_f)){ - if(IN6_IS_ADDR_LINKLOCAL(&(idata->dstaddr))){ - /* - If the IPv6 Destination Address is a multicast address, there is no need - to perform Neighbor Discovery - */ - if(IN6_IS_ADDR_MC_LINKLOCAL(&(idata->dstaddr))){ - idata->hdstaddr= ether_multicast(&(idata->dstaddr)); - } - else if(ipv6_to_ether(idata->pfd, idata, &(idata->dstaddr), &(idata->hdstaddr)) != 1){ - if(idata->verbose_f) - puts("Error while performing Neighbor Discovery for the Destination Address"); - - return(-1); - } - } - else if(find_ipv6_router_full(idata->pfd, idata) == 1){ - if(is_ip6_in_prefix_list(&(idata->dstaddr), &(idata->prefix_ol))){ - /* If address is on-link, we must perform Neighbor Discovery */ - if(ipv6_to_ether(idata->pfd, idata, &(idata->dstaddr), &(idata->hdstaddr)) != 1){ - if(idata->verbose_f) - puts("Error while performing Neighbor Discovery for the Destination Address"); - - return(-1); - } - } - else{ - idata->hdstaddr= idata->router_ether; - } - } - else{ - if(idata->verbose_f) - puts("Couldn't find local router. Now trying Neighbor Discovery for the target node"); - /* - * If we were not able to find a local router, we assume the destination is "on-link" (as - * a last ressort), and thus perform Neighbor Discovery for that destination - */ - if(ipv6_to_ether(idata->pfd, idata, &(idata->dstaddr), &(idata->hdstaddr)) != 1){ - if(idata->verbose_f) - puts("Error while performing Neighbor Discovery for the Destination Address"); - - return(-1); - } - } - } - - return(0); +int sel_next_hop_ra(struct iface_data *idata) { + /* + Select link-layer destination address + + + If the underlying interface is loopback or tunnel, there is no need + to select a link-layer destination address + + If a link-layer Destination Address has been specified, we do not need to + select one + + If the destination address is link-local, there is no need to perform + next-hop determination + + Otherwise we need to learn the local router or do ND as a last ressort + */ + if ((idata->type == DLT_EN10MB && (!(idata->flags & IFACE_LOOPBACK) && !(idata->flags & IFACE_TUNNEL))) && + (!(idata->hdstaddr_f) && idata->dstaddr_f)) { + if (IN6_IS_ADDR_LINKLOCAL(&(idata->dstaddr))) { + /* + If the IPv6 Destination Address is a multicast address, there is no need + to perform Neighbor Discovery + */ + if (IN6_IS_ADDR_MC_LINKLOCAL(&(idata->dstaddr))) { + idata->hdstaddr = ether_multicast(&(idata->dstaddr)); + } + else if (ipv6_to_ether(idata->pfd, idata, &(idata->dstaddr), &(idata->hdstaddr)) != 1) { + if (idata->verbose_f) + puts("Error while performing Neighbor Discovery for the Destination Address"); + + return (-1); + } + } + else if (find_ipv6_router_full(idata->pfd, idata) == 1) { + if (is_ip6_in_prefix_list(&(idata->dstaddr), &(idata->prefix_ol))) { + /* If address is on-link, we must perform Neighbor Discovery */ + if (ipv6_to_ether(idata->pfd, idata, &(idata->dstaddr), &(idata->hdstaddr)) != 1) { + if (idata->verbose_f) + puts("Error while performing Neighbor Discovery for the Destination Address"); + + return (-1); + } + } + else { + idata->hdstaddr = idata->router_ether; + } + } + else { + if (idata->verbose_f) + puts("Couldn't find local router. Now trying Neighbor Discovery for the target node"); + /* + * If we were not able to find a local router, we assume the destination is "on-link" (as + * a last ressort), and thus perform Neighbor Discovery for that destination + */ + if (ipv6_to_ether(idata->pfd, idata, &(idata->dstaddr), &(idata->hdstaddr)) != 1) { + if (idata->verbose_f) + puts("Error while performing Neighbor Discovery for the Destination Address"); + + return (-1); + } + } + } + + return (0); } - /* * Function: inc_sdev() * * Computes the average increment and standard deviation of an array of uint32_t's. * The function computes the aforementioned values for network byte order and host byte order, * and returns as a result the set of values with smaller standard deviation. -*/ -int inc_sdev(uint32_t *s, unsigned int n, uint32_t *diff_avg, double *diff_sdev){ - unsigned int i; - uint32_t *diff, *s2; - unsigned long long int diff1_avg, diff2_avg; - double diff1_sdev, diff2_sdev; + */ +int inc_sdev(uint32_t *s, unsigned int n, uint32_t *diff_avg, double *diff_sdev) { + unsigned int i; + uint32_t *diff, *s2; + unsigned long long int diff1_avg, diff2_avg; + double diff1_sdev, diff2_sdev; - if( (diff=malloc((n-1)*sizeof(uint32_t))) == NULL) - return(-1); + if ((diff = malloc((n - 1) * sizeof(uint32_t))) == NULL) + return (-1); - diff1_avg= 0; + diff1_avg = 0; - for(i=0; i<(n-1); i++){ - diff[i]= s[i+1]-s[i]; - diff1_avg+= diff[i]; - } + for (i = 0; i < (n - 1); i++) { + diff[i] = s[i + 1] - s[i]; + diff1_avg += diff[i]; + } - diff1_avg= diff1_avg/(n-1); + diff1_avg = diff1_avg / (n - 1); - diff1_sdev= 0; + diff1_sdev = 0; - for(i=0; i<(n-1); i++) - diff1_sdev= diff1_sdev + (diff[i] - diff1_avg) * (diff[i] - diff1_avg); + for (i = 0; i < (n - 1); i++) + diff1_sdev = diff1_sdev + (diff[i] - diff1_avg) * (diff[i] - diff1_avg); - diff1_sdev= sqrt(diff1_sdev/(n-2)); + diff1_sdev = sqrt(diff1_sdev / (n - 2)); - if( (s2=malloc(n * sizeof(uint32_t))) == NULL) - return(-1); + if ((s2 = malloc(n * sizeof(uint32_t))) == NULL) + return (-1); - memcpy(s2, s, n * sizeof(uint32_t)); - change_endianness(s2, n); + memcpy(s2, s, n * sizeof(uint32_t)); + change_endianness(s2, n); - diff2_avg= 0; + diff2_avg = 0; - for(i=0; i<(n-1); i++){ - diff[i]= s2[i+1]-s2[i]; - diff2_avg+= diff[i]; - } + for (i = 0; i < (n - 1); i++) { + diff[i] = s2[i + 1] - s2[i]; + diff2_avg += diff[i]; + } - diff2_avg= diff2_avg/(n-1); + diff2_avg = diff2_avg / (n - 1); - diff2_sdev= 0; + diff2_sdev = 0; - for(i=0; i<(n-1); i++) - diff2_sdev= diff2_sdev + (diff[i] - diff2_avg) * (diff[i] - diff2_avg); + for (i = 0; i < (n - 1); i++) + diff2_sdev = diff2_sdev + (diff[i] - diff2_avg) * (diff[i] - diff2_avg); - diff2_sdev= sqrt(diff2_sdev/(n-2)); + diff2_sdev = sqrt(diff2_sdev / (n - 2)); - free(diff); - free(s2); + free(diff); + free(s2); - if(diff1_sdev <= diff2_sdev){ - *diff_avg= (uint32_t) diff1_avg; - *diff_sdev= diff1_sdev; - } - else{ - *diff_avg= (uint32_t) diff2_avg; - *diff_sdev= diff2_sdev; - } + if (diff1_sdev <= diff2_sdev) { + *diff_avg = (uint32_t)diff1_avg; + *diff_sdev = diff1_sdev; + } + else { + *diff_avg = (uint32_t)diff2_avg; + *diff_sdev = diff2_sdev; + } - return(0); + return (0); } - /* * Function: change_endianness() * * Changes the endianness of an array of uint32_t's -*/ -void change_endianness(uint32_t *s, unsigned int n){ - unsigned int i; - union { - uint32_t ui; - unsigned char c[4]; - } swapper; - - unsigned char c; - - for(i=0; imtu; - - ether = (struct ether_header *) buffer; - v6buffer = buffer + idata->linkhsize; - ipv6 = (struct ip6_hdr *) v6buffer; - - ether->src = idata->ether; - ether->dst = ether_multicast(&(ipv6->ip6_dst)); - ether->ether_type = htons(ETHERTYPE_IPV6); - - ipv6->ip6_flow=0; - ipv6->ip6_vfc= 0x60; - ipv6->ip6_hlim= 255; - ipv6->ip6_src= idata->srcaddr; - ipv6->ip6_dst= solicited_node(&(idata->dstaddr)); - - prev_nh = (unsigned char *) &(ipv6->ip6_nxt); - *prev_nh = IPPROTO_ICMPV6; - - ptr = (unsigned char *) v6buffer + MIN_IPV6_HLEN; - - if( (ptr+sizeof(struct nd_neighbor_solicit)) > (v6buffer+ns_max_packet_size)){ - if(idata->verbose_f>1) - puts("Packet too large while inserting Neighbor Solicitation header"); - - return(-1); - } - - ns= (struct nd_neighbor_solicit *) (ptr); - - ns->nd_ns_type = ND_NEIGHBOR_SOLICIT; - ns->nd_ns_code = 0; - ns->nd_ns_reserved = 0; - ns->nd_ns_target = *target; - - ptr += sizeof(struct nd_neighbor_solicit); - sllaopt = (struct nd_opt_slla *) ptr; - - if( (ptr+sizeof(struct nd_opt_slla)) > (v6buffer+ns_max_packet_size)){ - if(idata->verbose_f>1) - puts("NS message too large while processing source link-layer address opt."); - - return(-1); - } - - sllaopt->type= ND_OPT_SOURCE_LINKADDR; - sllaopt->length= SLLA_OPT_LEN; - memcpy(sllaopt->address, &(idata->ether.a), ETH_ALEN); - ptr += sizeof(struct nd_opt_slla); - - ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); - ns->nd_ns_cksum = 0; - ns->nd_ns_cksum = in_chksum(v6buffer, ns, ptr-((unsigned char *)ns), IPPROTO_ICMPV6); - - if((nw=pcap_inject(idata->pfd, buffer, ptr - buffer)) == -1){ - if(idata->verbose_f>1) - printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); - - return(-1); - } - - if(nw != (ptr-buffer)){ - if(idata->verbose_f > 1) - printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, \ - (LUI) (ptr-buffer)); - return(-1); - } - - return 0; -} + */ +int send_neighbor_solicit(struct iface_data *idata, struct in6_addr *target) { + unsigned char *ptr, *prev_nh; + unsigned char buffer[65556]; + unsigned int ns_max_packet_size; + struct ether_header *ether; + unsigned char *v6buffer; + int nw; + struct ip6_hdr *ipv6; + struct nd_neighbor_solicit *ns; + struct nd_opt_slla *sllaopt; + + ns_max_packet_size = idata->mtu; + + ether = (struct ether_header *)buffer; + v6buffer = buffer + idata->linkhsize; + ipv6 = (struct ip6_hdr *)v6buffer; + + ether->src = idata->ether; + ether->dst = ether_multicast(&(ipv6->ip6_dst)); + ether->ether_type = htons(ETHERTYPE_IPV6); + + ipv6->ip6_flow = 0; + ipv6->ip6_vfc = 0x60; + ipv6->ip6_hlim = 255; + ipv6->ip6_src = idata->srcaddr; + ipv6->ip6_dst = solicited_node(&(idata->dstaddr)); + + prev_nh = (unsigned char *)&(ipv6->ip6_nxt); + *prev_nh = IPPROTO_ICMPV6; + + ptr = (unsigned char *)v6buffer + MIN_IPV6_HLEN; + + if ((ptr + sizeof(struct nd_neighbor_solicit)) > (v6buffer + ns_max_packet_size)) { + if (idata->verbose_f > 1) + puts("Packet too large while inserting Neighbor Solicitation header"); + + return (-1); + } + + ns = (struct nd_neighbor_solicit *)(ptr); + + ns->nd_ns_type = ND_NEIGHBOR_SOLICIT; + ns->nd_ns_code = 0; + ns->nd_ns_reserved = 0; + ns->nd_ns_target = *target; + + ptr += sizeof(struct nd_neighbor_solicit); + sllaopt = (struct nd_opt_slla *)ptr; + + if ((ptr + sizeof(struct nd_opt_slla)) > (v6buffer + ns_max_packet_size)) { + if (idata->verbose_f > 1) + puts("NS message too large while processing source link-layer address opt."); + + return (-1); + } + sllaopt->type = ND_OPT_SOURCE_LINKADDR; + sllaopt->length = SLLA_OPT_LEN; + memcpy(sllaopt->address, &(idata->ether.a), ETH_ALEN); + ptr += sizeof(struct nd_opt_slla); + + ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); + ns->nd_ns_cksum = 0; + ns->nd_ns_cksum = in_chksum(v6buffer, ns, ptr - ((unsigned char *)ns), IPPROTO_ICMPV6); + + if ((nw = pcap_inject(idata->pfd, buffer, ptr - buffer)) == -1) { + if (idata->verbose_f > 1) + printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); + + return (-1); + } + + if (nw != (ptr - buffer)) { + if (idata->verbose_f > 1) + printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, (LUI)(ptr - buffer)); + return (-1); + } + + return 0; +} #ifdef __linux__ /* * Function: sel_next_hop() * * Find the next hop for a target destination -*/ -int sel_next_hop(struct iface_data *idata){ - int sockfd; - struct sockaddr_nl addr, them; - int ret; - pid_t pid; - char reply[MAX_NLPAYLOAD]; - struct msghdr msg; - struct iovec iov; - struct nlrequest req; - struct nlmsghdr *nlp; - struct rtmsg *rtp; - struct rtattr *rtap; - int nll,rtl; - unsigned char skip_f; + */ +int sel_next_hop(struct iface_data *idata) { + int sockfd; + struct sockaddr_nl addr, them; + int ret; + pid_t pid; + char reply[MAX_NLPAYLOAD]; + struct msghdr msg; + struct iovec iov; + struct nlrequest req; + struct nlmsghdr *nlp; + struct rtmsg *rtp; + struct rtattr *rtap; + int nll, rtl; + unsigned char skip_f; #ifdef DEBUG - puts("DEBUG: BEGIN sel_next_hop()"); + puts("DEBUG: BEGIN sel_next_hop()"); #endif - if( (sockfd=socket(AF_NETLINK,SOCK_RAW,NETLINK_ROUTE)) == -1){ - if(idata->verbose_f) - puts("Error in socket()"); + if ((sockfd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1) { + if (idata->verbose_f) + puts("Error in socket()"); - return(FAILURE); - } + return (FAILURE); + } - memset((void *)&addr, 0, sizeof(addr)); - addr.nl_family = AF_NETLINK; - addr.nl_pid = pid= getpid(); - addr.nl_groups = RTMGRP_IPV6_ROUTE; + memset((void *)&addr, 0, sizeof(addr)); + addr.nl_family = AF_NETLINK; + addr.nl_pid = pid = getpid(); + addr.nl_groups = RTMGRP_IPV6_ROUTE; - if(bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) != 0){ - if(idata->verbose_f) - puts("Error in bind()"); + if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) != 0) { + if (idata->verbose_f) + puts("Error in bind()"); - close(sockfd); - return(FAILURE); - } + close(sockfd); + return (FAILURE); + } - memset(&req, 0, sizeof(req)); - req.nl.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); - req.nl.nlmsg_flags = NLM_F_REQUEST; - req.nl.nlmsg_type = RTM_GETROUTE; - req.rt.rtm_family= AF_INET6; + memset(&req, 0, sizeof(req)); + req.nl.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); + req.nl.nlmsg_flags = NLM_F_REQUEST; + req.nl.nlmsg_type = RTM_GETROUTE; + req.rt.rtm_family = AF_INET6; - rtap = (struct rtattr *) req.buf; + rtap = (struct rtattr *)req.buf; - /* Destination Address */ - if(idata->dstaddr_f){ + /* Destination Address */ + if (idata->dstaddr_f) { #ifdef DEBUG - print_ipv6_address("DEBUG Req RTA_DST: ", &(idata->dstaddr)); + print_ipv6_address("DEBUG Req RTA_DST: ", &(idata->dstaddr)); #endif - rtap->rta_type = RTA_DST; - rtap->rta_len = RTA_SPACE(sizeof(idata->dstaddr)); - memcpy(RTA_DATA(rtap), &(idata->dstaddr), sizeof(idata->dstaddr)); - req.nl.nlmsg_len += rtap->rta_len; - } - - /* Source Address */ - if(idata->srcaddr_f){ + rtap->rta_type = RTA_DST; + rtap->rta_len = RTA_SPACE(sizeof(idata->dstaddr)); + memcpy(RTA_DATA(rtap), &(idata->dstaddr), sizeof(idata->dstaddr)); + req.nl.nlmsg_len += rtap->rta_len; + } + + /* Source Address */ + if (idata->srcaddr_f) { #ifdef DEBUG - print_ipv6_address("DEBUG Req RTA_SRC: ", &(idata->srcaddr)); + print_ipv6_address("DEBUG Req RTA_SRC: ", &(idata->srcaddr)); #endif - rtap = (struct rtattr *)((char *)rtap + (rtap->rta_len)); - rtap->rta_type = RTA_SRC; - rtap->rta_len = RTA_SPACE(sizeof(idata->srcaddr)); - memcpy(RTA_DATA(rtap), &(idata->srcaddr), sizeof(idata->srcaddr)); - req.nl.nlmsg_len += rtap->rta_len; - } + rtap = (struct rtattr *)((char *)rtap + (rtap->rta_len)); + rtap->rta_type = RTA_SRC; + rtap->rta_len = RTA_SPACE(sizeof(idata->srcaddr)); + memcpy(RTA_DATA(rtap), &(idata->srcaddr), sizeof(idata->srcaddr)); + req.nl.nlmsg_len += rtap->rta_len; + } - /* address it */ - memset(&them, 0, sizeof(them)); - them.nl_family = AF_NETLINK; + /* address it */ + memset(&them, 0, sizeof(them)); + them.nl_family = AF_NETLINK; - memset(&msg, 0, sizeof(msg)); - msg.msg_name = (void *)&them; - msg.msg_namelen = sizeof(them); + memset(&msg, 0, sizeof(msg)); + msg.msg_name = (void *)&them; + msg.msg_namelen = sizeof(them); - memset(&iov, 0, sizeof(iov)); - iov.iov_base = (void *) &req.nl; - iov.iov_len = req.nl.nlmsg_len; + memset(&iov, 0, sizeof(iov)); + iov.iov_base = (void *)&req.nl; + iov.iov_len = req.nl.nlmsg_len; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; - /* send it */ - if( (ret = sendmsg(sockfd, &msg, 0)) < 0){ - if(idata->verbose_f) - puts("Error in send()"); + /* send it */ + if ((ret = sendmsg(sockfd, &msg, 0)) < 0) { + if (idata->verbose_f) + puts("Error in send()"); - close(sockfd); - return(FAILURE); - } + close(sockfd); + return (FAILURE); + } - memset(reply, 0, sizeof(reply)); + memset(reply, 0, sizeof(reply)); - if( (ret = recv(sockfd, reply, sizeof(reply), 0)) < 0){ - if(idata->verbose_f) - puts("Error in recv()"); + if ((ret = recv(sockfd, reply, sizeof(reply), 0)) < 0) { + if (idata->verbose_f) + puts("Error in recv()"); - close(sockfd); - return(FAILURE); - } + close(sockfd); + return (FAILURE); + } - nll = ret; + nll = ret; #ifdef DEBUG - puts("DEBUG: sel_next_hop() going to loop through the results"); + puts("DEBUG: sel_next_hop() going to loop through the results"); #endif - /* - This should eventually be improved to handle the case where messages are lost, since Netlink messages - are reliable. - */ - for(nlp = (struct nlmsghdr *)reply; NLMSG_OK(nlp,nll); nlp = NLMSG_NEXT(nlp, nll)){ - rtp = (struct rtmsg *) NLMSG_DATA(nlp); + /* + This should eventually be improved to handle the case where messages are lost, since Netlink messages + are reliable. + */ + for (nlp = (struct nlmsghdr *)reply; NLMSG_OK(nlp, nll); nlp = NLMSG_NEXT(nlp, nll)) { + rtp = (struct rtmsg *)NLMSG_DATA(nlp); - skip_f=0; + skip_f = 0; - if(rtp->rtm_family == AF_INET6){ - for(rtap = (struct rtattr *) RTM_RTA(rtp), rtl = RTM_PAYLOAD(nlp); RTA_OK(rtap, rtl); rtap = RTA_NEXT(rtap,rtl)) { - switch(rtap->rta_type){ - case RTA_DST: + if (rtp->rtm_family == AF_INET6) { + for (rtap = (struct rtattr *)RTM_RTA(rtp), rtl = RTM_PAYLOAD(nlp); RTA_OK(rtap, rtl); + rtap = RTA_NEXT(rtap, rtl)) { + switch (rtap->rta_type) { + case RTA_DST: #ifdef DEBUG - print_ipv6_address("DEBUG: RTA_DST: ", (struct in6_addr *) RTA_DATA(rtap)); + print_ipv6_address("DEBUG: RTA_DST: ", (struct in6_addr *)RTA_DATA(rtap)); #endif - /* - If Destination is different from Destination Address, this just means that we need to send - our packets to a local router - */ - /* - if(!is_eq_in6_addr(&(idata->dstaddr), (struct in6_addr *) RTA_DATA(rtap))){ - skip_f=1; - } - */ - break; + /* + If Destination is different from Destination Address, this just means that we need to send + our packets to a local router + */ + /* + if(!is_eq_in6_addr(&(idata->dstaddr), (struct in6_addr *) RTA_DATA(rtap))){ + skip_f=1; + } + */ + break; - case RTA_OIF: - idata->nhifindex= *((int *) RTA_DATA(rtap)); - - if(if_indextoname(idata->nhifindex, idata->nhiface) == NULL){ - if(idata->verbose_f) - puts("Error calling if_indextoname() from sel_next_hop()"); + case RTA_OIF: + idata->nhifindex = *((int *)RTA_DATA(rtap)); + if (if_indextoname(idata->nhifindex, idata->nhiface) == NULL) { + if (idata->verbose_f) + puts("Error calling if_indextoname() from sel_next_hop()"); #ifdef DEBUG - puts("DEBUG: RTA_OIF: iif_indextoname() failed"); + puts("DEBUG: RTA_OIF: iif_indextoname() failed"); #endif - return(FAILURE); - } + return (FAILURE); + } #ifdef DEBUG - printf("DEBUG: RTA_OIF: Index: %d, Name: %s\n", idata->nhifindex, idata->nhiface); + printf("DEBUG: RTA_OIF: Index: %d, Name: %s\n", idata->nhifindex, idata->nhiface); #endif - idata->nhifindex_f= 1; - break; + idata->nhifindex_f = 1; + break; - case RTA_GATEWAY: - idata->nhaddr= *( (struct in6_addr *) RTA_DATA(rtap)); + case RTA_GATEWAY: + idata->nhaddr = *((struct in6_addr *)RTA_DATA(rtap)); #ifdef DEBUG - print_ipv6_address("DEBUG: RTA_GATEWAY: ", (struct in6_addr *) RTA_DATA(rtap)); + print_ipv6_address("DEBUG: RTA_GATEWAY: ", (struct in6_addr *)RTA_DATA(rtap)); #endif - if(!IN6_IS_ADDR_UNSPECIFIED(&(idata->nhaddr))){ - idata->nhaddr_f= 1; + if (!IN6_IS_ADDR_UNSPECIFIED(&(idata->nhaddr))) { + idata->nhaddr_f = 1; #ifdef DEBUG - puts("DEBUG: set the nhaddr_F flag"); + puts("DEBUG: set the nhaddr_F flag"); #endif - } - else{ + } + else { #ifdef DEBUG - puts("DEBUG: Did not set the nhaddr_f flag was ADR_UNSPECIFIED)"); + puts("DEBUG: Did not set the nhaddr_f flag was ADR_UNSPECIFIED)"); #endif - } - break; - } + } + break; + } - if(skip_f) - break; - } + if (skip_f) + break; + } - if(skip_f){ + if (skip_f) { #ifdef DEBUG - puts("DEBUG: Skipping set"); + puts("DEBUG: Skipping set"); #endif - continue; - } - } - } + continue; + } + } + } - close(sockfd); + close(sockfd); - if(idata->nhifindex_f){ - idata->nh_f=TRUE; + if (idata->nhifindex_f) { + idata->nh_f = TRUE; #ifdef DEBUG - puts("DEBUG: END sel_next_hop() (SUCCESS)"); + puts("DEBUG: END sel_next_hop() (SUCCESS)"); #endif - return(SUCCESS); - } - else{ + return (SUCCESS); + } + else { #ifdef DEBUG - puts("DEBUG: END sel_next_hop() (FAILURE)"); + puts("DEBUG: END sel_next_hop() (FAILURE)"); #endif - return(FAILURE); - } + return (FAILURE); + } } -#elif defined (__FreeBSD__) || defined(__NetBSD__) || defined (__OpenBSD__) || defined(__APPLE__) || defined(__FreeBSD_kernel__) || defined(__sun) || defined(sun) +#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) || \ + defined(__FreeBSD_kernel__) || defined(__sun) || defined(sun) /* * Function: sel_next_hop() * * Find the next hop for a target destination -*/ -int sel_next_hop(struct iface_data *idata){ - int sockfd; - pid_t pid; - int seq; - ssize_t r; - unsigned int queries=0, i; - char reply[MAX_RTPAYLOAD]; - struct rt_msghdr *rtm; - struct sockaddr_in6 *sin6; - struct sockaddr_dl *sockpptr; - struct sockaddr *sa; - unsigned char onlink_f=FALSE; + */ +int sel_next_hop(struct iface_data *idata) { + int sockfd; + pid_t pid; + int seq; + ssize_t r; + unsigned int queries = 0, i; + char reply[MAX_RTPAYLOAD]; + struct rt_msghdr *rtm; + struct sockaddr_in6 *sin6; + struct sockaddr_dl *sockpptr; + struct sockaddr *sa; + unsigned char onlink_f = FALSE; #ifdef DEBUG - puts("DEBUG: BEGIN sel_next_hop()"); + puts("DEBUG: BEGIN sel_next_hop()"); #endif - if( (sockfd=socket(AF_ROUTE, SOCK_RAW, 0)) == -1){ - if(idata->verbose_f) - puts("Error in socket() call from sel_next_hop()"); + if ((sockfd = socket(AF_ROUTE, SOCK_RAW, 0)) == -1) { + if (idata->verbose_f) + puts("Error in socket() call from sel_next_hop()"); #ifdef DEBUG - puts("DEBUG: sel_next_hop() Failed when opening socket"); - puts("DEBUG end sel_next_hop() (FAILURE)"); + puts("DEBUG: sel_next_hop() Failed when opening socket"); + puts("DEBUG end sel_next_hop() (FAILURE)"); #endif - return(FAILURE); - } - - idata->nhaddr= idata->dstaddr; - - do{ - rtm= (struct rt_msghdr *) reply; - memset(rtm, 0, sizeof(struct rt_msghdr)); - rtm->rtm_msglen= sizeof(struct rt_msghdr) + sizeof(struct sockaddr_in6); - rtm->rtm_version= RTM_VERSION; - rtm->rtm_type= RTM_GET; -#if defined (__OpenBSD__) - rtm->rtm_addrs= RTA_DST; + return (FAILURE); + } + + idata->nhaddr = idata->dstaddr; + + do { + rtm = (struct rt_msghdr *)reply; + memset(rtm, 0, sizeof(struct rt_msghdr)); + rtm->rtm_msglen = sizeof(struct rt_msghdr) + sizeof(struct sockaddr_in6); + rtm->rtm_version = RTM_VERSION; + rtm->rtm_type = RTM_GET; +#if defined(__OpenBSD__) + rtm->rtm_addrs = RTA_DST; #else - rtm->rtm_addrs= RTA_DST | RTA_IFP; + rtm->rtm_addrs = RTA_DST | RTA_IFP; #endif - rtm->rtm_pid= pid= getpid(); - rtm->rtm_seq= seq= random(); + rtm->rtm_pid = pid = getpid(); + rtm->rtm_seq = seq = random(); - sin6= (struct sockaddr_in6 *) (rtm + 1); - memset(sin6, 0, sizeof(struct sockaddr_in6)); + sin6 = (struct sockaddr_in6 *)(rtm + 1); + memset(sin6, 0, sizeof(struct sockaddr_in6)); #ifdef SIN6_LEN - sin6->sin6_len= sizeof(struct sockaddr_in6); + sin6->sin6_len = sizeof(struct sockaddr_in6); #endif - sin6->sin6_family= AF_INET6; - sin6->sin6_addr= idata->nhaddr; - - if(write(sockfd, rtm, rtm->rtm_msglen) == -1){ - if(idata->verbose_f) - puts("write() failed. No route to the intenteded destination in the local routing table"); - - return(FAILURE); - } - - do{ - if( (r=read(sockfd, rtm, MAX_RTPAYLOAD)) < 0){ - if(idata->verbose_f) - puts("Error in read() call from sel_next_hop()"); - - return(FAILURE); - } - }while( rtm->rtm_type != RTM_GET || rtm->rtm_pid != pid || rtm->rtm_seq != seq); - - /* The rt_msghdr{} structure is followed by sockaddr structures */ - sa= (struct sockaddr *) (rtm+1); - - for(i=0; irtm_addrs & (1 << i)){ - switch(i){ - case RTAX_GATEWAY: - if(sa->sa_family == AF_INET6 && rtm->rtm_flags & RTF_GATEWAY){ - idata->nhaddr= ((struct sockaddr_in6 *) sa)->sin6_addr; - idata->nhaddr_f=TRUE; - } - break; - - case RTAX_IFP: - if(sa->sa_family == AF_LINK){ - sockpptr = (struct sockaddr_dl *) (sa); - idata->nhifindex= sockpptr->sdl_index; - idata->nhifindex_f=TRUE; - - if(if_indextoname(idata->nhifindex, idata->nhiface) == NULL){ - puts("Error calling if_indextoname() from sel_next_hop()"); - return(EXIT_FAILURE); - } - - onlink_f=TRUE; - } - break; - } - + sin6->sin6_family = AF_INET6; + sin6->sin6_addr = idata->nhaddr; + + if (write(sockfd, rtm, rtm->rtm_msglen) == -1) { + if (idata->verbose_f) + puts("write() failed. No route to the intenteded destination in the local routing table"); + + return (FAILURE); + } + + do { + if ((r = read(sockfd, rtm, MAX_RTPAYLOAD)) < 0) { + if (idata->verbose_f) + puts("Error in read() call from sel_next_hop()"); + + return (FAILURE); + } + } while (rtm->rtm_type != RTM_GET || rtm->rtm_pid != pid || rtm->rtm_seq != seq); + + /* The rt_msghdr{} structure is followed by sockaddr structures */ + sa = (struct sockaddr *)(rtm + 1); + + for (i = 0; i < RTAX_MAX; i++) { + if (rtm->rtm_addrs & (1 << i)) { + switch (i) { + case RTAX_GATEWAY: + if (sa->sa_family == AF_INET6 && rtm->rtm_flags & RTF_GATEWAY) { + idata->nhaddr = ((struct sockaddr_in6 *)sa)->sin6_addr; + idata->nhaddr_f = TRUE; + } + break; + + case RTAX_IFP: + if (sa->sa_family == AF_LINK) { + sockpptr = (struct sockaddr_dl *)(sa); + idata->nhifindex = sockpptr->sdl_index; + idata->nhifindex_f = TRUE; + + if (if_indextoname(idata->nhifindex, idata->nhiface) == NULL) { + puts("Error calling if_indextoname() from sel_next_hop()"); + return (EXIT_FAILURE); + } + + onlink_f = TRUE; + } + break; + } + #if defined(sun) || defined(__sun) - if(i==RTAX_IFP || i==RTAX_IFA) - sa = (struct sockaddr *) ((char *) sa + sizeof(struct sockaddr_dl)); - else - sa = (struct sockaddr *) ((char *) sa + sizeof(struct sockaddr_in6)); + if (i == RTAX_IFP || i == RTAX_IFA) + sa = (struct sockaddr *)((char *)sa + sizeof(struct sockaddr_dl)); + else + sa = (struct sockaddr *)((char *)sa + sizeof(struct sockaddr_in6)); #else - sa = (struct sockaddr *) ((char *) sa + SA_SIZE(sa)); + sa = (struct sockaddr *)((char *)sa + SA_SIZE(sa)); #endif - } - } - - queries++; - }while(!onlink_f && queries < 10); - - close(sockfd); - - if(idata->nhifindex_f){ -#if defined (__FreeBSD__) || defined(__NetBSD__) || defined (__OpenBSD__) || defined(__APPLE__) || defined(__FreeBSD_kernel__) - if(IN6_IS_ADDR_LINKLOCAL(&(idata->nhaddr))){ - /* BSDs store the interface index in s6_addr16[1], so we must clear it */ - idata->nhaddr.s6_addr16[1] =0; - idata->nhaddr.s6_addr16[2] =0; - idata->nhaddr.s6_addr16[3] =0; - } + } + } + + queries++; + } while (!onlink_f && queries < 10); + + close(sockfd); + + if (idata->nhifindex_f) { +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) || \ + defined(__FreeBSD_kernel__) + if (IN6_IS_ADDR_LINKLOCAL(&(idata->nhaddr))) { + /* BSDs store the interface index in s6_addr16[1], so we must clear it */ + idata->nhaddr.s6_addr16[1] = 0; + idata->nhaddr.s6_addr16[2] = 0; + idata->nhaddr.s6_addr16[3] = 0; + } #endif #ifdef DEBUG - puts("DEBUG: END sel_next_hop() (SUCCESS)"); + puts("DEBUG: END sel_next_hop() (SUCCESS)"); #endif - return(SUCCESS); - } - else{ + return (SUCCESS); + } + else { #ifdef DEBUG - puts("DEBUG: END sel_next_hop() (FAILURE)"); + puts("DEBUG: END sel_next_hop() (FAILURE)"); #endif - return(FAILURE); - } + return (FAILURE); + } } #endif - /* * Function: print_ipv6_address() * * Prints an IPv6 address with a legend */ -unsigned int print_ipv6_address(char *s, struct in6_addr *v6addr){ - char pv6addr[INET6_ADDRSTRLEN]; +unsigned int print_ipv6_address(char *s, struct in6_addr *v6addr) { + char pv6addr[INET6_ADDRSTRLEN]; - if(inet_ntop(AF_INET6, v6addr, pv6addr, sizeof(pv6addr)) == NULL){ - puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); - return(EXIT_FAILURE); - } + if (inet_ntop(AF_INET6, v6addr, pv6addr, sizeof(pv6addr)) == NULL) { + puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); + return (EXIT_FAILURE); + } - printf("%s%s\n", s, pv6addr); - return(EXIT_SUCCESS); + printf("%s%s\n", s, pv6addr); + return (EXIT_SUCCESS); } - /* * Function: print_ipv6_address_rev() * * Prints an IPv6 address in reversed form */ -unsigned int print_ipv6_address_rev(struct in6_addr *v6addr){ - int i; +unsigned int print_ipv6_address_rev(struct in6_addr *v6addr) { + int i; - for(i=15; i>=0; i--){ - printf("%01x.%01x%s", v6addr->s6_addr[i] & 0x0f, v6addr->s6_addr[i] >>4, i?".":"\n"); + for (i = 15; i >= 0; i--) { + printf("%01x.%01x%s", v6addr->s6_addr[i] & 0x0f, v6addr->s6_addr[i] >> 4, i ? "." : "\n"); + } - } - - return(EXIT_SUCCESS); + return (EXIT_SUCCESS); } - - /* * Function: get_local_addrs() * * Obtains all local addresses (Ethernet and IPv6 addresses for all interfaces) */ -int get_local_addrs(struct iface_data *idata){ - struct iface_entry *cif; - struct ifaddrs *ifptr, *ptr; - struct sockaddr_in6 *sockin6ptr; +int get_local_addrs(struct iface_data *idata) { + struct iface_entry *cif; + struct ifaddrs *ifptr, *ptr; + struct sockaddr_in6 *sockin6ptr; #ifdef __linux__ - struct sockaddr_ll *sockpptr; -#elif defined (__FreeBSD__) || defined(__NetBSD__) || defined (__OpenBSD__) || defined(__APPLE__) || defined(__FreeBSD_kernel__) - struct sockaddr_dl *sockpptr; + struct sockaddr_ll *sockpptr; +#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) || \ + defined(__FreeBSD_kernel__) + struct sockaddr_dl *sockpptr; #endif - if(getifaddrs(&ifptr) != 0){ - if(idata->verbose_f > 1){ - puts("Error in call to getifaddrs()"); - } - return(FAILURE); - } + if (getifaddrs(&ifptr) != 0) { + if (idata->verbose_f > 1) { + puts("Error in call to getifaddrs()"); + } + return (FAILURE); + } - for(ptr=ifptr; ptr != NULL; ptr= ptr->ifa_next){ - if(ptr->ifa_addr == NULL){ - continue; - } + for (ptr = ifptr; ptr != NULL; ptr = ptr->ifa_next) { + if (ptr->ifa_addr == NULL) { + continue; + } - if(ptr->ifa_name == NULL){ + if (ptr->ifa_name == NULL) { #ifdef DEBUG -puts("DEBUG: ifa_name was null"); + puts("DEBUG: ifa_name was null"); #endif - continue; - } - - if( (cif = find_iface_by_name( &(idata->iflist), ptr->ifa_name)) == NULL){ - if(idata->iflist.nifaces >= MAX_IFACES) - continue; - else{ - cif= &(idata->iflist.ifaces[idata->iflist.nifaces]); - strncpy(cif->iface, ptr->ifa_name, IFACE_LENGTH); - cif->iface[IFACE_LENGTH-1]=0; - /* XXX: Cannot otherwise find the index for tun devices? */ - cif->ifindex= if_nametoindex(cif->iface); - idata->iflist.nifaces++; - } - } + continue; + } + + if ((cif = find_iface_by_name(&(idata->iflist), ptr->ifa_name)) == NULL) { + if (idata->iflist.nifaces >= MAX_IFACES) + continue; + else { + cif = &(idata->iflist.ifaces[idata->iflist.nifaces]); + strncpy(cif->iface, ptr->ifa_name, IFACE_LENGTH); + cif->iface[IFACE_LENGTH - 1] = 0; + /* XXX: Cannot otherwise find the index for tun devices? */ + cif->ifindex = if_nametoindex(cif->iface); + idata->iflist.nifaces++; + } + } #ifdef __linux__ - if((ptr->ifa_addr)->sa_family == AF_PACKET){ - sockpptr = (struct sockaddr_ll *) (ptr->ifa_addr); - - if(sockpptr->sll_halen == ETHER_ADDR_LEN){ - memcpy(&(cif->ether), sockpptr->sll_addr, ETHER_ADDR_LEN); - cif->ether_f= TRUE; - } - - cif->ifindex= sockpptr->sll_ifindex; - } -#elif defined (__FreeBSD__) || defined(__NetBSD__) || defined (__OpenBSD__) || defined(__APPLE__) || defined(__FreeBSD_kernel__) - if((ptr->ifa_addr)->sa_family == AF_LINK){ - sockpptr = (struct sockaddr_dl *) (ptr->ifa_addr); - if(sockpptr->sdl_alen == ETHER_ADDR_LEN){ - memcpy(&(cif->ether), (sockpptr->sdl_data + sockpptr->sdl_nlen), ETHER_ADDR_LEN); - cif->ether_f= TRUE; - } - - cif->ifindex= sockpptr->sdl_index; - } + if ((ptr->ifa_addr)->sa_family == AF_PACKET) { + sockpptr = (struct sockaddr_ll *)(ptr->ifa_addr); + + if (sockpptr->sll_halen == ETHER_ADDR_LEN) { + memcpy(&(cif->ether), sockpptr->sll_addr, ETHER_ADDR_LEN); + cif->ether_f = TRUE; + } + + cif->ifindex = sockpptr->sll_ifindex; + } +#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) || \ + defined(__FreeBSD_kernel__) + if ((ptr->ifa_addr)->sa_family == AF_LINK) { + sockpptr = (struct sockaddr_dl *)(ptr->ifa_addr); + if (sockpptr->sdl_alen == ETHER_ADDR_LEN) { + memcpy(&(cif->ether), (sockpptr->sdl_data + sockpptr->sdl_nlen), ETHER_ADDR_LEN); + cif->ether_f = TRUE; + } + + cif->ifindex = sockpptr->sdl_index; + } #endif - else if((ptr->ifa_addr)->sa_family == AF_INET6){ - sockin6ptr= (struct sockaddr_in6 *) (ptr->ifa_addr); + else if ((ptr->ifa_addr)->sa_family == AF_INET6) { + sockin6ptr = (struct sockaddr_in6 *)(ptr->ifa_addr); - if(IN6_IS_ADDR_LINKLOCAL( &(sockin6ptr->sin6_addr))){ - if(cif->ip6_local.nprefix >= cif->ip6_local.maxprefix) - continue; + if (IN6_IS_ADDR_LINKLOCAL(&(sockin6ptr->sin6_addr))) { + if (cif->ip6_local.nprefix >= cif->ip6_local.maxprefix) + continue; - if(is_ip6_in_prefix_list( &(sockin6ptr->sin6_addr), &(cif->ip6_local)) == TRUE) - continue; + if (is_ip6_in_prefix_list(&(sockin6ptr->sin6_addr), &(cif->ip6_local)) == TRUE) + continue; - if( (cif->ip6_local.prefix[cif->ip6_local.nprefix] = malloc(sizeof(struct prefix_entry))) == NULL){ - if(idata->verbose_f > 1) - puts("Error while storing Source Address"); + if ((cif->ip6_local.prefix[cif->ip6_local.nprefix] = malloc(sizeof(struct prefix_entry))) == NULL) { + if (idata->verbose_f > 1) + puts("Error while storing Source Address"); - freeifaddrs(ifptr); - return(FAILURE); - } + freeifaddrs(ifptr); + return (FAILURE); + } - (cif->ip6_local.prefix[cif->ip6_local.nprefix])->len = 128; - (cif->ip6_local.prefix[cif->ip6_local.nprefix])->ip6 = sockin6ptr->sin6_addr; + (cif->ip6_local.prefix[cif->ip6_local.nprefix])->len = 128; + (cif->ip6_local.prefix[cif->ip6_local.nprefix])->ip6 = sockin6ptr->sin6_addr; -#if defined (__FreeBSD__) || defined(__NetBSD__) || defined (__OpenBSD__) || defined(__APPLE__) || defined(__FreeBSD_kernel__) - /* BSDs store the interface index in s6_addr16[1], so we must clear it */ - (cif->ip6_local.prefix[cif->ip6_local.nprefix])->ip6.s6_addr16[1] =0; - (cif->ip6_local.prefix[cif->ip6_local.nprefix])->ip6.s6_addr16[2] =0; - (cif->ip6_local.prefix[cif->ip6_local.nprefix])->ip6.s6_addr16[3] =0; +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) || \ + defined(__FreeBSD_kernel__) + /* BSDs store the interface index in s6_addr16[1], so we must clear it */ + (cif->ip6_local.prefix[cif->ip6_local.nprefix])->ip6.s6_addr16[1] = 0; + (cif->ip6_local.prefix[cif->ip6_local.nprefix])->ip6.s6_addr16[2] = 0; + (cif->ip6_local.prefix[cif->ip6_local.nprefix])->ip6.s6_addr16[3] = 0; #endif - cif->ip6_local.nprefix++; - } - else{ - if(is_ip6_in_prefix_list( &(sockin6ptr->sin6_addr), &(cif->ip6_global))) - continue; + cif->ip6_local.nprefix++; + } + else { + if (is_ip6_in_prefix_list(&(sockin6ptr->sin6_addr), &(cif->ip6_global))) + continue; - if(IN6_IS_ADDR_LOOPBACK(&(sockin6ptr->sin6_addr))) - cif->flags= IFACE_LOOPBACK; + if (IN6_IS_ADDR_LOOPBACK(&(sockin6ptr->sin6_addr))) + cif->flags = IFACE_LOOPBACK; - if(cif->ip6_global.nprefix >= cif->ip6_global.maxprefix) - continue; + if (cif->ip6_global.nprefix >= cif->ip6_global.maxprefix) + continue; - if( (cif->ip6_global.prefix[cif->ip6_global.nprefix] = \ - malloc(sizeof(struct prefix_entry))) == NULL){ - if(idata->verbose_f > 1) - puts("Error while storing Source Address"); + if ((cif->ip6_global.prefix[cif->ip6_global.nprefix] = malloc(sizeof(struct prefix_entry))) == NULL) { + if (idata->verbose_f > 1) + puts("Error while storing Source Address"); - freeifaddrs(ifptr); - return(FAILURE); - } + freeifaddrs(ifptr); + return (FAILURE); + } - (cif->ip6_global.prefix[cif->ip6_global.nprefix])->len = 128; - (cif->ip6_global.prefix[cif->ip6_global.nprefix])->ip6 = sockin6ptr->sin6_addr; - cif->ip6_global.nprefix++; - } - } - } + (cif->ip6_global.prefix[cif->ip6_global.nprefix])->len = 128; + (cif->ip6_global.prefix[cif->ip6_global.nprefix])->ip6 = sockin6ptr->sin6_addr; + cif->ip6_global.nprefix++; + } + } + } - freeifaddrs(ifptr); + freeifaddrs(ifptr); #ifdef DEBUG - debug_print_ifaces_data( &(idata->iflist)); + debug_print_ifaces_data(&(idata->iflist)); #endif - return(SUCCESS); + return (SUCCESS); } - - - /* * Function: debug_print_ifaces_data() * * Prints the data correspoding to each interface */ -void debug_print_ifaces_data(struct iface_list *iflist){ - unsigned int i, j; - struct iface_entry *iface; - char plinkaddr[ETHER_ADDR_PLEN]; - char pv6addr[INET6_ADDRSTRLEN]; +void debug_print_ifaces_data(struct iface_list *iflist) { + unsigned int i, j; + struct iface_entry *iface; + char plinkaddr[ETHER_ADDR_PLEN]; + char pv6addr[INET6_ADDRSTRLEN]; - for(i=0; i< iflist->nifaces; i++){ - iface= iflist->ifaces +i; + for (i = 0; i < iflist->nifaces; i++) { + iface = iflist->ifaces + i; - printf("DEBUG: Interface: %s (%d)\tFlags:%s%s\n", iface->iface, iface->ifindex, (iface->flags & IFACE_LOOPBACK)?" LOOPBACK":"",\ - (iface->flags & IFACE_TUNNEL)?"TUNNEL":""); + printf("DEBUG: Interface: %s (%d)\tFlags:%s%s\n", iface->iface, iface->ifindex, + (iface->flags & IFACE_LOOPBACK) ? " LOOPBACK" : "", (iface->flags & IFACE_TUNNEL) ? "TUNNEL" : ""); - if(iface->ether_f){ - if(ether_ntop(&(iface->ether), plinkaddr, sizeof(plinkaddr)) == 0){ - puts("DEBUG: ether_ntop(): Error converting address"); - exit(EXIT_FAILURE); - } + if (iface->ether_f) { + if (ether_ntop(&(iface->ether), plinkaddr, sizeof(plinkaddr)) == 0) { + puts("DEBUG: ether_ntop(): Error converting address"); + exit(EXIT_FAILURE); + } - printf("DEBUG: Link address: %s\n", plinkaddr); - } + printf("DEBUG: Link address: %s\n", plinkaddr); + } - if( (iface->ip6_global).nprefix){ - puts("DEBUG: Global addresses:"); + if ((iface->ip6_global).nprefix) { + puts("DEBUG: Global addresses:"); - for(j=0; j<(iface->ip6_global.nprefix); j++){ - if(inet_ntop(AF_INET6, &((iface->ip6_global.prefix[j])->ip6), pv6addr, sizeof(pv6addr)) == NULL){ - puts("DEBUG: inet_ntop(): Error converting IPv6 Address to presentation format"); - exit(EXIT_FAILURE); - } + for (j = 0; j < (iface->ip6_global.nprefix); j++) { + if (inet_ntop(AF_INET6, &((iface->ip6_global.prefix[j])->ip6), pv6addr, sizeof(pv6addr)) == NULL) { + puts("DEBUG: inet_ntop(): Error converting IPv6 Address to presentation format"); + exit(EXIT_FAILURE); + } - printf("DEBUG: %s\n", pv6addr); - } - } + printf("DEBUG: %s\n", pv6addr); + } + } - if( (iface->ip6_local).nprefix){ - puts("DEBUG: Local addresses:"); + if ((iface->ip6_local).nprefix) { + puts("DEBUG: Local addresses:"); - for(j=0; j<(iface->ip6_local.nprefix); j++){ - if(inet_ntop(AF_INET6, &((iface->ip6_local.prefix[j])->ip6), pv6addr, sizeof(pv6addr)) == NULL){ - puts("DEBUG: inet_ntop(): Error converting IPv6 Address to presentation format"); - exit(EXIT_FAILURE); - } + for (j = 0; j < (iface->ip6_local.nprefix); j++) { + if (inet_ntop(AF_INET6, &((iface->ip6_local.prefix[j])->ip6), pv6addr, sizeof(pv6addr)) == NULL) { + puts("DEBUG: inet_ntop(): Error converting IPv6 Address to presentation format"); + exit(EXIT_FAILURE); + } - printf("DEBUG: %s\n", pv6addr); - } - } + printf("DEBUG: %s\n", pv6addr); + } + } - puts(""); - } + puts(""); + } } - - /* * Function: find_iface_by_name() * * Finds an Interface (by name) in an Interface list */ -void *find_iface_by_name(struct iface_list *iflist, char *iface){ - unsigned int i; +void *find_iface_by_name(struct iface_list *iflist, char *iface) { + unsigned int i; - for(i=0; i < iflist->nifaces; i++){ - if(strncmp((iflist->ifaces[i]).iface, iface, IFACE_LENGTH) == 0) - return(&(iflist->ifaces[i])); - } + for (i = 0; i < iflist->nifaces; i++) { + if (strncmp((iflist->ifaces[i]).iface, iface, IFACE_LENGTH) == 0) + return (&(iflist->ifaces[i])); + } - return(NULL); + return (NULL); } - /* * Function: find_iface_by_index() * * Finds an Interface (by index) in an Interface list */ -void *find_iface_by_index(struct iface_list *iflist, int ifindex){ - unsigned int i; +void *find_iface_by_index(struct iface_list *iflist, int ifindex) { + unsigned int i; - for(i=0; i < iflist->nifaces; i++){ - if((iflist->ifaces[i]).ifindex == ifindex) - return(&(iflist->ifaces[i])); - } + for (i = 0; i < iflist->nifaces; i++) { + if ((iflist->ifaces[i]).ifindex == ifindex) + return (&(iflist->ifaces[i])); + } - return(NULL); + return (NULL); } - /* * Function: find_iface_by_addr() * * Finds an Interface (by IPv6 address) in an Interface list */ -void *find_iface_by_addr(struct iface_list *iflist, struct in6_addr *addr){ - unsigned int i; +void *find_iface_by_addr(struct iface_list *iflist, struct in6_addr *addr) { + unsigned int i; - for(i=0; i < iflist->nifaces; i++){ - if(is_ip6_in_prefix_list(addr, &((iflist->ifaces[i]).ip6_global)) || is_ip6_in_prefix_list(addr, &((iflist->ifaces[i]).ip6_local))) - return(&(iflist->ifaces[i])); - } + for (i = 0; i < iflist->nifaces; i++) { + if (is_ip6_in_prefix_list(addr, &((iflist->ifaces[i]).ip6_global)) || + is_ip6_in_prefix_list(addr, &((iflist->ifaces[i]).ip6_local))) + return (&(iflist->ifaces[i])); + } - return(NULL); + return (NULL); } - /* * Function: is_in6addr_iniface_list() * * Finds an Interface (by name) in an Interface list */ -int is_ip6_in_iface_entry(struct iface_list *iflist, int ifindex, struct in6_addr *addr){ - unsigned int i; +int is_ip6_in_iface_entry(struct iface_list *iflist, int ifindex, struct in6_addr *addr) { + unsigned int i; - for(i=0; i < iflist->nifaces; i++){ - if(iflist->ifaces[i].ifindex == ifindex){ - if(is_ip6_in_prefix_list(addr, &(iflist->ifaces[i].ip6_global))) - return(TRUE); - else if(is_ip6_in_prefix_list(addr, &(iflist->ifaces[i].ip6_local))) - return(TRUE); - } - } + for (i = 0; i < iflist->nifaces; i++) { + if (iflist->ifaces[i].ifindex == ifindex) { + if (is_ip6_in_prefix_list(addr, &(iflist->ifaces[i].ip6_global))) + return (TRUE); + else if (is_ip6_in_prefix_list(addr, &(iflist->ifaces[i].ip6_local))) + return (TRUE); + } + } - return(FALSE); + return (FALSE); } - /* * Function: find_matching_address() * * Finds the longest matching address in an Interface list */ -struct iface_entry *find_matching_address(struct iface_data *idata, struct iface_list *iflist, struct in6_addr *dst, struct in6_addr *match){ - unsigned int i, j, mlen, len; - struct iface_entry *cif=NULL; /* Not needed, but avoids warning in OpenBSD/gcc */ - mlen= 0; - - for(i=0; i < iflist->nifaces; i++){ - if(idata->iface_f && (idata->ifindex != (iflist->ifaces[i]).ifindex)) - continue; - - for(j=0; j < (iflist->ifaces[i]).ip6_local.nprefix; j++){ - if( (len= ip6_longest_match( &((iflist->ifaces[i].ip6_local.prefix[j])->ip6), dst)) >= mlen){ - cif= &(iflist->ifaces[i]); - *match= (iflist->ifaces[i].ip6_local.prefix[j])->ip6; - mlen= len; - } - - if(mlen >= 64){ - return(cif); - } - } - - for(j=0; j < (iflist->ifaces[i]).ip6_global.nprefix; j++){ - if( (len= ip6_longest_match( &((iflist->ifaces[i].ip6_global.prefix[j])->ip6), dst)) >= mlen){ - cif= &(iflist->ifaces[i]); - *match= (iflist->ifaces[i].ip6_global.prefix[j])->ip6; - mlen= len; - } - - if(mlen >= 64){ - return(cif); - } - } - } - - return(cif); +struct iface_entry *find_matching_address(struct iface_data *idata, struct iface_list *iflist, struct in6_addr *dst, + struct in6_addr *match) { + unsigned int i, j, mlen, len; + struct iface_entry *cif = NULL; /* Not needed, but avoids warning in OpenBSD/gcc */ + mlen = 0; + + for (i = 0; i < iflist->nifaces; i++) { + if (idata->iface_f && (idata->ifindex != (iflist->ifaces[i]).ifindex)) + continue; + + for (j = 0; j < (iflist->ifaces[i]).ip6_local.nprefix; j++) { + if ((len = ip6_longest_match(&((iflist->ifaces[i].ip6_local.prefix[j])->ip6), dst)) >= mlen) { + cif = &(iflist->ifaces[i]); + *match = (iflist->ifaces[i].ip6_local.prefix[j])->ip6; + mlen = len; + } + + if (mlen >= 64) { + return (cif); + } + } + + for (j = 0; j < (iflist->ifaces[i]).ip6_global.nprefix; j++) { + if ((len = ip6_longest_match(&((iflist->ifaces[i].ip6_global.prefix[j])->ip6), dst)) >= mlen) { + cif = &(iflist->ifaces[i]); + *match = (iflist->ifaces[i].ip6_global.prefix[j])->ip6; + mlen = len; + } + + if (mlen >= 64) { + return (cif); + } + } + } + + return (cif); } - /* * Function: ip6_longest_match() * * Finds the mask that two IPv6 addresses have in common * XXX */ -unsigned int ip6_longest_match(struct in6_addr *addr1, struct in6_addr *addr2){ - unsigned int mask, step=1, match=0; - struct in6_addr a1, a2; - - for(mask=0; mask <= 64; mask=mask+step){ - a1= *addr1; - a2= *addr2; - sanitize_ipv6_prefix(&a1, mask); - sanitize_ipv6_prefix(&a2, mask); - - if(!is_eq_in6_addr(&a1, &a2)) - return(match); - else - match=mask; - } - - return(64); +unsigned int ip6_longest_match(struct in6_addr *addr1, struct in6_addr *addr2) { + unsigned int mask, step = 1, match = 0; + struct in6_addr a1, a2; + + for (mask = 0; mask <= 64; mask = mask + step) { + a1 = *addr1; + a2 = *addr2; + sanitize_ipv6_prefix(&a1, mask); + sanitize_ipv6_prefix(&a2, mask); + + if (!is_eq_in6_addr(&a1, &a2)) + return (match); + else + match = mask; + } + + return (64); } - /* * Function: sel_src_addr() * * Selects a Source Address for a given Destination */ -int sel_src_addr(struct iface_data *idata){ - struct in6_addr match; - struct iface_entry *cif, *nhif; +int sel_src_addr(struct iface_data *idata) { + struct in6_addr match; + struct iface_entry *cif, *nhif; #ifdef DEBUG - puts("DEBUG: BEGIN sel_src_addr()"); + puts("DEBUG: BEGIN sel_src_addr()"); #endif - /* - If the packet is directed to a link-local addresses, the ourgoing interface should have been specified. - If not, that's a failure. If specified, we give higher priority to link-local addresses - */ - if(IN6_IS_ADDR_LINKLOCAL(&(idata->dstaddr))){ + /* + If the packet is directed to a link-local addresses, the ourgoing interface should have been specified. + If not, that's a failure. If specified, we give higher priority to link-local addresses + */ + if (IN6_IS_ADDR_LINKLOCAL(&(idata->dstaddr))) { #ifdef DEBUG - puts("DEBUG: Destination is link-local"); + puts("DEBUG: Destination is link-local"); #endif - if(!idata->iface_f){ + if (!idata->iface_f) { #ifdef DEBUG - puts("DEBUG: Interface not specified"); - puts("DEBUG: END sel_src_addr() (FAILURE)"); + puts("DEBUG: Interface not specified"); + puts("DEBUG: END sel_src_addr() (FAILURE)"); #endif - return(FAILURE); - } - else{ + return (FAILURE); + } + else { #ifdef DEBUG - puts("DEBUG: Interface has been specified"); + puts("DEBUG: Interface has been specified"); #endif - if( (cif=find_iface_by_index( &(idata->iflist), idata->ifindex)) == NULL){ + if ((cif = find_iface_by_index(&(idata->iflist), idata->ifindex)) == NULL) { #ifdef DEBUG - puts("DEBUG: Did not find interface in local data"); - puts("DEBUG: END sel_src_addr() (FAILURE)"); + puts("DEBUG: Did not find interface in local data"); + puts("DEBUG: END sel_src_addr() (FAILURE)"); #endif - return(FAILURE); - } - else{ + return (FAILURE); + } + else { #ifdef DEBUG - puts("DEBUG: Found interface in local data"); + puts("DEBUG: Found interface in local data"); #endif - idata->ether= cif->ether; - idata->ether_flag= cif->ether_f; - idata->flags= cif->flags; - - if((cif->ip6_local).nprefix){ - idata->ip6_local= (cif->ip6_local).prefix[0]->ip6; - idata->ip6_local_flag= TRUE; - } - - idata->ip6_global= cif->ip6_global; - if((idata->ip6_global).nprefix) - idata->ip6_global_flag= TRUE; - - /* - Since destination is a link-local address, use a link-local address as IPv6 Source Address - if available. - */ - if(idata->ip6_local_flag == TRUE){ - idata->srcaddr= (cif->ip6_local.prefix[0])->ip6; - idata->srcaddr_f= ADDR_AUTO; + idata->ether = cif->ether; + idata->ether_flag = cif->ether_f; + idata->flags = cif->flags; + + if ((cif->ip6_local).nprefix) { + idata->ip6_local = (cif->ip6_local).prefix[0]->ip6; + idata->ip6_local_flag = TRUE; + } + + idata->ip6_global = cif->ip6_global; + if ((idata->ip6_global).nprefix) + idata->ip6_global_flag = TRUE; + + /* + Since destination is a link-local address, use a link-local address as IPv6 Source Address + if available. + */ + if (idata->ip6_local_flag == TRUE) { + idata->srcaddr = (cif->ip6_local.prefix[0])->ip6; + idata->srcaddr_f = ADDR_AUTO; #ifdef DEBUG - puts("DEBUG: END sel_src_addr() (SUCCESS)"); + puts("DEBUG: END sel_src_addr() (SUCCESS)"); #endif - return(SUCCESS); - } - else if(idata->ip6_global_flag == TRUE){ - idata->srcaddr= (cif->ip6_local.prefix[0])->ip6; - idata->srcaddr_f= ADDR_AUTO; + return (SUCCESS); + } + else if (idata->ip6_global_flag == TRUE) { + idata->srcaddr = (cif->ip6_local.prefix[0])->ip6; + idata->srcaddr_f = ADDR_AUTO; #ifdef DEBUG - puts("DEBUG: END sel_src_addr() (SUCCESS)"); + puts("DEBUG: END sel_src_addr() (SUCCESS)"); #endif - return(SUCCESS); - } - } - } - } - else{ + return (SUCCESS); + } + } + } + } + else { #ifdef DEBUG - puts("DEBUG: Destination is NOT link-local"); + puts("DEBUG: Destination is NOT link-local"); #endif - /* - If the destination address is not a link-local address, then: + /* + If the destination address is not a link-local address, then: - 1) If the interface has been specified, we select an IPv6 address assigned to that interface - (prioritizing "global" addresses) + 1) If the interface has been specified, we select an IPv6 address assigned to that interface + (prioritizing "global" addresses) - 2) If an interface has not been specified, we select the longest-matching address for that - destination - */ - if(idata->iface_f){ + 2) If an interface has not been specified, we select the longest-matching address for that + destination + */ + if (idata->iface_f) { #ifdef DEBUG - puts("DEBUG: Interface was specified"); + puts("DEBUG: Interface was specified"); #endif - if( (cif=find_iface_by_index( &(idata->iflist), idata->ifindex)) == NULL){ + if ((cif = find_iface_by_index(&(idata->iflist), idata->ifindex)) == NULL) { #ifdef DEBUG - puts("DEBUG: Did not find interface in local data"); - puts("DEBUG: END sel_src_addr() (FAILURE)"); + puts("DEBUG: Did not find interface in local data"); + puts("DEBUG: END sel_src_addr() (FAILURE)"); #endif - return(FAILURE); - } - else{ - idata->ether= cif->ether; - idata->ether_flag= cif->ether_f; - idata->flags= cif->flags; - - idata->ip6_global= cif->ip6_global; - if(cif->ip6_global.nprefix){ - idata->ip6_global_flag= TRUE; - } - - if((cif->ip6_local).nprefix){ - idata->ip6_local= (cif->ip6_local).prefix[0]->ip6; - idata->ip6_local_flag= TRUE; - } - - if(idata->ip6_global_flag){ - /* XXX This should be replaced with "find the longest match for this list */ - idata->srcaddr= (idata->ip6_global).prefix[0]->ip6; - idata->srcaddr_f= ADDR_AUTO; + return (FAILURE); + } + else { + idata->ether = cif->ether; + idata->ether_flag = cif->ether_f; + idata->flags = cif->flags; + + idata->ip6_global = cif->ip6_global; + if (cif->ip6_global.nprefix) { + idata->ip6_global_flag = TRUE; + } + + if ((cif->ip6_local).nprefix) { + idata->ip6_local = (cif->ip6_local).prefix[0]->ip6; + idata->ip6_local_flag = TRUE; + } + + if (idata->ip6_global_flag) { + /* XXX This should be replaced with "find the longest match for this list */ + idata->srcaddr = (idata->ip6_global).prefix[0]->ip6; + idata->srcaddr_f = ADDR_AUTO; #ifdef DEBUG - puts("DEBUG: END sel_src_addr() Used global address (SUCCESS)"); + puts("DEBUG: END sel_src_addr() Used global address (SUCCESS)"); #endif - return(SUCCESS); - } - else if(idata->ip6_local_flag){ - idata->srcaddr= idata->ip6_local; - idata->srcaddr_f= ADDR_AUTO; + return (SUCCESS); + } + else if (idata->ip6_local_flag) { + idata->srcaddr = idata->ip6_local; + idata->srcaddr_f = ADDR_AUTO; #ifdef DEBUG - puts("DEBUG: END sel_src_addr() Used local address (SUCCESS)"); + puts("DEBUG: END sel_src_addr() Used local address (SUCCESS)"); #endif - return(SUCCESS); - } - else{ + return (SUCCESS); + } + else { #ifdef DEBUG - puts("DEBUG: END sel_src_addr() Have no IPv6 addresses (FAILURE)"); + puts("DEBUG: END sel_src_addr() Have no IPv6 addresses (FAILURE)"); #endif - return(FAILURE); - } - } - } - else{ + return (FAILURE); + } + } + } + else { #ifdef DEBUG - puts("DEBUG: Interface was not specified"); + puts("DEBUG: Interface was not specified"); #endif - if( (cif=find_matching_address(idata, &(idata->iflist), &(idata->dstaddr), &match)) != NULL){ - idata->srcaddr= match; - idata->srcaddr_f= ADDR_AUTO; - strncpy(idata->iface, cif->iface, IFACE_LENGTH); - idata->iface[IFACE_LENGTH-1]= 0; - idata->ifindex= cif->ifindex; - idata->ifindex_f= TRUE; - idata->flags= cif->flags; + if ((cif = find_matching_address(idata, &(idata->iflist), &(idata->dstaddr), &match)) != NULL) { + idata->srcaddr = match; + idata->srcaddr_f = ADDR_AUTO; + strncpy(idata->iface, cif->iface, IFACE_LENGTH); + idata->iface[IFACE_LENGTH - 1] = 0; + idata->ifindex = cif->ifindex; + idata->ifindex_f = TRUE; + idata->flags = cif->flags; #ifdef DEBUG - puts("DEBUG: Found a matching address"); - print_ipv6_address("DEBUG: Src addr: ", &(idata->srcaddr)); - printf("DEBUG: Interface name: %s, Index: %d\n", idata->iface, idata->ifindex); + puts("DEBUG: Found a matching address"); + print_ipv6_address("DEBUG: Src addr: ", &(idata->srcaddr)); + printf("DEBUG: Interface name: %s, Index: %d\n", idata->iface, idata->ifindex); #endif - /* - We know check whether the selected address belongs to the outgoing - interface -- otherwise packets might be filtered - */ + /* + We know check whether the selected address belongs to the outgoing + interface -- otherwise packets might be filtered + */ - - if(sel_next_hop(idata) == SUCCESS){ + if (sel_next_hop(idata) == SUCCESS) { #ifdef DEBUG - puts("DEBUG: sel_next_hop() suceeded"); + puts("DEBUG: sel_next_hop() suceeded"); #endif - if( (nhif=find_iface_by_index( &(idata->iflist), idata->nhifindex)) == NULL){ - return(FAILURE); - } + if ((nhif = find_iface_by_index(&(idata->iflist), idata->nhifindex)) == NULL) { + return (FAILURE); + } - if( (nhif->flags & IFACE_LOOPBACK) || is_ip6_in_iface_entry(&(idata->iflist), idata->nhifindex, &(idata->srcaddr)) == TRUE){ + if ((nhif->flags & IFACE_LOOPBACK) || + is_ip6_in_iface_entry(&(idata->iflist), idata->nhifindex, &(idata->srcaddr)) == TRUE) { #ifdef DEBUG - puts("DEBUG: Selected address was in outgoing interface"); + puts("DEBUG: Selected address was in outgoing interface"); #endif - if((cif->ip6_local).nprefix){ - idata->ip6_local= (cif->ip6_local).prefix[0]->ip6; - idata->ip6_local_flag= TRUE; - } + if ((cif->ip6_local).nprefix) { + idata->ip6_local = (cif->ip6_local).prefix[0]->ip6; + idata->ip6_local_flag = TRUE; + } - idata->ip6_global= cif->ip6_global; - if((idata->ip6_global).nprefix) - idata->ip6_global_flag= TRUE; + idata->ip6_global = cif->ip6_global; + if ((idata->ip6_global).nprefix) + idata->ip6_global_flag = TRUE; - idata->ether= cif->ether; - idata->ether_flag= cif->ether_f; - idata->srcaddr_f= ADDR_AUTO; + idata->ether = cif->ether; + idata->ether_flag = cif->ether_f; + idata->srcaddr_f = ADDR_AUTO; #ifdef DEBUG - print_ipv6_address("DEBUG: Src addr: ", &(idata->srcaddr)); - puts("DEBUG: END sel_src_addr() (SUCCESS)"); + print_ipv6_address("DEBUG: Src addr: ", &(idata->srcaddr)); + puts("DEBUG: END sel_src_addr() (SUCCESS)"); #endif - return(SUCCESS); - } - else{ + return (SUCCESS); + } + else { #ifdef DEBUG - puts("DEBUG: Selected address was NOT in outgoing interface"); + puts("DEBUG: Selected address was NOT in outgoing interface"); #endif - /* - If the seleted address doesn't correspond to the outgoing interface, throw away - the previously-selected IPv6 Address, and select one that is assigned to the - outgoing interface. - */ - if( (cif= find_iface_by_index(&(idata->iflist), idata->nhifindex)) == NULL){ + /* + If the seleted address doesn't correspond to the outgoing interface, throw away + the previously-selected IPv6 Address, and select one that is assigned to the + outgoing interface. + */ + if ((cif = find_iface_by_index(&(idata->iflist), idata->nhifindex)) == NULL) { #ifdef DEBUG - puts("DEBUG: END Did not find interface in local data"); - puts("DEBUG: END sel_src_addr() (FAILURE)"); + puts("DEBUG: END Did not find interface in local data"); + puts("DEBUG: END sel_src_addr() (FAILURE)"); #endif - return(FAILURE); - } - else{ + return (FAILURE); + } + else { #ifdef DEBUG - puts("DEBUG: Copying data from output interface into idata"); + puts("DEBUG: Copying data from output interface into idata"); #endif - idata->ether= cif->ether; - idata->ether_flag= cif->ether_f; - idata->ifindex= idata->nhifindex; - idata->flags= cif->flags; - strncpy(idata->iface, idata->nhiface, IFACE_LENGTH); - idata->iface[IFACE_LENGTH-1]= 0; - - if((cif->ip6_local).nprefix){ - idata->ip6_local= (cif->ip6_local).prefix[0]->ip6; - idata->ip6_local_flag= TRUE; - } - - idata->ip6_global= cif->ip6_global; - if((idata->ip6_global).nprefix) - idata->ip6_global_flag= TRUE; - - if(idata->ip6_global_flag == TRUE){ - idata->srcaddr= (cif->ip6_global.prefix[0])->ip6; - idata->srcaddr_f= ADDR_AUTO; + idata->ether = cif->ether; + idata->ether_flag = cif->ether_f; + idata->ifindex = idata->nhifindex; + idata->flags = cif->flags; + strncpy(idata->iface, idata->nhiface, IFACE_LENGTH); + idata->iface[IFACE_LENGTH - 1] = 0; + + if ((cif->ip6_local).nprefix) { + idata->ip6_local = (cif->ip6_local).prefix[0]->ip6; + idata->ip6_local_flag = TRUE; + } + + idata->ip6_global = cif->ip6_global; + if ((idata->ip6_global).nprefix) + idata->ip6_global_flag = TRUE; + + if (idata->ip6_global_flag == TRUE) { + idata->srcaddr = (cif->ip6_global.prefix[0])->ip6; + idata->srcaddr_f = ADDR_AUTO; #ifdef DEBUG - puts("DEBUG: Used global src addr for global dst addr"); - print_ipv6_address("DEBUG: Src addr: ", &(idata->srcaddr)); - puts("DEBUG: END sel_src_addr() (SUCCESS)"); + puts("DEBUG: Used global src addr for global dst addr"); + print_ipv6_address("DEBUG: Src addr: ", &(idata->srcaddr)); + puts("DEBUG: END sel_src_addr() (SUCCESS)"); #endif - return(SUCCESS); - } - else if(idata->ip6_local_flag){ - idata->srcaddr= idata->ip6_local; - idata->srcaddr_f= ADDR_AUTO; + return (SUCCESS); + } + else if (idata->ip6_local_flag) { + idata->srcaddr = idata->ip6_local; + idata->srcaddr_f = ADDR_AUTO; #ifdef DEBUG - puts("DEBUG: Used local src addr for global dst addr"); - print_ipv6_address("DEBUG: Src addr: ", &(idata->srcaddr)); - puts("DEBUG: END sel_src_addr() (SUCCESS)"); + puts("DEBUG: Used local src addr for global dst addr"); + print_ipv6_address("DEBUG: Src addr: ", &(idata->srcaddr)); + puts("DEBUG: END sel_src_addr() (SUCCESS)"); #endif - return(SUCCESS); - } - } - } - } - } - } - } + return (SUCCESS); + } + } + } + } + } + } + } #ifdef DEBUG - puts("DEBUG: END sel_src_addr() (FAILURE)"); + puts("DEBUG: END sel_src_addr() (FAILURE)"); #endif - return(FAILURE); + return (FAILURE); } - - /* * Function: load_dst_and_pcap() * * Finds the Sorurce Address, Next-Hop, and outgoing interface for a given Destination Address */ -int load_dst_and_pcap(struct iface_data *idata, unsigned int mode){ - struct iface_entry *cif, *rif; - struct in6_addr randprefix, loopback; - unsigned char randpreflen; - char errbuf[PCAP_ERRBUF_SIZE]; - - if(mode != LOAD_PCAP_ONLY && - (IN6_IS_ADDR_LINKLOCAL(&(idata->dstaddr)) || - IN6_IS_ADDR_MC_LINKLOCAL(&(idata->dstaddr)))) { - /* Special case where the Destination Address is a link-local address */ - if(!idata->iface_f){ - puts("Need to specify an interface ('-i' option) when Destination Address is link-local"); - return(FAILURE); - } - - if(!idata->ifindex_f){ - idata->ifindex= if_nametoindex(idata->iface); - idata->ifindex_f= TRUE; - } - - idata->nhifindex= idata->ifindex; - idata->nhifindex_f= TRUE; - - if(get_if_addrs(idata) == -1){ - if(idata->verbose_f){ - puts("Error while obtaining local interface data"); - } - - return(FAILURE); - } - } - else if(mode != LOAD_PCAP_ONLY){ - if(idata->srcprefix_f){ - randprefix= idata->srcaddr; - randpreflen= idata->srcpreflen; - randomize_ipv6_addr(&(idata->srcaddr), &randprefix, randpreflen); - idata->srcaddr_f=1; - } - - if(get_local_addrs(idata) == FAILURE){ - if(idata->verbose_f) - puts("Error while obtaining local addresses"); - - return(FAILURE); - } - - if(!idata->srcaddr_f){ +int load_dst_and_pcap(struct iface_data *idata, unsigned int mode) { + struct iface_entry *cif, *rif; + struct in6_addr randprefix, loopback; + unsigned char randpreflen; + char errbuf[PCAP_ERRBUF_SIZE]; + + if (mode != LOAD_PCAP_ONLY && + (IN6_IS_ADDR_LINKLOCAL(&(idata->dstaddr)) || IN6_IS_ADDR_MC_LINKLOCAL(&(idata->dstaddr)))) { + /* Special case where the Destination Address is a link-local address */ + if (!idata->iface_f) { + puts("Need to specify an interface ('-i' option) when Destination Address is link-local"); + return (FAILURE); + } + + if (!idata->ifindex_f) { + idata->ifindex = if_nametoindex(idata->iface); + idata->ifindex_f = TRUE; + } + + idata->nhifindex = idata->ifindex; + idata->nhifindex_f = TRUE; + + if (get_if_addrs(idata) == -1) { + if (idata->verbose_f) { + puts("Error while obtaining local interface data"); + } + + return (FAILURE); + } + } + else if (mode != LOAD_PCAP_ONLY) { + if (idata->srcprefix_f) { + randprefix = idata->srcaddr; + randpreflen = idata->srcpreflen; + randomize_ipv6_addr(&(idata->srcaddr), &randprefix, randpreflen); + idata->srcaddr_f = 1; + } + + if (get_local_addrs(idata) == FAILURE) { + if (idata->verbose_f) + puts("Error while obtaining local addresses"); + + return (FAILURE); + } + + if (!idata->srcaddr_f) { #ifdef DEBUG - puts("DEBUG: Has not specified source address"); + puts("DEBUG: Has not specified source address"); #endif - /* - If no source address or prefix have been specified, then we need to automatically learn our IPv6 - address. This is our appraoch: + /* + If no source address or prefix have been specified, then we need to automatically learn our IPv6 + address. This is our appraoch: - * Firstly, assume that our host has IPv6 connectivity: - + If an interface has been specified, select an IPv6 address from one of the configures addresses - of such interface. + * Firstly, assume that our host has IPv6 connectivity: + + If an interface has been specified, select an IPv6 address from one of the configures addresses + of such interface. - * If an interface has not been specified, select a source address taking into consideration - all configured addresses. + * If an interface has not been specified, select a source address taking into consideration + all configured addresses. - * If that doesn't succeed, try sending RAs + * If that doesn't succeed, try sending RAs - */ + */ - if(sel_src_addr(idata) == SUCCESS){ - if(sel_next_hop(idata) == SUCCESS){ - /* This is actually redundant (nh_f is already set by sel_next_hop() */ + if (sel_src_addr(idata) == SUCCESS) { + if (sel_next_hop(idata) == SUCCESS) { + /* This is actually redundant (nh_f is already set by sel_next_hop() */ #ifdef DEBUG - puts("DEBUG: sel_next_hop() succeeded"); + puts("DEBUG: sel_next_hop() succeeded"); #endif - idata->nh_f= TRUE; - } - else{ + idata->nh_f = TRUE; + } + else { #ifdef DEBUG - puts("DEBUG: sel_next_hop() failed"); + puts("DEBUG: sel_next_hop() failed"); #endif - } + } #ifdef DEBUG - printf("DEBUG: nhifindex_f: %s\tnhaddr_f: %s", (idata->nhifindex_f)?"TRUE":"FALSE", (idata->nhaddr_f)?"TRUE":"FALSE"); + printf("DEBUG: nhifindex_f: %s\tnhaddr_f: %s", (idata->nhifindex_f) ? "TRUE" : "FALSE", + (idata->nhaddr_f) ? "TRUE" : "FALSE"); - if(idata->nhifindex_f) - printf("\tnhifindex: %d ", idata->nhifindex); + if (idata->nhifindex_f) + printf("\tnhifindex: %d ", idata->nhifindex); - if(idata->nhaddr_f) - print_ipv6_address("\tnhaddr: ", &(idata->nhaddr)); - else - puts(""); + if (idata->nhaddr_f) + print_ipv6_address("\tnhaddr: ", &(idata->nhaddr)); + else + puts(""); #endif - } + } - if(idata->nh_f == FALSE){ + if (idata->nh_f == FALSE) { #ifdef DEBUG - puts("DEBUG: Automatic address selection failed"); + puts("DEBUG: Automatic address selection failed"); #endif - /* XXX Should really free the memory allocated by the other functions, since they are of no further use */ - idata->ip6_local_flag= FALSE; - idata->ip6_global.nprefix=0; - idata->ip6_global_flag= FALSE; + /* XXX Should really free the memory allocated by the other functions, since they are of no further use + */ + idata->ip6_local_flag = FALSE; + idata->ip6_global.nprefix = 0; + idata->ip6_global_flag = FALSE; - if(!idata->iface_f){ + if (!idata->iface_f) { #ifdef DEBUG - puts("DEBUG: No automatic address selection, and no specified interface"); + puts("DEBUG: No automatic address selection, and no specified interface"); #endif - if(idata->verbose_f) - puts("Could not determine next hop address"); - - return(FAILURE); - } - - /* This sends an RA, populates the local addresses and prefixes, and the local router */ - if(sel_next_hop_ra(idata) == -1){ + if (idata->verbose_f) + puts("Could not determine next hop address"); + + return (FAILURE); + } + + /* This sends an RA, populates the local addresses and prefixes, and the local router */ + if (sel_next_hop_ra(idata) == -1) { #ifdef DEBUG - puts("DEBUG: sel_next_hop_ra() failed"); + puts("DEBUG: sel_next_hop_ra() failed"); #endif - puts("Could not learn a local router"); - return(FAILURE); - } + puts("Could not learn a local router"); + return (FAILURE); + } - if(sel_src_addr_ra(idata, &(idata->dstaddr)) == FAILURE || !idata->ether_flag || !idata->ip6_global_flag || !idata->ip6_local_flag){ + if (sel_src_addr_ra(idata, &(idata->dstaddr)) == FAILURE || !idata->ether_flag || + !idata->ip6_global_flag || !idata->ip6_local_flag) { #ifdef DEBUG - puts("DEBUG: sel_src_addr_ra() failed"); + puts("DEBUG: sel_src_addr_ra() failed"); #endif - puts("Could not obtain local address **"); - return(FAILURE); - } - - idata->ifindex= if_nametoindex(idata->iface); - idata->ifindex_f= TRUE; - } - } - else{ + puts("Could not obtain local address **"); + return (FAILURE); + } + + idata->ifindex = if_nametoindex(idata->iface); + idata->ifindex_f = TRUE; + } + } + else { #ifdef DEBUG - puts("DEBUG: Has specified source address"); + puts("DEBUG: Has specified source address"); #endif - if(sel_next_hop(idata) == SUCCESS){ + if (sel_next_hop(idata) == SUCCESS) { #ifdef DEBUG - puts("DEBUG: sel_next_hop() succeeded"); + puts("DEBUG: sel_next_hop() succeeded"); #endif - idata->ifindex= idata->nhifindex; - idata->nh_f= TRUE; - strncpy(idata->iface, idata->nhiface, IFACE_LENGTH); - idata->iface[IFACE_LENGTH-1]= 0; - - if( (cif=find_iface_by_index(&(idata->iflist), idata->ifindex)) != NULL){ - idata->ether= cif->ether; - idata->ether_flag= cif->ether_f; - } - } - else{ + idata->ifindex = idata->nhifindex; + idata->nh_f = TRUE; + strncpy(idata->iface, idata->nhiface, IFACE_LENGTH); + idata->iface[IFACE_LENGTH - 1] = 0; + + if ((cif = find_iface_by_index(&(idata->iflist), idata->ifindex)) != NULL) { + idata->ether = cif->ether; + idata->ether_flag = cif->ether_f; + } + } + else { #ifdef DEBUG - puts("DEBUG: sel_next_hop() DID NOT succeed, Now trying RAs"); + puts("DEBUG: sel_next_hop() DID NOT succeed, Now trying RAs"); #endif - /* This sends an RA, populates the local addresses and prefixes, and the local router */ - if(sel_next_hop_ra(idata) == -1){ + /* This sends an RA, populates the local addresses and prefixes, and the local router */ + if (sel_next_hop_ra(idata) == -1) { #ifdef DEBUG - puts("DEBUG: ssel_next_hop_ra() failed"); + puts("DEBUG: ssel_next_hop_ra() failed"); #endif - puts("Could not learn a local router"); - return(FAILURE); - } - } - } - - /* - If a next hop was found, we employ whatever was found as the output interface, because we need to open - a pcap_t for that interface - */ - if(idata->nhifindex_f){ + puts("Could not learn a local router"); + return (FAILURE); + } + } + } + + /* + If a next hop was found, we employ whatever was found as the output interface, because we need to open + a pcap_t for that interface + */ + if (idata->nhifindex_f) { #ifdef DEBUG -puts("sel_next eligio nh_index"); + puts("sel_next eligio nh_index"); #endif - idata->ifindex= idata->nhifindex; + idata->ifindex = idata->nhifindex; - if( (cif = find_iface_by_index( &(idata->iflist), idata->ifindex)) == NULL){ - if(idata->verbose_f){ - puts("Could not find selected interface in local data"); - } + if ((cif = find_iface_by_index(&(idata->iflist), idata->ifindex)) == NULL) { + if (idata->verbose_f) { + puts("Could not find selected interface in local data"); + } #ifdef DEBUG -puts("No la interfaz que buscaba"); + puts("No la interfaz que buscaba"); #endif - return(FAILURE); - } + return (FAILURE); + } - idata->flags= cif->flags; + idata->flags = cif->flags; - if(if_indextoname(idata->ifindex, idata->iface) == NULL){ - if(idata->verbose_f) - puts("Error calling if_indextoname() from sel_next_hop()"); + if (if_indextoname(idata->ifindex, idata->iface) == NULL) { + if (idata->verbose_f) + puts("Error calling if_indextoname() from sel_next_hop()"); #ifdef DEBUG - puts("DEBUG: if_indextoname() failed"); + puts("DEBUG: if_indextoname() failed"); #endif - return(FAILURE); - } - } + return (FAILURE); + } + } #ifdef DEBUG -puts("Voy a chequear si es loopback"); + puts("Voy a chequear si es loopback"); #endif - if( !(idata->flags & IFACE_LOOPBACK)){ + if (!(idata->flags & IFACE_LOOPBACK)) { #ifdef DEBUG -puts("COmprobe que era distinta de loopback"); + puts("COmprobe que era distinta de loopback"); #endif - if(is_ip6_in_prefix_list( &(idata->dstaddr), &(idata->ip6_global)) || \ - is_eq_in6_addr( &(idata->dstaddr), &(idata->ip6_local))){ + if (is_ip6_in_prefix_list(&(idata->dstaddr), &(idata->ip6_global)) || + is_eq_in6_addr(&(idata->dstaddr), &(idata->ip6_local))) { #ifdef DEBUG -puts("ENcontre la dst en mi lista de direcciones"); + puts("ENcontre la dst en mi lista de direcciones"); #endif - /* - Since we're sending a packet on the same interface to which the destination address belongs, - the packet should actually be sent to the loopback interface - */ - if ( inet_pton(AF_INET6, LOOPBACK_ADDR, &loopback) <= 0){ - if(idata->verbose_f) - puts("inet_pton(): Error converting loopback address from presentation to network format"); + /* + Since we're sending a packet on the same interface to which the destination address belongs, + the packet should actually be sent to the loopback interface + */ + if (inet_pton(AF_INET6, LOOPBACK_ADDR, &loopback) <= 0) { + if (idata->verbose_f) + puts("inet_pton(): Error converting loopback address from presentation to network format"); #ifdef DEBUG -puts("inet_pton dio error"); + puts("inet_pton dio error"); #endif - return(FAILURE); - } + return (FAILURE); + } - if( (rif=find_iface_by_addr( &(idata->iflist), &loopback)) == NULL){ + if ((rif = find_iface_by_addr(&(idata->iflist), &loopback)) == NULL) { #ifdef DEBUG -puts("No encontre loopback"); + puts("No encontre loopback"); #endif - if(idata->verbose_f) - puts("Could not find loopback interface in local data"); + if (idata->verbose_f) + puts("Could not find loopback interface in local data"); - return(FAILURE); - } - else{ + return (FAILURE); + } + else { #ifdef DEBUG -puts("Encontre loopback y voy a sobreeescribir la info de destino"); + puts("Encontre loopback y voy a sobreeescribir la info de destino"); #endif - idata->flags= rif->flags; - idata->ifindex= rif->ifindex; - strncpy(idata->iface, rif->iface, IFACE_LENGTH); - idata->iface[IFACE_LENGTH-1]= 0; - } - } - } - - } - else{ - /* LOAD_PCAP_ONLY */ - - if(!idata->iface_f){ - if(idata->verbose_f){ - puts("Error opening pcap socket because interface was not specified"); - } - - return(FAILURE); - } - - idata->ifindex= if_nametoindex(idata->iface); - idata->ifindex_f= TRUE; - - if(get_if_addrs(idata) == -1){ - if(idata->verbose_f){ - puts("Error while obtaining local interface data"); - } - - return(FAILURE); - } - } - - if(idata->nhifindex_f && !idata->nhaddr_f) - idata->nhaddr= idata->dstaddr; + idata->flags = rif->flags; + idata->ifindex = rif->ifindex; + strncpy(idata->iface, rif->iface, IFACE_LENGTH); + idata->iface[IFACE_LENGTH - 1] = 0; + } + } + } + } + else { + /* LOAD_PCAP_ONLY */ + + if (!idata->iface_f) { + if (idata->verbose_f) { + puts("Error opening pcap socket because interface was not specified"); + } + + return (FAILURE); + } + + idata->ifindex = if_nametoindex(idata->iface); + idata->ifindex_f = TRUE; + + if (get_if_addrs(idata) == -1) { + if (idata->verbose_f) { + puts("Error while obtaining local interface data"); + } + + return (FAILURE); + } + } + + if (idata->nhifindex_f && !idata->nhaddr_f) + idata->nhaddr = idata->dstaddr; #ifdef DEBUG - if(idata->nhaddr_f) - print_ipv6_address("DEBUG: load_dst_(): Nex Hop: ", &(idata->nhaddr)); - else - puts("DEBUG: load_dst() Next Hop address not set"); + if (idata->nhaddr_f) + print_ipv6_address("DEBUG: load_dst_(): Nex Hop: ", &(idata->nhaddr)); + else + puts("DEBUG: load_dst() Next Hop address not set"); - printf("DEBUG: Output interface: %s (%d)\n", idata->iface, idata->ifindex); + printf("DEBUG: Output interface: %s (%d)\n", idata->iface, idata->ifindex); #endif - if(!(idata->hsrcaddr_f)){ - if(idata->ether_flag) - idata->hsrcaddr=idata->ether; - else{ - randomize_ether_addr(&(idata->hsrcaddr)); - } - } - - if(!idata->ip6_local_flag){ - ether_to_ipv6_linklocal(&idata->ether, &idata->ip6_local); - } - - if( (idata->pfd= pcap_open_live(idata->iface, PCAP_SNAP_LEN, PCAP_PROMISC, PCAP_TIMEOUT, errbuf)) == NULL){ - printf("pcap_open_live(%s): %s\n", idata->iface, errbuf); - return(FAILURE); - } - - if (pcap_setnonblock(idata->pfd, 1, errbuf) == -1) { - printf("pcap_setnonblock(): %s\n", errbuf); - return(FAILURE); - } - - if( (idata->fd= pcap_fileno(idata->pfd)) == -1){ - if(idata->verbose_f) - puts("Error obtaining descriptor number for pcap_t"); - - return(FAILURE); - } - - if( (idata->type = pcap_datalink(idata->pfd)) == DLT_EN10MB){ - idata->linkhsize= ETH_HLEN; - idata->mtu= ETH_DATA_LEN; - } - else if( idata->type == DLT_RAW){ - idata->linkhsize=0; - idata->mtu= MIN_IPV6_MTU; - idata->flags|= IFACE_TUNNEL; - } -#if defined (__OpenBSD__) - else if( idata->type == DLT_LOOP){ - idata->linkhsize=4; - idata->mtu= MIN_IPV6_MTU; - idata->flags|= IFACE_TUNNEL; - } + if (!(idata->hsrcaddr_f)) { + if (idata->ether_flag) + idata->hsrcaddr = idata->ether; + else { + randomize_ether_addr(&(idata->hsrcaddr)); + } + } + + if (!idata->ip6_local_flag) { + ether_to_ipv6_linklocal(&idata->ether, &idata->ip6_local); + } + + if ((idata->pfd = pcap_open_live(idata->iface, PCAP_SNAP_LEN, PCAP_PROMISC, PCAP_TIMEOUT, errbuf)) == NULL) { + printf("pcap_open_live(%s): %s\n", idata->iface, errbuf); + return (FAILURE); + } + + if (pcap_setnonblock(idata->pfd, 1, errbuf) == -1) { + printf("pcap_setnonblock(): %s\n", errbuf); + return (FAILURE); + } + + if ((idata->fd = pcap_fileno(idata->pfd)) == -1) { + if (idata->verbose_f) + puts("Error obtaining descriptor number for pcap_t"); + + return (FAILURE); + } + + if ((idata->type = pcap_datalink(idata->pfd)) == DLT_EN10MB) { + idata->linkhsize = ETH_HLEN; + idata->mtu = ETH_DATA_LEN; + } + else if (idata->type == DLT_RAW) { + idata->linkhsize = 0; + idata->mtu = MIN_IPV6_MTU; + idata->flags |= IFACE_TUNNEL; + } +#if defined(__OpenBSD__) + else if (idata->type == DLT_LOOP) { + idata->linkhsize = 4; + idata->mtu = MIN_IPV6_MTU; + idata->flags |= IFACE_TUNNEL; + } #elif defined(__linux__) - else if( idata->type == DLT_LINUX_SLL){ - idata->linkhsize= sizeof(struct sll_linux); - idata->mtu= MIN_IPV6_MTU; - idata->flags|= IFACE_TUNNEL; - } + else if (idata->type == DLT_LINUX_SLL) { + idata->linkhsize = sizeof(struct sll_linux); + idata->mtu = MIN_IPV6_MTU; + idata->flags |= IFACE_TUNNEL; + } #endif - else if(idata->type == DLT_NULL){ - idata->linkhsize=4; - idata->mtu= MIN_IPV6_MTU; - idata->flags|= IFACE_TUNNEL; - } - else{ + else if (idata->type == DLT_NULL) { + idata->linkhsize = 4; + idata->mtu = MIN_IPV6_MTU; + idata->flags |= IFACE_TUNNEL; + } + else { #ifdef DEBUG -puts("Estoy en load_dst() y voy a imprimir error"); + puts("Estoy en load_dst() y voy a imprimir error"); #endif - printf("Error: Interface %s is not of any supported type (type= %u)\n", idata->iface, idata->type); - return(FAILURE); - } - - if(idata->fragh_f) - idata->max_packet_size = MAX_IPV6_PAYLOAD + MIN_IPV6_HLEN; - else - idata->max_packet_size = idata->mtu; - - if(mode == LOAD_PCAP_ONLY) - return(SUCCESS); - - if(!(idata->flags & IFACE_TUNNEL) && !(idata->flags & IFACE_LOOPBACK)){ - if(!(idata->hdstaddr_f)){ - if(IN6_IS_ADDR_MULTICAST(&(idata->dstaddr))){ - idata->nhhaddr= ether_multicast(&(idata->dstaddr)); - } - else{ - if(ipv6_to_ether(idata->pfd, idata, &(idata->nhaddr), &(idata->nhhaddr)) != 1){ - puts("Error while performing Neighbor Discovery for the Destination Address"); - return(FAILURE); - } - } - - idata->hdstaddr= idata->nhhaddr; - } - } - - return(SUCCESS); + printf("Error: Interface %s is not of any supported type (type= %u)\n", idata->iface, idata->type); + return (FAILURE); + } + + if (idata->fragh_f) + idata->max_packet_size = MAX_IPV6_PAYLOAD + MIN_IPV6_HLEN; + else + idata->max_packet_size = idata->mtu; + + if (mode == LOAD_PCAP_ONLY) + return (SUCCESS); + + if (!(idata->flags & IFACE_TUNNEL) && !(idata->flags & IFACE_LOOPBACK)) { + if (!(idata->hdstaddr_f)) { + if (IN6_IS_ADDR_MULTICAST(&(idata->dstaddr))) { + idata->nhhaddr = ether_multicast(&(idata->dstaddr)); + } + else { + if (ipv6_to_ether(idata->pfd, idata, &(idata->nhaddr), &(idata->nhhaddr)) != 1) { + puts("Error while performing Neighbor Discovery for the Destination Address"); + return (FAILURE); + } + } + + idata->hdstaddr = idata->nhhaddr; + } + } + + return (SUCCESS); } - - /* * sanitize_ipv4_prefix() * * Clears those bits in an IPv4 address that are not within a prefix length. */ -void sanitize_ipv4_prefix(struct prefix4_entry *prefix4){ - unsigned int clear, i; - in_addr_t mask=0xffffffff; +void sanitize_ipv4_prefix(struct prefix4_entry *prefix4) { + unsigned int clear, i; + in_addr_t mask = 0xffffffff; - clear= 32-prefix4->len; + clear = 32 - prefix4->len; - for(i=0; i>1; + for (i = 0; i < clear; i++) + mask = mask >> 1; - for(i=0; iip.s_addr= prefix4->ip.s_addr & htonl(mask); + prefix4->ip.s_addr = prefix4->ip.s_addr & htonl(mask); } - - /* * Function: is_ip6_in_list() * * Checks whether an IPv6 address is present in an address list. */ -int is_ip6_in_list(struct in6_addr *target, struct host_list *hlist){ - unsigned int i; +int is_ip6_in_list(struct in6_addr *target, struct host_list *hlist) { + unsigned int i; - for(i=0; i < hlist->nhosts; i++) - if(is_eq_in6_addr(target, &((hlist->host[i])->ip6))) - return 1; + for (i = 0; i < hlist->nhosts; i++) + if (is_eq_in6_addr(target, &((hlist->host[i])->ip6))) + return 1; - return 0; + return 0; } - - /* * Function: dec_to_hex() * * Convert a decimal number into a number that has the same representation in hexadecimal */ -uint16_t dec_to_hex(uint16_t n){ - uint16_t r=0; - unsigned int d, i; +uint16_t dec_to_hex(uint16_t n) { + uint16_t r = 0; + unsigned int d, i; - /* The source number is truncated to the first four digits */ - n= n%10000; - d=1000; + /* The source number is truncated to the first four digits */ + n = n % 10000; + d = 1000; - for(i=0; i<4; i++){ - r= (r << 4) | (n/d); - n= n%d; - d=d/10; - } + for (i = 0; i < 4; i++) { + r = (r << 4) | (n / d); + n = n % d; + d = d / 10; + } - return(r); + return (r); } - /* * Function: keyval() * * Obtains a (variable, value) pair from a line of text in "variable=value # comments" format */ -int keyval(char *line, unsigned int len, char **key, char **val){ - char *ptr; - ptr= line; - - /* Skip initial spaces (e.g. " variable=value") */ - while( (*ptr==' ' || *ptr=='\t') && ptr < (line+len)) - ptr++; - - /* If we got to end of line or there is a comment or equal sign, there is no (variable, value) pair) */ - if(ptr==(line+len) || *ptr=='#' || *ptr=='=' || *ptr=='\r' || *ptr=='\n') - return 0; - - *key=ptr; - - /* The variable name is everything till (and excluding) the first separator character (e.g., space or tab) */ - while( (*ptr!=' ' && *ptr!='\t' && *ptr!='\r' && *ptr!='\n' && *ptr!='#' && *ptr!='=') && ptr < (line+len)) - ptr++; - - /* - If the variable name is followed by a comment sign, or occupies the entire line, there's an error - in the config file (i.e., there is no "variable=value" pair) - */ - if(ptr==(line+len) || *ptr=='#' || *ptr=='\r' || *ptr=='\n') - return -1; - - - if(*ptr==' ' || *ptr=='\t'){ - /* The variable name is followed by spaces -- skip them, and find the "equal to" sign */ - *ptr=0; /* NULL-terminate the key */ - ptr++; - - while(ptr<(line+len) && (*ptr==' ' || *ptr=='\t')) - ptr++; - - if(ptr==(line+len) || *ptr!='=') - return -1; - - ptr++; - }else{ - /* The variable name is followed by the "equal to" sign */ - *ptr=0; - ptr++; - } - - /* - If the equal sign is followed by spaces, skip them - */ - while( (*ptr==' ' || *ptr=='\t') && ptr<(line+len)) - ptr++; - - /* We found the "value" in the "variable=value" pair */ - *val=ptr; - - /* The value is everthing till (and excluding) the first separator character */ - while( (*ptr!='#' && *ptr!='\r' && *ptr!='\n' && *ptr!='\t' && *ptr!='=' && *ptr!=' ') && ptr < (line+len)) - ptr++; - - /* If the value string was actually "empty", we return an error */ - if(ptr == *val) - return(-1); - - *ptr=0; - return(1); +int keyval(char *line, unsigned int len, char **key, char **val) { + char *ptr; + ptr = line; + + /* Skip initial spaces (e.g. " variable=value") */ + while ((*ptr == ' ' || *ptr == '\t') && ptr < (line + len)) + ptr++; + + /* If we got to end of line or there is a comment or equal sign, there is no (variable, value) pair) */ + if (ptr == (line + len) || *ptr == '#' || *ptr == '=' || *ptr == '\r' || *ptr == '\n') + return 0; + + *key = ptr; + + /* The variable name is everything till (and excluding) the first separator character (e.g., space or tab) */ + while ((*ptr != ' ' && *ptr != '\t' && *ptr != '\r' && *ptr != '\n' && *ptr != '#' && *ptr != '=') && + ptr < (line + len)) + ptr++; + + /* + If the variable name is followed by a comment sign, or occupies the entire line, there's an error + in the config file (i.e., there is no "variable=value" pair) + */ + if (ptr == (line + len) || *ptr == '#' || *ptr == '\r' || *ptr == '\n') + return -1; + + if (*ptr == ' ' || *ptr == '\t') { + /* The variable name is followed by spaces -- skip them, and find the "equal to" sign */ + *ptr = 0; /* NULL-terminate the key */ + ptr++; + + while (ptr < (line + len) && (*ptr == ' ' || *ptr == '\t')) + ptr++; + + if (ptr == (line + len) || *ptr != '=') + return -1; + + ptr++; + } + else { + /* The variable name is followed by the "equal to" sign */ + *ptr = 0; + ptr++; + } + + /* + If the equal sign is followed by spaces, skip them + */ + while ((*ptr == ' ' || *ptr == '\t') && ptr < (line + len)) + ptr++; + + /* We found the "value" in the "variable=value" pair */ + *val = ptr; + + /* The value is everthing till (and excluding) the first separator character */ + while ((*ptr != '#' && *ptr != '\r' && *ptr != '\n' && *ptr != '\t' && *ptr != '=' && *ptr != ' ') && + ptr < (line + len)) + ptr++; + + /* If the value string was actually "empty", we return an error */ + if (ptr == *val) + return (-1); + + *ptr = 0; + return (1); } - /* * Function: address_contains_ranges() * @@ -4166,34 +4090,33 @@ int keyval(char *line, unsigned int len, char **key, char **val){ * /length prefix is considered invalid. */ -int address_contains_ranges(char *ptr){ - unsigned char slash_f=0, dash_f=0; - unsigned int i=0; - - while(i <= (MAX_RANGE_STR_LEN) && *ptr){ - if(*ptr == '-') - dash_f=1; - - if(*ptr=='/') - slash_f=1; - - ptr++; - i++; - } - - /* If the string contains both slashes and dashes, it is an error */ - if(dash_f){ - if(slash_f) - return(-1); - else - return(1); - } - else{ - return(0); - } +int address_contains_ranges(char *ptr) { + unsigned char slash_f = 0, dash_f = 0; + unsigned int i = 0; + + while (i <= (MAX_RANGE_STR_LEN) && *ptr) { + if (*ptr == '-') + dash_f = 1; + + if (*ptr == '/') + slash_f = 1; + + ptr++; + i++; + } + + /* If the string contains both slashes and dashes, it is an error */ + if (dash_f) { + if (slash_f) + return (-1); + else + return (1); + } + else { + return (0); + } } - /* * Function: address_contains_colons() * @@ -4201,382 +4124,376 @@ int address_contains_ranges(char *ptr){ * domain names and IPv6 addresses. */ -int address_contains_colons(char *ptr){ - unsigned char colon_f=0; - unsigned int i=0; +int address_contains_colons(char *ptr) { + unsigned char colon_f = 0; + unsigned int i = 0; - while(i <= (MAX_RANGE_STR_LEN) && *ptr){ - if(*ptr == ':') - colon_f=1; + while (i <= (MAX_RANGE_STR_LEN) && *ptr) { + if (*ptr == ':') + colon_f = 1; - ptr++; - i++; - } + ptr++; + i++; + } - if(colon_f) - return(1); - else - return(0); + if (colon_f) + return (1); + else + return (0); } - /* * Function: read_prefix() * * Obtain a pointer to the beginning of non-blank text, and zero-terminate that text upon space or comment. */ -int read_prefix(char *line, unsigned int len, char **start){ - char *end; +int read_prefix(char *line, unsigned int len, char **start) { + char *end; - *start=line; + *start = line; - while( (*start < (line + len)) && (**start==' ' || **start=='\t' || **start=='\r' || **start=='\n')){ - (*start)++; - } + while ((*start < (line + len)) && (**start == ' ' || **start == '\t' || **start == '\r' || **start == '\n')) { + (*start)++; + } - if( *start == (line + len)) - return(0); + if (*start == (line + len)) + return (0); - if( **start == '#') - return(0); + if (**start == '#') + return (0); - end= *start; + end = *start; - while( (end < (line + len)) && !(*end==' ' || *end=='\t' || *end=='#' || *end=='\r' || *end=='\n')) - end++; + while ((end < (line + len)) && !(*end == ' ' || *end == '\t' || *end == '#' || *end == '\r' || *end == '\n')) + end++; - *end=0; - return(1); + *end = 0; + return (1); } - /* * Function: read_ipv6_address() * * Obtains an IPv6 address (struct in6_addr) from a line of text in "IPv6_address # comments" format */ -int read_ipv6_address(char *line, unsigned int len, struct in6_addr *iid){ - char *ptr, *ipv6addr; - ptr= line; +int read_ipv6_address(char *line, unsigned int len, struct in6_addr *iid) { + char *ptr, *ipv6addr; + ptr = line; - /* Skip initial spaces (e.g. " IPv6_address") */ - while( (*ptr==' ' || *ptr=='\t') && ptr < (line+len)) - ptr++; + /* Skip initial spaces (e.g. " IPv6_address") */ + while ((*ptr == ' ' || *ptr == '\t') && ptr < (line + len)) + ptr++; - /* If we got to end of line or there is a comment or equal sign, there is no IPv6 address */ - if(ptr==(line+len) || *ptr=='#' || *ptr=='=' || *ptr=='\r' || *ptr=='\n') - return 0; + /* If we got to end of line or there is a comment or equal sign, there is no IPv6 address */ + if (ptr == (line + len) || *ptr == '#' || *ptr == '=' || *ptr == '\r' || *ptr == '\n') + return 0; - ipv6addr=ptr; + ipv6addr = ptr; - /* The IPv6 address is everything till (and excluding) the first separator character (e.g., space or tab) */ - while( (*ptr!=' ' && *ptr!='\t' && *ptr!='\r' && *ptr!='\n' && *ptr!='#' && *ptr!='=') && ptr < (line+len)) - ptr++; + /* The IPv6 address is everything till (and excluding) the first separator character (e.g., space or tab) */ + while ((*ptr != ' ' && *ptr != '\t' && *ptr != '\r' && *ptr != '\n' && *ptr != '#' && *ptr != '=') && + ptr < (line + len)) + ptr++; - /* NULL-terminate the ASCII-encoded IPv6 address */ - *ptr=0; + /* NULL-terminate the ASCII-encoded IPv6 address */ + *ptr = 0; - if ( inet_pton(AF_INET6, ipv6addr, iid) <= 0){ - return(-1); - } + if (inet_pton(AF_INET6, ipv6addr, iid) <= 0) { + return (-1); + } - return(1); + return (1); } - /* * Function: print_local_addrs() * * Debugging function to print all local addresses (starting from a struct iface_data *) */ -int print_local_addrs(struct iface_data *idata){ - unsigned int i, j; - char pv6addr[INET6_ADDRSTRLEN]; - char plinkaddr[ETHER_ADDR_PLEN]; +int print_local_addrs(struct iface_data *idata) { + unsigned int i, j; + char pv6addr[INET6_ADDRSTRLEN]; + char plinkaddr[ETHER_ADDR_PLEN]; - puts("List of local interfaces/addresses"); + puts("List of local interfaces/addresses"); - for(i=0; i < idata->iflist.nifaces; i++){ - if(ether_ntop(&((idata->iflist).ifaces[i].ether), plinkaddr, sizeof(plinkaddr)) == 0){ - puts("ether_ntop(): Error converting address"); - exit(EXIT_FAILURE); - } + for (i = 0; i < idata->iflist.nifaces; i++) { + if (ether_ntop(&((idata->iflist).ifaces[i].ether), plinkaddr, sizeof(plinkaddr)) == 0) { + puts("ether_ntop(): Error converting address"); + exit(EXIT_FAILURE); + } - printf("Name: %s\tIndex: %d\t Address: %s\n", (idata->iflist.ifaces[i]).iface, (idata->iflist.ifaces[i]).ifindex, plinkaddr); - puts("Link-local addresses:"); + printf("Name: %s\tIndex: %d\t Address: %s\n", (idata->iflist.ifaces[i]).iface, + (idata->iflist.ifaces[i]).ifindex, plinkaddr); + puts("Link-local addresses:"); - for(j=0; j < idata->iflist.ifaces[i].ip6_local.nprefix; j++){ - if(inet_ntop(AF_INET6, idata->iflist.ifaces[i].ip6_local.prefix[j], pv6addr, sizeof(pv6addr)) == NULL){ - puts("inet_ntop(): Error converting IPv6 address to presentation format"); - exit(EXIT_FAILURE); - } + for (j = 0; j < idata->iflist.ifaces[i].ip6_local.nprefix; j++) { + if (inet_ntop(AF_INET6, idata->iflist.ifaces[i].ip6_local.prefix[j], pv6addr, sizeof(pv6addr)) == NULL) { + puts("inet_ntop(): Error converting IPv6 address to presentation format"); + exit(EXIT_FAILURE); + } - printf("\t%s\n", pv6addr); - } + printf("\t%s\n", pv6addr); + } - puts("Global addresses:"); + puts("Global addresses:"); - for(j=0; j < idata->iflist.ifaces[i].ip6_global.nprefix; j++){ - if(inet_ntop(AF_INET6, idata->iflist.ifaces[i].ip6_global.prefix[j], pv6addr, sizeof(pv6addr)) == NULL){ - puts("inet_ntop(): Error converting IPv6 address to presentation format"); - exit(EXIT_FAILURE); - } + for (j = 0; j < idata->iflist.ifaces[i].ip6_global.nprefix; j++) { + if (inet_ntop(AF_INET6, idata->iflist.ifaces[i].ip6_global.prefix[j], pv6addr, sizeof(pv6addr)) == NULL) { + puts("inet_ntop(): Error converting IPv6 address to presentation format"); + exit(EXIT_FAILURE); + } - printf("\t%s\n", pv6addr); - } + printf("\t%s\n", pv6addr); + } - puts(""); - } + puts(""); + } - return(SUCCESS); + return (SUCCESS); } - /* * Function: find_ipv6_router() * * Finds a local router (by means of Neighbor Discovery) */ -int find_ipv6_router(pcap_t *pfd, struct ether_addr *hsrcaddr, struct in6_addr *srcaddr, \ - struct ether_addr *result_ether, struct in6_addr *result_ipv6){ - - struct pcap_pkthdr *pkthdr; - struct bpf_program pcap_filter; - const u_char *pktdata; - struct ether_header *pkt_ether; - struct ip6_hdr *pkt_ipv6; - struct nd_router_advert *pkt_ra; - unsigned char *pkt_end; - unsigned char *ptr, *prev_nh; - int r; - int nw; - - unsigned char buffer[65556]; - unsigned int rs_max_packet_size; - struct ether_header *ether; - unsigned char *v6buffer; - struct ip6_hdr *ipv6; - struct nd_router_solicit *rs; - struct nd_opt_slla *sllaopt; - volatile unsigned int tries=0; - volatile unsigned int foundrouter=0; - struct sigaction new_sig, old_sig; - - rs_max_packet_size = ETH_DATA_LEN; - - ether = (struct ether_header *) buffer; - v6buffer = buffer + sizeof(struct ether_header); - ipv6 = (struct ip6_hdr *) v6buffer; - - if(pcap_compile(pfd, &pcap_filter, PCAP_ICMPV6_RA_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1){ - printf("pcap_compile(): %s", pcap_geterr(pfd)); - return(-1); - } - - if(pcap_setfilter(pfd, &pcap_filter) == -1){ - printf("pcap_setfilter(): %s", pcap_geterr(pfd)); - return(-1); - } - - pcap_freecode(&pcap_filter); - - ipv6->ip6_flow=0; - ipv6->ip6_vfc= 0x60; - ipv6->ip6_hlim= 255; - ipv6->ip6_src= *srcaddr; - - if ( inet_pton(AF_INET6, ALL_ROUTERS_MULTICAST_ADDR, &(ipv6->ip6_dst)) <= 0){ - puts("inet_pton(): Error converting All Routers address from presentation to network format"); - return(-1); - } - - ether->src = *hsrcaddr; - - if(ether_pton(ETHER_ALLROUTERS_LINK_ADDR, &(ether->dst), sizeof(struct ether_addr)) == 0){ - puts("ether_pton(): Error converting all-nodes multicast address"); - return(-1); - } - - ether->ether_type = htons(ETHERTYPE_IPV6); - - prev_nh = (unsigned char *) &(ipv6->ip6_nxt); - *prev_nh = IPPROTO_ICMPV6; - - ptr = (unsigned char *) v6buffer + MIN_IPV6_HLEN; - - if( (ptr+sizeof(struct nd_router_solicit)) > (v6buffer+rs_max_packet_size)){ - puts("Packet too large while inserting Router Solicitation header"); - return(-1); - } - - rs= (struct nd_router_solicit *) (ptr); - - rs->nd_rs_type = ND_ROUTER_SOLICIT; - rs->nd_rs_code = 0; - rs->nd_rs_reserved = 0; - - ptr += sizeof(struct nd_router_solicit); - sllaopt = (struct nd_opt_slla *) ptr; - - if( (ptr+sizeof(struct nd_opt_slla)) > (v6buffer+rs_max_packet_size)){ - puts("RS message too large while processing source link-layer address opt."); - return(-1); - } - - sllaopt->type= ND_OPT_SOURCE_LINKADDR; - sllaopt->length= SLLA_OPT_LEN; - memcpy(sllaopt->address, &(hsrcaddr->a), ETH_ALEN); - ptr += sizeof(struct nd_opt_slla); - - ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); - rs->nd_rs_cksum = 0; - rs->nd_rs_cksum = in_chksum(v6buffer, rs, ptr-((unsigned char *)rs), IPPROTO_ICMPV6); - - /* We set the signal handler, and the anchor for siglongjump() */ - canjump=0; - memset(&new_sig, 0, sizeof(struct sigaction)); - sigemptyset(&new_sig.sa_mask); - new_sig.sa_handler= &sig_alarm; - - alarm(0); - - if( sigaction(SIGALRM, &new_sig, &old_sig) == -1){ - puts("Error setting up 'Alarm' signal"); - return(-1); - } - - if(sigsetjmp(env, 1) != 0) - tries++; - - canjump=1; - - while(tries<3 && !foundrouter){ - if((nw=pcap_inject(pfd, buffer, ptr - buffer)) == -1){ - printf("pcap_inject(): %s\n", pcap_geterr(pfd)); - return(-1); - } - - if(nw != (ptr-buffer)){ - printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, \ - (LUI) (ptr-buffer)); - return(-1); - } - - alarm(1); - - while(!foundrouter){ - if( (r=pcap_next_ex(pfd, &pkthdr, &pktdata)) == -1){ - printf("pcap_next_ex(): %s", pcap_geterr(pfd)); - exit(EXIT_FAILURE); - } - else if(r == 0 || pktdata == NULL){ - continue; /* Should never happen */ - } - - pkt_ether = (struct ether_header *) pktdata; - pkt_ipv6 = (struct ip6_hdr *)((char *) pkt_ether + ETHER_HDR_LEN); - pkt_ra = (struct nd_router_advert *) ((char *) pkt_ipv6 + MIN_IPV6_HLEN); - pkt_end = (unsigned char *) pktdata + pkthdr->caplen; - - - /* The packet length is the minimum of what we capured, and what is specified in the - IPv6 Total Lenght field - */ - if( pkt_end > ((unsigned char *)pkt_ra + ntohs(pkt_ipv6->ip6_plen)) ) - pkt_end = (unsigned char *)pkt_ra + ntohs(pkt_ipv6->ip6_plen); - - /* - Discard the packet if it is not of the minimum size to contain a Neighbor Advertisement - message with a source link-layer address option - */ - if( (pkt_end - (unsigned char *) pkt_ra) < (sizeof(struct nd_router_advert) + \ - sizeof(struct nd_opt_slla))) - continue; - - /* - Neighbor Discovery packets must have a Hop Limit of 255 - */ - if(pkt_ipv6->ip6_hlim != 255) - continue; - - /* - Check that the IPv6 packet encapsulates an ICMPv6 message - */ - if(pkt_ipv6->ip6_nxt != IPPROTO_ICMPV6) - continue; - - /* - Check that the ICMPv6 type corresponds to RA - */ - if(pkt_ra->nd_ra_type != ND_ROUTER_ADVERT) - continue; - - /* - Check that the ICMPv6 code is 0 - */ - if(pkt_ra->nd_ra_code != 0) - continue; - - /* - Check that the IPv6 Source Address of the Router Advertisement is an IPv6 link-local - address. - */ - if(!IN6_IS_ADDR_LINKLOCAL(&(pkt_ipv6->ip6_src))) - continue; - - /* - Check that that the Destination Address of the Router Advertisement is either the one - that we used for sending the Router Solicitation message or a multicast address (typically the all-nodes) - */ - if(!is_eq_in6_addr(&(pkt_ipv6->ip6_dst), &(ipv6->ip6_src)) && !IN6_IS_ADDR_MULTICAST(&(pkt_ipv6->ip6_dst))) - continue; - - /* Check that the ICMPv6 checksum is correct. If the received checksum is valid, - and we compute the checksum over the received packet (including the Checkdum field) - the result is 0. Otherwise, the packet has been corrupted. - */ - if(in_chksum(pkt_ipv6, pkt_ra, pkt_end- (unsigned char *)pkt_ra, IPPROTO_ICMPV6) != 0) - continue; - - ptr= (unsigned char *) pkt_ra + sizeof(struct nd_router_advert); - - /* Process Router Advertisement options */ - while( (ptr+sizeof(struct nd_opt_slla)) <= pkt_end && (*(ptr+1) != 0)){ - if(*ptr == ND_OPT_SOURCE_LINKADDR){ - if( (*(ptr+1) * 8) != sizeof(struct nd_opt_tlla)) - break; - - /* Got a response, so we shouln't time out */ - alarm(0); - - /* Save the link-layer address */ - *result_ether= *(struct ether_addr *) (ptr+2); - *result_ipv6= pkt_ipv6->ip6_src; - foundrouter=1; - break; - } - - ptr= ptr + *(ptr+1) * 8; - } /* Processing options */ - - } /* Processing packets */ - - } /* Resending Router Solicitations */ - - if( sigaction(SIGALRM, &old_sig, NULL) == -1){ - puts("Error setting up 'Alarm' signal"); - return(-1); - } - - if(foundrouter) - return 0; - else - return -1; -} +int find_ipv6_router(pcap_t *pfd, struct ether_addr *hsrcaddr, struct in6_addr *srcaddr, + struct ether_addr *result_ether, struct in6_addr *result_ipv6) { + + struct pcap_pkthdr *pkthdr; + struct bpf_program pcap_filter; + const u_char *pktdata; + struct ether_header *pkt_ether; + struct ip6_hdr *pkt_ipv6; + struct nd_router_advert *pkt_ra; + unsigned char *pkt_end; + unsigned char *ptr, *prev_nh; + int r; + int nw; + unsigned char buffer[65556]; + unsigned int rs_max_packet_size; + struct ether_header *ether; + unsigned char *v6buffer; + struct ip6_hdr *ipv6; + struct nd_router_solicit *rs; + struct nd_opt_slla *sllaopt; + volatile unsigned int tries = 0; + volatile unsigned int foundrouter = 0; + struct sigaction new_sig, old_sig; + + rs_max_packet_size = ETH_DATA_LEN; + + ether = (struct ether_header *)buffer; + v6buffer = buffer + sizeof(struct ether_header); + ipv6 = (struct ip6_hdr *)v6buffer; + + if (pcap_compile(pfd, &pcap_filter, PCAP_ICMPV6_RA_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1) { + printf("pcap_compile(): %s", pcap_geterr(pfd)); + return (-1); + } + + if (pcap_setfilter(pfd, &pcap_filter) == -1) { + printf("pcap_setfilter(): %s", pcap_geterr(pfd)); + return (-1); + } + + pcap_freecode(&pcap_filter); + + ipv6->ip6_flow = 0; + ipv6->ip6_vfc = 0x60; + ipv6->ip6_hlim = 255; + ipv6->ip6_src = *srcaddr; + + if (inet_pton(AF_INET6, ALL_ROUTERS_MULTICAST_ADDR, &(ipv6->ip6_dst)) <= 0) { + puts("inet_pton(): Error converting All Routers address from presentation to network format"); + return (-1); + } + + ether->src = *hsrcaddr; + + if (ether_pton(ETHER_ALLROUTERS_LINK_ADDR, &(ether->dst), sizeof(struct ether_addr)) == 0) { + puts("ether_pton(): Error converting all-nodes multicast address"); + return (-1); + } + + ether->ether_type = htons(ETHERTYPE_IPV6); + + prev_nh = (unsigned char *)&(ipv6->ip6_nxt); + *prev_nh = IPPROTO_ICMPV6; + + ptr = (unsigned char *)v6buffer + MIN_IPV6_HLEN; + + if ((ptr + sizeof(struct nd_router_solicit)) > (v6buffer + rs_max_packet_size)) { + puts("Packet too large while inserting Router Solicitation header"); + return (-1); + } + + rs = (struct nd_router_solicit *)(ptr); + + rs->nd_rs_type = ND_ROUTER_SOLICIT; + rs->nd_rs_code = 0; + rs->nd_rs_reserved = 0; + + ptr += sizeof(struct nd_router_solicit); + sllaopt = (struct nd_opt_slla *)ptr; + + if ((ptr + sizeof(struct nd_opt_slla)) > (v6buffer + rs_max_packet_size)) { + puts("RS message too large while processing source link-layer address opt."); + return (-1); + } + + sllaopt->type = ND_OPT_SOURCE_LINKADDR; + sllaopt->length = SLLA_OPT_LEN; + memcpy(sllaopt->address, &(hsrcaddr->a), ETH_ALEN); + ptr += sizeof(struct nd_opt_slla); + + ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); + rs->nd_rs_cksum = 0; + rs->nd_rs_cksum = in_chksum(v6buffer, rs, ptr - ((unsigned char *)rs), IPPROTO_ICMPV6); + + /* We set the signal handler, and the anchor for siglongjump() */ + canjump = 0; + memset(&new_sig, 0, sizeof(struct sigaction)); + sigemptyset(&new_sig.sa_mask); + new_sig.sa_handler = &sig_alarm; + + alarm(0); + + if (sigaction(SIGALRM, &new_sig, &old_sig) == -1) { + puts("Error setting up 'Alarm' signal"); + return (-1); + } + + if (sigsetjmp(env, 1) != 0) + tries++; + + canjump = 1; + + while (tries < 3 && !foundrouter) { + if ((nw = pcap_inject(pfd, buffer, ptr - buffer)) == -1) { + printf("pcap_inject(): %s\n", pcap_geterr(pfd)); + return (-1); + } + + if (nw != (ptr - buffer)) { + printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, (LUI)(ptr - buffer)); + return (-1); + } + + alarm(1); + + while (!foundrouter) { + if ((r = pcap_next_ex(pfd, &pkthdr, &pktdata)) == -1) { + printf("pcap_next_ex(): %s", pcap_geterr(pfd)); + exit(EXIT_FAILURE); + } + else if (r == 0 || pktdata == NULL) { + continue; /* Should never happen */ + } + + pkt_ether = (struct ether_header *)pktdata; + pkt_ipv6 = (struct ip6_hdr *)((char *)pkt_ether + ETHER_HDR_LEN); + pkt_ra = (struct nd_router_advert *)((char *)pkt_ipv6 + MIN_IPV6_HLEN); + pkt_end = (unsigned char *)pktdata + pkthdr->caplen; + + /* The packet length is the minimum of what we capured, and what is specified in the + IPv6 Total Lenght field + */ + if (pkt_end > ((unsigned char *)pkt_ra + ntohs(pkt_ipv6->ip6_plen))) + pkt_end = (unsigned char *)pkt_ra + ntohs(pkt_ipv6->ip6_plen); + + /* + Discard the packet if it is not of the minimum size to contain a Neighbor Advertisement + message with a source link-layer address option + */ + if ((pkt_end - (unsigned char *)pkt_ra) < (sizeof(struct nd_router_advert) + sizeof(struct nd_opt_slla))) + continue; + + /* + Neighbor Discovery packets must have a Hop Limit of 255 + */ + if (pkt_ipv6->ip6_hlim != 255) + continue; + + /* + Check that the IPv6 packet encapsulates an ICMPv6 message + */ + if (pkt_ipv6->ip6_nxt != IPPROTO_ICMPV6) + continue; + + /* + Check that the ICMPv6 type corresponds to RA + */ + if (pkt_ra->nd_ra_type != ND_ROUTER_ADVERT) + continue; + + /* + Check that the ICMPv6 code is 0 + */ + if (pkt_ra->nd_ra_code != 0) + continue; + + /* + Check that the IPv6 Source Address of the Router Advertisement is an IPv6 link-local + address. + */ + if (!IN6_IS_ADDR_LINKLOCAL(&(pkt_ipv6->ip6_src))) + continue; + + /* + Check that that the Destination Address of the Router Advertisement is either the one + that we used for sending the Router Solicitation message or a multicast address (typically the all-nodes) + */ + if (!is_eq_in6_addr(&(pkt_ipv6->ip6_dst), &(ipv6->ip6_src)) && !IN6_IS_ADDR_MULTICAST(&(pkt_ipv6->ip6_dst))) + continue; + + /* Check that the ICMPv6 checksum is correct. If the received checksum is valid, + and we compute the checksum over the received packet (including the Checkdum field) + the result is 0. Otherwise, the packet has been corrupted. + */ + if (in_chksum(pkt_ipv6, pkt_ra, pkt_end - (unsigned char *)pkt_ra, IPPROTO_ICMPV6) != 0) + continue; + + ptr = (unsigned char *)pkt_ra + sizeof(struct nd_router_advert); + + /* Process Router Advertisement options */ + while ((ptr + sizeof(struct nd_opt_slla)) <= pkt_end && (*(ptr + 1) != 0)) { + if (*ptr == ND_OPT_SOURCE_LINKADDR) { + if ((*(ptr + 1) * 8) != sizeof(struct nd_opt_tlla)) + break; + + /* Got a response, so we shouln't time out */ + alarm(0); + + /* Save the link-layer address */ + *result_ether = *(struct ether_addr *)(ptr + 2); + *result_ipv6 = pkt_ipv6->ip6_src; + foundrouter = 1; + break; + } + + ptr = ptr + *(ptr + 1) * 8; + } /* Processing options */ + + } /* Processing packets */ + + } /* Resending Router Solicitations */ + + if (sigaction(SIGALRM, &old_sig, NULL) == -1) { + puts("Error setting up 'Alarm' signal"); + return (-1); + } + + if (foundrouter) + return 0; + else + return -1; +} /* * Function: timeval timeval_sub() @@ -4584,39 +4501,36 @@ int find_ipv6_router(pcap_t *pfd, struct ether_addr *hsrcaddr, struct in6_addr * * Substract two struct timeval */ -struct timeval timeval_sub(struct timeval *t2, struct timeval *t1){ - struct timeval result; +struct timeval timeval_sub(struct timeval *t2, struct timeval *t1) { + struct timeval result; - if(t1->tv_usec > t2->tv_usec){ - result.tv_sec= t2->tv_sec - t1->tv_sec - 1; - result.tv_usec= 1000000 - t1->tv_usec + t2->tv_usec ; - } - else{ - result.tv_sec= t2->tv_sec - t1->tv_sec; - result.tv_usec= t2->tv_usec - t1->tv_usec ; - } + if (t1->tv_usec > t2->tv_usec) { + result.tv_sec = t2->tv_sec - t1->tv_sec - 1; + result.tv_usec = 1000000 - t1->tv_usec + t2->tv_usec; + } + else { + result.tv_sec = t2->tv_sec - t1->tv_sec; + result.tv_usec = t2->tv_usec - t1->tv_usec; + } - return(result); + return (result); } - /* * Function: time_diff_ms() * * Return the difference between two struct timeval (in msec) */ -float time_diff_ms(struct timeval *t2, struct timeval *t1){ - /* XXX: Need to review!! */ - - float result; - - result= t2->tv_sec * 1000 - t1->tv_sec * 1000 + (float ) t2->tv_usec / 1000 - (float) t1->tv_usec / 1000; +float time_diff_ms(struct timeval *t2, struct timeval *t1) { + /* XXX: Need to review!! */ - return(result); -} + float result; + result = t2->tv_sec * 1000 - t1->tv_sec * 1000 + (float)t2->tv_usec / 1000 - (float)t1->tv_usec / 1000; + return (result); +} /* * Function: dump_hex() @@ -4624,18 +4538,16 @@ float time_diff_ms(struct timeval *t2, struct timeval *t1){ * Prints a buffer in hexadecimal (mostly for debugging purposes) */ -void dump_hex(void* ptr, size_t s){ - unsigned int i; +void dump_hex(void *ptr, size_t s) { + unsigned int i; - for(i=0; i < s; i++){ - printf("%02x ", *( ((uint8_t *)ptr)+i) ); - } + for (i = 0; i < s; i++) { + printf("%02x ", *(((uint8_t *)ptr) + i)); + } - puts(""); + puts(""); } - - /* * Function: get_ipv6_target() * @@ -4643,83 +4555,80 @@ void dump_hex(void* ptr, size_t s){ * * Return value: 0: success, -1: name conversion error, 1: non-suitable address */ -int get_ipv6_target(struct target_ipv6 *target){ - struct addrinfo hints, *res, *ptr; - - memset(&hints, 0, sizeof(hints)); - hints.ai_flags= (target->flags)?AI_CANONNAME:0; - hints.ai_family= AF_INET6; - hints.ai_canonname = NULL; - hints.ai_addr = NULL; - hints.ai_next = NULL; - - if( (target->res = getaddrinfo(target->name, NULL, &hints, &res)) != 0){ - return(-1); - } - - /* If canonname is non-NULL, the canonic name is required */ - if(target->flags){ - if(res != NULL && res->ai_canonname != NULL){ - strncpy( target->canonname, res->ai_canonname, NI_MAXHOST); - target->canonname[NI_MAXHOST-1]=0; - } - else{ - target->canonname[0]=0; - target->flags=0; - } - } - - for(ptr=res; ptr != NULL; ptr=ptr->ai_next){ - if(ptr->ai_family != AF_INET6) - continue; - - if(ptr->ai_addrlen != sizeof(struct sockaddr_in6)) - continue; - - if(ptr->ai_addr == NULL) - continue; - - memcpy( &(target->ip6), &(( (struct sockaddr_in6 *)ptr->ai_addr)->sin6_addr), sizeof(struct in6_addr)); - break; - } - - freeaddrinfo(res); - - if(ptr != NULL) - return(0); - else - return(1); +int get_ipv6_target(struct target_ipv6 *target) { + struct addrinfo hints, *res, *ptr; + + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = (target->flags) ? AI_CANONNAME : 0; + hints.ai_family = AF_INET6; + hints.ai_canonname = NULL; + hints.ai_addr = NULL; + hints.ai_next = NULL; + + if ((target->res = getaddrinfo(target->name, NULL, &hints, &res)) != 0) { + return (-1); + } + + /* If canonname is non-NULL, the canonic name is required */ + if (target->flags) { + if (res != NULL && res->ai_canonname != NULL) { + strncpy(target->canonname, res->ai_canonname, NI_MAXHOST); + target->canonname[NI_MAXHOST - 1] = 0; + } + else { + target->canonname[0] = 0; + target->flags = 0; + } + } + + for (ptr = res; ptr != NULL; ptr = ptr->ai_next) { + if (ptr->ai_family != AF_INET6) + continue; + + if (ptr->ai_addrlen != sizeof(struct sockaddr_in6)) + continue; + + if (ptr->ai_addr == NULL) + continue; + + memcpy(&(target->ip6), &(((struct sockaddr_in6 *)ptr->ai_addr)->sin6_addr), sizeof(struct in6_addr)); + break; + } + + freeaddrinfo(res); + + if (ptr != NULL) + return (0); + else + return (1); } - /* * Function: is_iid_null() * * Checks whether the IID of a prefix is set to all-zeroes - * + * */ -int is_iid_null(struct in6_addr *prefix, uint8_t len){ - unsigned int skip, i; - uint32_t mask; +int is_iid_null(struct in6_addr *prefix, uint8_t len) { + unsigned int skip, i; + uint32_t mask; - skip= len/32; + skip = len / 32; - if(len%32){ - mask= 0xffffffff; - mask= mask >> (len%32); + if (len % 32) { + mask = 0xffffffff; + mask = mask >> (len % 32); - if(prefix->s6_addr32[skip] & htonl(mask)) - return(FALSE); + if (prefix->s6_addr32[skip] & htonl(mask)) + return (FALSE); - skip=skip+1; - } + skip = skip + 1; + } - for(i=skip; i<4; i++){ - if(prefix->s6_addr32[i]) - return(FALSE); + for (i = skip; i < 4; i++) { + if (prefix->s6_addr32[i]) + return (FALSE); + } - } - - return TRUE; + return TRUE; } - diff --git a/tools/libipv6.h b/tools/libipv6.h index 1638dd5..b19eeb8 100644 --- a/tools/libipv6.h +++ b/tools/libipv6.h @@ -2,371 +2,362 @@ #include #endif +#include /* For IFNAMSIZ */ #include -#include /* For IFNAMSIZ */ /* General constants */ -#define SUCCESS 1 -#define FAILURE 0 -#define TRUE 1 -#define FALSE 0 - -#define ADDR_AUTO 2 - - -#define LUI long unsigned int -#define CHAR_CR 0x0d -#define CHAR_LF 0x0a -#define DATA_BUFFER_LEN 1000 -#define LINE_BUFFER_SIZE 80 -#define MAX_STRING_SIZE 10 /* For limiting strncmp */ -#define MAX_RANGE_STR_LEN 79 /* For function that check for address ranges in string */ -#define ETH_ALEN 6 /* Octets in one ethernet addr */ -#define ETH_HLEN 14 /* Total octets in header. */ -#define ETH_DATA_LEN 1500 /* Max. octets in payload */ -#define ETHERTYPE_IPV6 0x86dd /* IP protocol version 6 */ -#define ETHER_ADDR_LEN ETH_ALEN /* size of ethernet addr */ -#define ETHER_HDR_LEN ETH_HLEN /* total octets in header */ - -#define ETHER_ADDR_PLEN 18 /* Includes termination byte */ - -#define ETHER_ALLNODES_LINK_ADDR "33:33:00:00:00:01" -#define ETHER_ALLROUTERS_LINK_ADDR "33:33:00:00:00:02" - -#define MIN_IPV6_HLEN 40 -#define MIN_IPV6_MTU 1280 -#define MIN_TCP_HLEN 20 -#define MIN_UDP_HLEN 8 -#define MIN_ICMP6_HLEN 8 -#define MIN_HBH_LEN 8 -#define MIN_EXT_HLEN 8 -#define SLLA_OPT_LEN 1 -#define TLLA_OPT_LEN 1 -#define MIN_DST_OPT_HDR_SIZE 8 -#define MAX_SLLA_OPTION 100 -#define MAX_TLLA_OPTION 256 -#define IFACE_LENGTH IFNAMSIZ -#define ALL_NODES_MULTICAST_ADDR "FF02::1" -#define ALL_ROUTERS_MULTICAST_ADDR "FF02::2" -#define LOOPBACK_ADDR "::1" +#define SUCCESS 1 +#define FAILURE 0 +#define TRUE 1 +#define FALSE 0 + +#define ADDR_AUTO 2 + +#define LUI long unsigned int +#define CHAR_CR 0x0d +#define CHAR_LF 0x0a +#define DATA_BUFFER_LEN 1000 +#define LINE_BUFFER_SIZE 80 +#define MAX_STRING_SIZE 10 /* For limiting strncmp */ +#define MAX_RANGE_STR_LEN 79 /* For function that check for address ranges in string */ +#define ETH_ALEN 6 /* Octets in one ethernet addr */ +#define ETH_HLEN 14 /* Total octets in header. */ +#define ETH_DATA_LEN 1500 /* Max. octets in payload */ +#define ETHERTYPE_IPV6 0x86dd /* IP protocol version 6 */ +#define ETHER_ADDR_LEN ETH_ALEN /* size of ethernet addr */ +#define ETHER_HDR_LEN ETH_HLEN /* total octets in header */ + +#define ETHER_ADDR_PLEN 18 /* Includes termination byte */ + +#define ETHER_ALLNODES_LINK_ADDR "33:33:00:00:00:01" +#define ETHER_ALLROUTERS_LINK_ADDR "33:33:00:00:00:02" + +#define MIN_IPV6_HLEN 40 +#define MIN_IPV6_MTU 1280 +#define MIN_TCP_HLEN 20 +#define MIN_UDP_HLEN 8 +#define MIN_ICMP6_HLEN 8 +#define MIN_HBH_LEN 8 +#define MIN_EXT_HLEN 8 +#define SLLA_OPT_LEN 1 +#define TLLA_OPT_LEN 1 +#define MIN_DST_OPT_HDR_SIZE 8 +#define MAX_SLLA_OPTION 100 +#define MAX_TLLA_OPTION 256 +#define IFACE_LENGTH IFNAMSIZ +#define ALL_NODES_MULTICAST_ADDR "FF02::1" +#define ALL_ROUTERS_MULTICAST_ADDR "FF02::2" +#define LOOPBACK_ADDR "::1" #define SOLICITED_NODE_MULTICAST_PREFIX "FF02:0:0:0:0:1:FF00::" - /* Support for IPv6 extension headers */ -#define FRAG_HDR_SIZE 8 -#define MAX_IPV6_PAYLOAD 65535 -#define MAX_DST_OPT_HDR 1024 -#define MAX_DST_OPT_U_HDR MAX_DST_OPT_HDR -#define MAX_HBH_OPT_HDR MAX_DST_OPT_HDR +#define FRAG_HDR_SIZE 8 +#define MAX_IPV6_PAYLOAD 65535 +#define MAX_DST_OPT_HDR 1024 +#define MAX_DST_OPT_U_HDR MAX_DST_OPT_HDR +#define MAX_HBH_OPT_HDR MAX_DST_OPT_HDR /* Filter Constants */ -#define MAX_BLOCK_SRC 50 -#define MAX_BLOCK_DST 50 -#define MAX_BLOCK_TARGET 50 -#define MAX_BLOCK_LINK_SRC 50 -#define MAX_BLOCK_LINK_DST 50 - -struct filters{ - /* Block Filters */ - struct in6_addr *blocksrc; - struct in6_addr *blockdst; - struct in6_addr *blocktarget; - - uint8_t *blocksrclen; - uint8_t *blockdstlen; - uint8_t *blocktargetlen; - - struct ether_addr *blocklinksrc; - struct ether_addr *blocklinkdst; - - unsigned int nblocksrc; - unsigned int nblockdst; - unsigned int nblocktarget; - unsigned int nblocklinksrc; - unsigned int nblocklinkdst; - - /* Accept Filters */ - struct in6_addr *acceptsrc; - struct in6_addr *acceptdst; - struct in6_addr *accepttarget; - - uint8_t *acceptsrclen; - uint8_t *acceptdstlen; - uint8_t *accepttargetlen; - unsigned char acceptfilters_f; - - struct ether_addr *acceptlinksrc; - struct ether_addr *acceptlinkdst; - - unsigned int nacceptsrc; - unsigned int nacceptdst; - unsigned int naccepttarget; - unsigned int nacceptlinksrc; - unsigned int nacceptlinkdst; +#define MAX_BLOCK_SRC 50 +#define MAX_BLOCK_DST 50 +#define MAX_BLOCK_TARGET 50 +#define MAX_BLOCK_LINK_SRC 50 +#define MAX_BLOCK_LINK_DST 50 + +struct filters { + /* Block Filters */ + struct in6_addr *blocksrc; + struct in6_addr *blockdst; + struct in6_addr *blocktarget; + + uint8_t *blocksrclen; + uint8_t *blockdstlen; + uint8_t *blocktargetlen; + + struct ether_addr *blocklinksrc; + struct ether_addr *blocklinkdst; + + unsigned int nblocksrc; + unsigned int nblockdst; + unsigned int nblocktarget; + unsigned int nblocklinksrc; + unsigned int nblocklinkdst; + + /* Accept Filters */ + struct in6_addr *acceptsrc; + struct in6_addr *acceptdst; + struct in6_addr *accepttarget; + + uint8_t *acceptsrclen; + uint8_t *acceptdstlen; + uint8_t *accepttargetlen; + unsigned char acceptfilters_f; + + struct ether_addr *acceptlinksrc; + struct ether_addr *acceptlinkdst; + + unsigned int nacceptsrc; + unsigned int nacceptdst; + unsigned int naccepttarget; + unsigned int nacceptlinksrc; + unsigned int nacceptlinkdst; }; -#define MAX_ACCEPT_SRC 50 -#define MAX_ACCEPT_DST 50 -#define MAX_ACCEPT_TARGET 50 -#define MAX_ACCEPT_LINK_SRC 50 -#define MAX_ACCEPT_LINK_DST 50 - -#define ACCEPTED 1 -#define BLOCKED 0 +#define MAX_ACCEPT_SRC 50 +#define MAX_ACCEPT_DST 50 +#define MAX_ACCEPT_TARGET 50 +#define MAX_ACCEPT_LINK_SRC 50 +#define MAX_ACCEPT_LINK_DST 50 +#define ACCEPTED 1 +#define BLOCKED 0 /* Constants used with the libcap functions */ -#define PCAP_SNAP_LEN 65535 -#define PCAP_PROMISC 1 -#define PCAP_OPT 1 +#define PCAP_SNAP_LEN 65535 +#define PCAP_PROMISC 1 +#define PCAP_OPT 1 #ifndef PCAP_NETMASK_UNKNOWN - #define PCAP_NETMASK_UNKNOWN 0xffffffff +#define PCAP_NETMASK_UNKNOWN 0xffffffff #endif /* XXX: -At some point we were setting the timeout differently for different platforms. Should double-check, but doesn't seem to make sense. +At some point we were setting the timeout differently for different platforms. Should double-check, but doesn't seem to +make sense. -#if defined (__FreeBSD__) || defined(__NetBSD__) || defined (__OpenBSD__) || defined(__APPLE__) || defined(__FreeBSD_kernel__) || defined(sun) || defined(__sun) - #define PCAP_TIMEOUT 1 -#else - #define PCAP_TIMEOUT 0 -#endif +#if defined (__FreeBSD__) || defined(__NetBSD__) || defined (__OpenBSD__) || defined(__APPLE__) || +defined(__FreeBSD_kernel__) || defined(sun) || defined(__sun) #define PCAP_TIMEOUT 1 #else #define +PCAP_TIMEOUT 0 #endif */ -#define PCAP_TIMEOUT 1 +#define PCAP_TIMEOUT 1 -#define PCAP_IPV6_FILTER "ip6" -#define PCAP_TCPV6_FILTER "ip6 and tcp" -#define PCAP_UDPV6_FILTER "ip6 and udp" -#define PCAP_ICMPV6_FILTER "icmp6" -#define PCAP_ICMPV6_NA_FILTER "icmp6 and ip6[7]==255 and ip6[40]==136 and ip6[41]==0" +#define PCAP_IPV6_FILTER "ip6" +#define PCAP_TCPV6_FILTER "ip6 and tcp" +#define PCAP_UDPV6_FILTER "ip6 and udp" +#define PCAP_ICMPV6_FILTER "icmp6" +#define PCAP_ICMPV6_NA_FILTER "icmp6 and ip6[7]==255 and ip6[40]==136 and ip6[41]==0" /* XXX: Should check the na6 code: we fail to receive packets (Ubuntu, at least) when this filter is set #define PCAP_ICMPV6_NS_FILTER "icmp6 and ((ip6[7]==255 and ip6[40]==135 and ip6[41]==0) or ip6[40]==4)" */ -#define PCAP_ICMPV6_NS_FILTER "ip6" +#define PCAP_ICMPV6_NS_FILTER "ip6" #define PCAP_ICMPV6_RA_FILTER "icmp6 and ip6[7]==255 and ip6[40]==134 and ip6[41]==0" -#define PCAP_ICMPV6_RANS_FILTER "icmp6 and ip6[7]==255 and ((ip6[40]==134 and ip6[41]==0) or (ip6[40]==135 and ip6[41]==0))" -#define PCAP_TCPIPV6_NS_FILTER "ip6 and (tcp or (icmp6 and ip6[7]==255 and ip6[40]==135 and ip6[41]==0))" +#define PCAP_ICMPV6_RANS_FILTER \ + "icmp6 and ip6[7]==255 and ((ip6[40]==134 and ip6[41]==0) or (ip6[40]==135 and ip6[41]==0))" +#define PCAP_TCPIPV6_NS_FILTER "ip6 and (tcp or (icmp6 and ip6[7]==255 and ip6[40]==135 and ip6[41]==0))" /* #define PCAP_TCPIPV6_NS_FILTER "ip6" */ -#define PCAP_UDPIPV6_NS_FILTER "ip6 and (udp or (icmp6 and ip6[7]==255 and ip6[40]==135 and ip6[41]==0))" -#define PCAP_ICMPV6_NI_QUERY "icmp6 and ip6[40]==139" -#define PCAP_ICMPV6_NI_REPLY "icmp6 and ip6[40]==140" -#define PCAP_NOPACKETS_FILTER "not ip and not ip6 and not arp" -#define PCAP_ICMPV6NSEXCEEDED_FILTER "icmp6 and ((ip6[40]==3 and ip6[41]==1) or (ip6[40]==129 and ip6[41]==0))" -#define PCAP_ICMPV6_RS_FILTER "icmp6 and ip6[7]==255 and ip6[40]==133 and ip6[41]==0" -#define PCAP_ICMPV6_NSECHOEXCEEDED_FILTER "icmp6 and ((ip6[40]==3 and ip6[41]==1) or (ip6[40]==129 and ip6[41]==0) or (ip6[7]==255 and ip6[40]==135 and ip6[41]==0))" +#define PCAP_UDPIPV6_NS_FILTER "ip6 and (udp or (icmp6 and ip6[7]==255 and ip6[40]==135 and ip6[41]==0))" +#define PCAP_ICMPV6_NI_QUERY "icmp6 and ip6[40]==139" +#define PCAP_ICMPV6_NI_REPLY "icmp6 and ip6[40]==140" +#define PCAP_NOPACKETS_FILTER "not ip and not ip6 and not arp" +#define PCAP_ICMPV6NSEXCEEDED_FILTER "icmp6 and ((ip6[40]==3 and ip6[41]==1) or (ip6[40]==129 and ip6[41]==0))" +#define PCAP_ICMPV6_RS_FILTER "icmp6 and ip6[7]==255 and ip6[40]==133 and ip6[41]==0" +#define PCAP_ICMPV6_NSECHOEXCEEDED_FILTER \ + "icmp6 and ((ip6[40]==3 and ip6[41]==1) or (ip6[40]==129 and ip6[41]==0) or (ip6[7]==255 and ip6[40]==135 and " \ + "ip6[41]==0))" /* Filter to receive Neighbor Solicitations and Fragmented packets */ #define PCAP_ICMPV6NSFRAG_FILTER "(ip6[7]==255 and icmp6 and ip6[40]==135 and ip6[41]==0) or (ip6 and ip6[6]==44)" #define PCAP_NSTCP_FILTER "(ip6[7]==255 and icmp6 and ip6[40]==135 and ip6[41]==0) or (ip6 and ip6[6]==6)" - /* Filter to receive Neighbor Solicitations and Fragmented packets */ #define PCAP_ICMPV6NSFRAG_FILTER "(ip6[7]==255 and icmp6 and ip6[40]==135 and ip6[41]==0) or (ip6 and ip6[6]==44)" /* -#define PCAP_ICMPV6NSEXCEEDED_FILTER "icmp6 and ((ip6[7]==255 and ip6[40]==135 and ip6[41]==0) or (ip6[40]==3 and ip6[41]==1) or (ip6[40]==129 and ip6[41]==0))" +#define PCAP_ICMPV6NSEXCEEDED_FILTER "icmp6 and ((ip6[7]==255 and ip6[40]==135 and ip6[41]==0) or (ip6[40]==3 and +ip6[41]==1) or (ip6[40]==129 and ip6[41]==0))" */ #define PCAP_TCPIPV6_FILTER "ip6 and tcp" /* Originally from scan6.h */ -#define PCAP_ICMPV6_NA_FILTER "icmp6 and ip6[7]==255 and ip6[40]==136 and ip6[41]==0" -#define PCAP_ICMPV6_RANS_FILTER "icmp6 and ip6[7]==255 and ((ip6[40]==134 and ip6[41]==0) or (ip6[40]==135 and ip6[41]==0))" -#define PCAP_ICMPV6_ERNS_FILTER "icmp6 and ((ip6[40]==129 and ip6[41]==0) or (ip6[40]==135 and ip6[41]==0))" -#define PCAP_ICMPV6_ERRORNS_FILTER "icmp6 and ((ip6[40]==4) or (ip6[40]==135 and ip6[41]==0))" - -#define PCAP_ICMPV6_ERQNSNA_FILTER "icmp6 and ((ip6[40]==129 and ip6[41]==0) or ((ip6[40]==135 or ip6[40]==136) and ip6[41]==0 and ip6[7]==255))" -#define PCAP_ICMPV6_ERRORNSNA_FILTER "icmp6 and ((ip6[40]==4) or ((ip6[7]==255 and ip6[41]==0) and (ip6[40]==135 or ip6[40]==136)))" -#define PCAP_TCP_NSNA_FILTER "(ip6 and tcp) or (icmp6 and ip6[7]==255 and ip6[41]==0 and (ip6[40]==135 or ip6[40]==136))" -#define PCAP_UDP_NSNA_FILTER "(ip6 and (udp or icmp6))" +#define PCAP_ICMPV6_NA_FILTER "icmp6 and ip6[7]==255 and ip6[40]==136 and ip6[41]==0" +#define PCAP_ICMPV6_RANS_FILTER \ + "icmp6 and ip6[7]==255 and ((ip6[40]==134 and ip6[41]==0) or (ip6[40]==135 and ip6[41]==0))" +#define PCAP_ICMPV6_ERNS_FILTER "icmp6 and ((ip6[40]==129 and ip6[41]==0) or (ip6[40]==135 and ip6[41]==0))" +#define PCAP_ICMPV6_ERRORNS_FILTER "icmp6 and ((ip6[40]==4) or (ip6[40]==135 and ip6[41]==0))" + +#define PCAP_ICMPV6_ERQNSNA_FILTER \ + "icmp6 and ((ip6[40]==129 and ip6[41]==0) or ((ip6[40]==135 or ip6[40]==136) and ip6[41]==0 and ip6[7]==255))" +#define PCAP_ICMPV6_ERRORNSNA_FILTER \ + "icmp6 and ((ip6[40]==4) or ((ip6[7]==255 and ip6[41]==0) and (ip6[40]==135 or ip6[40]==136)))" +#define PCAP_TCP_NSNA_FILTER \ + "(ip6 and tcp) or (icmp6 and ip6[7]==255 and ip6[41]==0 and (ip6[40]==135 or ip6[40]==136))" +#define PCAP_UDP_NSNA_FILTER "(ip6 and (udp or icmp6))" /* -#define PCAP_UDP_NSNA_FILTER "(ip6 and (udp or icmp6)) or (icmp6 and ip6[7]==255 and ip6[41]==0 and (ip6[40]==135 or ip6[40]==136))" +#define PCAP_UDP_NSNA_FILTER "(ip6 and (udp or icmp6)) or (icmp6 and ip6[7]==255 and ip6[41]==0 and +(ip6[40]==135 or ip6[40]==136))" */ -#define PCAP_TCP_UDP_NSNA_FILTER "(ip6 and (tcp or udp or icmp6))" +#define PCAP_TCP_UDP_NSNA_FILTER "(ip6 and (tcp or udp or icmp6))" /* -#define PCAP_TCP_UDP_NSNA_FILTER "(ip6 and (tcp or udp or icmp6)) or (icmp6 and ip6[7]==255 and ip6[41]==0 and (ip6[40]==135 or ip6[40]==136))" +#define PCAP_TCP_UDP_NSNA_FILTER "(ip6 and (tcp or udp or icmp6)) or (icmp6 and ip6[7]==255 and ip6[41]==0 and +(ip6[40]==135 or ip6[40]==136))" */ - /* Constants used for Router Discovery */ -#define MAX_PREFIXES_ONLINK 100 -#define MAX_PREFIXES_AUTO 100 -#define MAX_LOCAL_ADDRESSES 256 - +#define MAX_PREFIXES_ONLINK 100 +#define MAX_PREFIXES_AUTO 100 +#define MAX_LOCAL_ADDRESSES 256 /* Constants used for sending Router Advertisements */ -#define MAX_PREFIX_OPTION 256 -#define MAX_ROUTE_OPTION MAX_PREFIX_OPTION -#define MAX_MTU_OPTION MAX_PREFIX_OPTION -#define MAX_RDNSS_OPTION MAX_PREFIX_OPTION -#define MAX_RDNSS_OPT_ADDRS 127 -#define DEFAULT_PREFIX_PREFERRED 0xffffffff -#define DEFAULT_PREFIX_VALID 0xffffffff -#define DEFAULT_CURHOP 255 -#define DEFAULT_ROUTER_LIFETIME 9000 -#define DEFAULT_ROUTER_REACHABLE 0Xffffffff -#define DEFAULT_ROUTER_RETRANS 4000 -#define DEFAULT_ROUTER_PREFERENCE 0x08 -#define DEFAULT_RDNSS_LIFETIME 9000 -#define DEFAULT_ROUTE_OPT_LIFE 0xffffffff -#define DEFAULT_ROUTE_OPT_PREF 0x08 - - +#define MAX_PREFIX_OPTION 256 +#define MAX_ROUTE_OPTION MAX_PREFIX_OPTION +#define MAX_MTU_OPTION MAX_PREFIX_OPTION +#define MAX_RDNSS_OPTION MAX_PREFIX_OPTION +#define MAX_RDNSS_OPT_ADDRS 127 +#define DEFAULT_PREFIX_PREFERRED 0xffffffff +#define DEFAULT_PREFIX_VALID 0xffffffff +#define DEFAULT_CURHOP 255 +#define DEFAULT_ROUTER_LIFETIME 9000 +#define DEFAULT_ROUTER_REACHABLE 0Xffffffff +#define DEFAULT_ROUTER_RETRANS 4000 +#define DEFAULT_ROUTER_PREFERENCE 0x08 +#define DEFAULT_RDNSS_LIFETIME 9000 +#define DEFAULT_ROUTE_OPT_LIFE 0xffffffff +#define DEFAULT_ROUTE_OPT_PREF 0x08 /* For Fragment ID or Flow Label assessment */ -#define ID_ASSESS_TIMEOUT 5 -#define NSAMPLES 40 -#define FIXED_ORIGIN 1 -#define MULTI_ORIGIN 2 +#define ID_ASSESS_TIMEOUT 5 +#define NSAMPLES 40 +#define FIXED_ORIGIN 1 +#define MULTI_ORIGIN 2 - -struct ether_addr{ - uint8_t a[ETHER_ADDR_LEN]; -} __attribute__ ((__packed__)); +struct ether_addr { + uint8_t a[ETHER_ADDR_LEN]; +} __attribute__((__packed__)); /* For DLT_NULL encapsulation */ -struct dlt_null -{ - uint32_t family; /* Protocol Family */ -} __attribute__ ((__packed__)); - +struct dlt_null { + uint32_t family; /* Protocol Family */ +} __attribute__((__packed__)); /* IPv6 options - Most stacks define "struct ip_opt" for this purpose. But it has proved to be painful to use this - structure in Mac OS, since its definition seems to depend on the Xcode version, which is hard - (if at all possible) to check at compile time. As a workaround, we define our own data type for + Most stacks define "struct ip_opt" for this purpose. But it has proved to be painful to use this + structure in Mac OS, since its definition seems to depend on the Xcode version, which is hard + (if at all possible) to check at compile time. As a workaround, we define our own data type for IPv6 options */ -struct ip6_option{ - uint8_t ip6o_type; - uint8_t ip6o_len; -} __attribute__ ((__packed__)); - -struct nd_opt_slla{ - uint8_t type; - uint8_t length; - uint8_t address[6]; -} __attribute__ ((__packed__)); - -struct nd_opt_tlla{ - uint8_t type; - uint8_t length; - uint8_t address[6]; -} __attribute__ ((__packed__)); - -struct nd_opt_route_info_l{ - uint8_t nd_opt_ri_type; - uint8_t nd_opt_ri_len; - uint8_t nd_opt_ri_prefix_len; - uint8_t nd_opt_ri_rsvd_pref_rsvd; - uint32_t nd_opt_ri_lifetime; - struct in6_addr nd_opt_ri_prefix; -} __attribute__ ((__packed__)); - -struct nd_opt_rdnss_l{ - uint8_t nd_opt_rdnss_type; - uint8_t nd_opt_rdnss_len; - uint16_t nd_opt_rdnss_rsvd; - uint32_t nd_opt_rdnss_lifetime; - struct in6_addr nd_opt_rdnss_addr[]; -} __attribute__ ((__packed__)); - -struct ipv6pseudohdr{ +struct ip6_option { + uint8_t ip6o_type; + uint8_t ip6o_len; +} __attribute__((__packed__)); + +struct nd_opt_slla { + uint8_t type; + uint8_t length; + uint8_t address[6]; +} __attribute__((__packed__)); + +struct nd_opt_tlla { + uint8_t type; + uint8_t length; + uint8_t address[6]; +} __attribute__((__packed__)); + +struct nd_opt_route_info_l { + uint8_t nd_opt_ri_type; + uint8_t nd_opt_ri_len; + uint8_t nd_opt_ri_prefix_len; + uint8_t nd_opt_ri_rsvd_pref_rsvd; + uint32_t nd_opt_ri_lifetime; + struct in6_addr nd_opt_ri_prefix; +} __attribute__((__packed__)); + +struct nd_opt_rdnss_l { + uint8_t nd_opt_rdnss_type; + uint8_t nd_opt_rdnss_len; + uint16_t nd_opt_rdnss_rsvd; + uint32_t nd_opt_rdnss_lifetime; + struct in6_addr nd_opt_rdnss_addr[]; +} __attribute__((__packed__)); + +struct ipv6pseudohdr { struct in6_addr srcaddr; struct in6_addr dstaddr; - uint32_t len; + uint32_t len; uint8_t zero[3]; - uint8_t nh; -} __attribute__ ((__packed__)); + uint8_t nh; +} __attribute__((__packed__)); /* 10Mb/s ethernet header */ -struct ether_header{ - struct ether_addr dst; /* destination eth addr */ - struct ether_addr src; /* source ether addr */ - uint16_t ether_type; /* packet type ID field */ -} __attribute__ ((__packed__)); - +struct ether_header { + struct ether_addr dst; /* destination eth addr */ + struct ether_addr src; /* source ether addr */ + uint16_t ether_type; /* packet type ID field */ +} __attribute__((__packed__)); /* Generic extension header. */ -struct ip6_eh{ - uint8_t eh_nxt; /* next header. */ - uint8_t eh_len; /* length in units of 8 octets. */ -} __attribute__ ((__packed__)); - +struct ip6_eh { + uint8_t eh_nxt; /* next header. */ + uint8_t eh_len; /* length in units of 8 octets. */ +} __attribute__((__packed__)); /* Solaris does not define this one */ #if defined(sun) || defined(__sun) - struct ip6_ext { - uint8_t ip6e_nxt; - uint8_t ip6e_len; - } __attribute__ ((__packed__)); +struct ip6_ext { + uint8_t ip6e_nxt; + uint8_t ip6e_len; +} __attribute__((__packed__)); #endif - -typedef uint32_t tcp_seq; - - +typedef uint32_t tcp_seq; /* XXX: To be removed * Definitions required for OSX 10.6.8 with Xcode 3.2.6 */ /* #ifndef __BYTE_ORDER__ - #ifdef __LITTLE_ENDIAN__ - #define __BYTE_ORDER__ __LITTLE_ENDIAN__ - #elif defined(__BIG_ENDIAN__) - #define __BYTE_ORDER__ __BIG_ENDIAN__ - #endif + #ifdef __LITTLE_ENDIAN__ + #define __BYTE_ORDER__ __LITTLE_ENDIAN__ + #elif defined(__BIG_ENDIAN__) + #define __BYTE_ORDER__ __BIG_ENDIAN__ + #endif #endif #ifndef __ORDER_LITTLE_ENDIAN__ - #define __ORDER_LITTLE_ENDIAN__ __LITTLE_ENDIAN__ + #define __ORDER_LITTLE_ENDIAN__ __LITTLE_ENDIAN__ #endif #ifndef __ORDER_BIG_ENDIAN__ - #define __ORDER_BIG_ENDIAN__ __BIG_ENDIAN__ + #define __ORDER_BIG_ENDIAN__ __BIG_ENDIAN__ #endif */ - /* Different OSes employ different constants fo specifying the byte order. We employ the native Linux one, and if not available, map the BSD, Mac OS, or Solaris into the Linux one. */ #ifndef __BYTE_ORDER - #define __LITTLE_ENDIAN 1234 - #define __BIG_ENDIAN 4321 - - /* Mac OS */ - #if defined (__BYTE_ORDER__) - # if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ - #define __BYTE_ORDER __LITTLE_ENDIAN - #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ - #define __BYTE_ORDER __BIG_ENDIAN - #endif - - /* BSD */ - #elif defined(_BYTE_ORDER) - #if _BYTE_ORDER == _LITTLE_ENDIAN - #define __BYTE_ORDER __LITTLE_ENDIAN - #elif _BYTE_ORDER == _BIG_ENDIAN - #define __BYTE_ORDER __BIG_ENDIAN - #endif - /* XXX: Solaris. There should be a better constant on which to check the byte order */ - #elif defined(sun) || defined (__sun) - #if defined(_BIT_FIELDS_LTOH) - #define __BYTE_ORDER __LITTLE_ENDIAN - #else - #define __BYTE_ORDER __IG_ENDIAN - #endif - #endif +#define __LITTLE_ENDIAN 1234 +#define __BIG_ENDIAN 4321 + +/* Mac OS */ +#if defined(__BYTE_ORDER__) +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define __BYTE_ORDER __LITTLE_ENDIAN +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define __BYTE_ORDER __BIG_ENDIAN #endif +/* BSD */ +#elif defined(_BYTE_ORDER) +#if _BYTE_ORDER == _LITTLE_ENDIAN +#define __BYTE_ORDER __LITTLE_ENDIAN +#elif _BYTE_ORDER == _BIG_ENDIAN +#define __BYTE_ORDER __BIG_ENDIAN +#endif +/* XXX: Solaris. There should be a better constant on which to check the byte order */ +#elif defined(sun) || defined(__sun) +#if defined(_BIT_FIELDS_LTOH) +#define __BYTE_ORDER __LITTLE_ENDIAN +#else +#define __BYTE_ORDER __IG_ENDIAN +#endif +#endif +#endif /* BSD definition */ @@ -375,56 +366,54 @@ typedef uint32_t tcp_seq; * Per RFC 793, September, 1981. */ struct tcp_hdr { - uint16_t th_sport; /* source port */ - uint16_t th_dport; /* destination port */ - tcp_seq th_seq; /* sequence number */ - tcp_seq th_ack; /* acknowledgement number */ + uint16_t th_sport; /* source port */ + uint16_t th_dport; /* destination port */ + tcp_seq th_seq; /* sequence number */ + tcp_seq th_ack; /* acknowledgement number */ #if __BYTE_ORDER == __LITTLE_ENDIAN - uint32_t th_x2:4, /* (unused) */ - th_off:4; /* data offset */ + uint32_t th_x2 : 4, /* (unused) */ + th_off : 4; /* data offset */ #endif -# if __BYTE_ORDER == __BIG_ENDIAN - uint32_t th_off:4, /* data offset */ - th_x2:4; /* (unused) */ +#if __BYTE_ORDER == __BIG_ENDIAN + uint32_t th_off : 4, /* data offset */ + th_x2 : 4; /* (unused) */ #endif - uint8_t th_flags; -#define TH_FIN 0x01 -#define TH_SYN 0x02 -#define TH_RST 0x04 -#define TH_PUSH 0x08 -#define TH_ACK 0x10 -#define TH_URG 0x20 -#define TH_ECE 0x40 -#define TH_CWR 0x80 - uint16_t th_win; /* window */ - uint16_t th_sum; /* checksum */ - uint16_t th_urp; /* urgent pointer */ + uint8_t th_flags; +#define TH_FIN 0x01 +#define TH_SYN 0x02 +#define TH_RST 0x04 +#define TH_PUSH 0x08 +#define TH_ACK 0x10 +#define TH_URG 0x20 +#define TH_ECE 0x40 +#define TH_CWR 0x80 + uint16_t th_win; /* window */ + uint16_t th_sum; /* checksum */ + uint16_t th_urp; /* urgent pointer */ }; /* - 0 7 8 15 16 23 24 31 - +--------+--------+--------+--------+ - | Source | Destination | - | Port | Port | - +--------+--------+--------+--------+ - | | | - | Length | Checksum | - +--------+--------+--------+--------+ - | - | data octets ... - +---------------- ... + 0 7 8 15 16 23 24 31 + +--------+--------+--------+--------+ + | Source | Destination | + | Port | Port | + +--------+--------+--------+--------+ + | | | + | Length | Checksum | + +--------+--------+--------+--------+ + | + | data octets ... + +---------------- ... User Datagram Header Format */ -struct udp_hdr{ - uint16_t uh_sport; /* source port */ - uint16_t uh_dport; /* destination port */ - uint16_t uh_ulen; /* udp length */ - uint16_t uh_sum; /* udp checksum */ -} __attribute__ ((__packed__)); - - +struct udp_hdr { + uint16_t uh_sport; /* source port */ + uint16_t uh_dport; /* destination port */ + uint16_t uh_ulen; /* udp length */ + uint16_t uh_sum; /* udp checksum */ +} __attribute__((__packed__)); /* Definition of the Authentication Header 0 1 2 3 @@ -441,15 +430,14 @@ struct udp_hdr{ | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ -struct ah_hdr{ - uint8_t ah_nxt; /* Next Header */ - uint8_t ah_len; /* Payload length */ - uint16_t ah_rsvd; /* Reserved */ - uint32_t ah_spi; /* Reserved */ - uint32_t ah_seq; /* Reserved */ - uint32_t ah_icv; /* Integrity Check Value - ICV */ -} __attribute__ ((__packed__)); - +struct ah_hdr { + uint8_t ah_nxt; /* Next Header */ + uint8_t ah_len; /* Payload length */ + uint16_t ah_rsvd; /* Reserved */ + uint32_t ah_spi; /* Reserved */ + uint32_t ah_seq; /* Reserved */ + uint32_t ah_icv; /* Integrity Check Value - ICV */ +} __attribute__((__packed__)); /* Definition of the Encapsulating Security Payload @@ -473,424 +461,397 @@ struct ah_hdr{ | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ -struct esp_hdr{ - uint32_t esp_spi; /* Reserved */ - uint32_t esp_seq; /* Reserved */ - uint32_t ah_payload; /* Integrity Check Value - ICV */ -} __attribute__ ((__packed__)); - - - -#define ARP_REQUEST 1 -#define ARP_REPLY 2 -#define RARP_REQUEST 3 -#define RARP_REPLY 4 - -struct arp_hdr{ - struct ether_header ether; - uint16_t hard_type; /* packet type ID field */ - uint16_t prot_type; /* packet type ID field */ - uint8_t hard_size; - uint8_t prot_size; - uint8_t op; - struct ether_addr src_ether; - struct in_addr src_ip; - struct ether_addr tgt_ether; - struct in_addr tgt_ip; -} __attribute__ ((__packed__)); - +struct esp_hdr { + uint32_t esp_spi; /* Reserved */ + uint32_t esp_seq; /* Reserved */ + uint32_t ah_payload; /* Integrity Check Value - ICV */ +} __attribute__((__packed__)); + +#define ARP_REQUEST 1 +#define ARP_REPLY 2 +#define RARP_REQUEST 3 +#define RARP_REPLY 4 + +struct arp_hdr { + struct ether_header ether; + uint16_t hard_type; /* packet type ID field */ + uint16_t prot_type; /* packet type ID field */ + uint8_t hard_size; + uint8_t prot_size; + uint8_t op; + struct ether_addr src_ether; + struct in_addr src_ip; + struct ether_addr tgt_ether; + struct in_addr tgt_ip; +} __attribute__((__packed__)); /* For obtaining an IPv6 target */ -struct target_ipv6{ - struct in6_addr ip6; /* IPv6 address */ - char name [NI_MAXHOST]; /* Name */ - char canonname [NI_MAXHOST]; /* Canonic name */ - int res; /* Error code */ - unsigned int flags; /* Value-result: Whether the canonic name is required/obtained */ +struct target_ipv6 { + struct in6_addr ip6; /* IPv6 address */ + char name[NI_MAXHOST]; /* Name */ + char canonname[NI_MAXHOST]; /* Canonic name */ + int res; /* Error code */ + unsigned int flags; /* Value-result: Whether the canonic name is required/obtained */ }; -struct prefix_entry{ - struct in6_addr ip6; - unsigned char len; +struct prefix_entry { + struct in6_addr ip6; + unsigned char len; }; -struct prefix_list{ - struct prefix_entry **prefix; - unsigned int nprefix; - unsigned int maxprefix; +struct prefix_list { + struct prefix_entry **prefix; + unsigned int nprefix; + unsigned int maxprefix; }; -struct prefix4_entry{ - struct in_addr ip; - unsigned char len; +struct prefix4_entry { + struct in_addr ip; + unsigned char len; }; -struct host_entry{ - struct in6_addr ip6; - struct ether_addr ether; - unsigned char flag; - struct host_entry *next; +struct host_entry { + struct in6_addr ip6; + struct ether_addr ether; + unsigned char flag; + struct host_entry *next; }; -struct host_list{ - struct host_entry **host; - unsigned int nhosts; - unsigned int maxhosts; +struct host_list { + struct host_entry **host; + unsigned int nhosts; + unsigned int maxhosts; }; -struct address_list{ - struct in6_addr *addr; - unsigned int naddr; - unsigned int maxaddr; +struct address_list { + struct in6_addr *addr; + unsigned int naddr; + unsigned int maxaddr; }; - -#define MAX_IFACES 25 -struct iface_entry{ - int ifindex; - char iface[IFACE_LENGTH]; - struct ether_addr ether; - unsigned char ether_f; - struct prefix_list ip6_global; - struct prefix_list ip6_local; - int flags; +#define MAX_IFACES 25 +struct iface_entry { + int ifindex; + char iface[IFACE_LENGTH]; + struct ether_addr ether; + unsigned char ether_f; + struct prefix_list ip6_global; + struct prefix_list ip6_local; + int flags; }; -struct iface_list{ - struct iface_entry *ifaces; - unsigned int nifaces; - unsigned int maxifaces; +struct iface_list { + struct iface_entry *ifaces; + unsigned int nifaces; + unsigned int maxifaces; }; - /* Constants employed by decode_ipv6_address() */ -#define IPV6_UNSPEC 1 -#define IPV6_MULTICAST 2 -#define IPV6_UNICAST 4 - -#define UCAST_V4MAPPED 1 -#define UCAST_V4COMPAT 2 -#define UCAST_LINKLOCAL 4 -#define UCAST_SITELOCAL 8 -#define UCAST_UNIQUELOCAL 16 -#define UCAST_6TO4 32 -#define UCAST_TEREDO 64 -#define UCAST_GLOBAL 128 -#define UCAST_LOOPBACK 256 - -#define MCAST_PERMANENT 512 -#define MCAST_NONPERMANENT 1024 -#define MCAST_INVALID 2048 -#define MCAST_UNICASTBASED 4096 -#define MCAST_EMBEDRP 8192 -#define MCAST_UNKNOWN 16384 - -#define SCOPE_RESERVED 1 -#define SCOPE_INTERFACE 2 -#define SCOPE_LINK 4 -#define SCOPE_ADMIN 8 -#define SCOPE_SITE 16 -#define SCOPE_ORGANIZATION 32 -#define SCOPE_GLOBAL 64 -#define SCOPE_UNASSIGNED 128 -#define SCOPE_UNSPECIFIED 256 - -#define IID_MACDERIVED 1 -#define IID_ISATAP 2 -#define IID_EMBEDDEDIPV4 4 -#define IID_EMBEDDEDIPV4_32 8192 -#define IID_EMBEDDEDIPV4_64 64 -#define IID_EMBEDDEDPORT 8 -#define IID_EMBEDDEDPORTREV 16 -#define IID_LOWBYTE 32 -#define IID_PATTERN_BYTES 128 -#define IID_RANDOM 256 -#define IID_TEREDO_RFC4380 512 -#define IID_TEREDO_RFC5991 1024 -#define IID_TEREDO_UNKNOWN 2048 -#define IID_TEREDO 4096 -#define IID_UNSPECIFIED 8192 - - - +#define IPV6_UNSPEC 1 +#define IPV6_MULTICAST 2 +#define IPV6_UNICAST 4 + +#define UCAST_V4MAPPED 1 +#define UCAST_V4COMPAT 2 +#define UCAST_LINKLOCAL 4 +#define UCAST_SITELOCAL 8 +#define UCAST_UNIQUELOCAL 16 +#define UCAST_6TO4 32 +#define UCAST_TEREDO 64 +#define UCAST_GLOBAL 128 +#define UCAST_LOOPBACK 256 + +#define MCAST_PERMANENT 512 +#define MCAST_NONPERMANENT 1024 +#define MCAST_INVALID 2048 +#define MCAST_UNICASTBASED 4096 +#define MCAST_EMBEDRP 8192 +#define MCAST_UNKNOWN 16384 + +#define SCOPE_RESERVED 1 +#define SCOPE_INTERFACE 2 +#define SCOPE_LINK 4 +#define SCOPE_ADMIN 8 +#define SCOPE_SITE 16 +#define SCOPE_ORGANIZATION 32 +#define SCOPE_GLOBAL 64 +#define SCOPE_UNASSIGNED 128 +#define SCOPE_UNSPECIFIED 256 + +#define IID_MACDERIVED 1 +#define IID_ISATAP 2 +#define IID_EMBEDDEDIPV4 4 +#define IID_EMBEDDEDIPV4_32 8192 +#define IID_EMBEDDEDIPV4_64 64 +#define IID_EMBEDDEDPORT 8 +#define IID_EMBEDDEDPORTREV 16 +#define IID_LOWBYTE 32 +#define IID_PATTERN_BYTES 128 +#define IID_RANDOM 256 +#define IID_TEREDO_RFC4380 512 +#define IID_TEREDO_RFC5991 1024 +#define IID_TEREDO_UNKNOWN 2048 +#define IID_TEREDO 4096 +#define IID_UNSPECIFIED 8192 /* This struture is employed by decode_ipv6_address */ -struct decode6{ - struct in6_addr ip6; - unsigned int type; - unsigned int subtype; - unsigned int scope; - unsigned int iidtype; - unsigned int iidsubtype; +struct decode6 { + struct in6_addr ip6; + unsigned int type; + unsigned int subtype; + unsigned int scope; + unsigned int iidtype; + unsigned int iidsubtype; }; - #ifndef IN6_IS_ADDR_UNIQUELOCAL - #define IN6_IS_ADDR_UNIQUELOCAL(a) \ - ((((uint32_t *) (a))[0] & htonl (0xfe000000)) \ - == htonl (0xfc000000)) +#define IN6_IS_ADDR_UNIQUELOCAL(a) ((((uint32_t *)(a))[0] & htonl(0xfe000000)) == htonl(0xfc000000)) #endif #ifndef IN6_IS_ADDR_6TO4 - #define IN6_IS_ADDR_6TO4(a) \ - ((((uint32_t *) (a))[0] & htonl (0xffff0000)) \ - == htonl (0x20020000)) +#define IN6_IS_ADDR_6TO4(a) ((((uint32_t *)(a))[0] & htonl(0xffff0000)) == htonl(0x20020000)) #endif #ifndef IN6_IS_ADDR_TEREDO - #define IN6_IS_ADDR_TEREDO(a) \ - (((uint32_t *) (a))[0] == htonl (0x20010000)) +#define IN6_IS_ADDR_TEREDO(a) (((uint32_t *)(a))[0] == htonl(0x20010000)) #endif #ifndef IN6_IS_ADDR_TEREDO_LEGACY - #define IN6_IS_ADDR_TEREDO_LEGACY(a) \ - (((uint32_t *) (a))[0] == htonl (0x3ffe831f)) +#define IN6_IS_ADDR_TEREDO_LEGACY(a) (((uint32_t *)(a))[0] == htonl(0x3ffe831f)) #endif +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) +#ifndef s6_addr16 +#define s6_addr16 __u6_addr.__u6_addr16 +#endif +#ifndef s6_addr +#define s6_addr __u6_addr.__u6_addr8 +#endif +#ifndef s6_addr8 +#define s6_addr8 __u6_addr.__u6_addr8 +#endif -#if defined (__FreeBSD__) || defined(__NetBSD__) || defined (__OpenBSD__) || defined(__APPLE__) - #ifndef s6_addr16 - #define s6_addr16 __u6_addr.__u6_addr16 - #endif - - #ifndef s6_addr - #define s6_addr __u6_addr.__u6_addr8 - #endif - - #ifndef s6_addr8 - #define s6_addr8 __u6_addr.__u6_addr8 - #endif - - #ifndef s6_addr32 - #define s6_addr32 __u6_addr.__u6_addr32 - #endif -#elif defined __linux__ || ( !defined(__FreeBSD__) && defined(__FreeBSD_kernel__)) - #ifndef s6_addr16 - #define s6_addr16 __in6_u.__u6_addr16 - #endif +#ifndef s6_addr32 +#define s6_addr32 __u6_addr.__u6_addr32 +#endif +#elif defined __linux__ || (!defined(__FreeBSD__) && defined(__FreeBSD_kernel__)) +#ifndef s6_addr16 +#define s6_addr16 __in6_u.__u6_addr16 +#endif - #ifndef s6_addr32 - #define s6_addr32 __in6_u.__u6_addr32 - #endif +#ifndef s6_addr32 +#define s6_addr32 __in6_u.__u6_addr32 +#endif #elif defined(__sun) || defined(sun) - #ifndef s6_addr8 - #define s6_addr8 _S6_un._S6_u8 - #endif - - #ifndef s6_addr32 - #define s6_addr32 _S6_un._S6_u32 - #endif +#ifndef s6_addr8 +#define s6_addr8 _S6_un._S6_u8 #endif +#ifndef s6_addr32 +#define s6_addr32 _S6_un._S6_u32 +#endif +#endif /* This causes Linux to use the BSD definition of the TCP and UDP header fields */ #ifndef __FAVOR_BSD - #define __FAVOR_BSD +#define __FAVOR_BSD #endif - /* Names (DNS, NI) related constants and definitions */ -#define MAX_DOMAIN_LEN 512 -#define MAX_DNS_LABELS 50 -#define MAX_DNS_CLABELS 5 - +#define MAX_DOMAIN_LEN 512 +#define MAX_DNS_LABELS 50 +#define MAX_DNS_CLABELS 5 /* RFC 4191 Router Advertisement Preference */ -#define RTR_PREF_HIGH 0x01 -#define RTR_PREF_LOW 0x03 -#define RTR_PREF_MED 0x00 -#define RTR_PREF_RSVD 0x02 +#define RTR_PREF_HIGH 0x01 +#define RTR_PREF_LOW 0x03 +#define RTR_PREF_MED 0x00 +#define RTR_PREF_RSVD 0x02 /* ICMPv6 Types/Codes not defined in some OSes */ #ifndef ICMP6_DST_UNREACH_FAILEDPOLICY - #define ICMP6_DST_UNREACH_FAILEDPOLICY 5 +#define ICMP6_DST_UNREACH_FAILEDPOLICY 5 #endif #ifndef ICMP6_DST_UNREACH_REJECTROUTE - #define ICMP6_DST_UNREACH_REJECTROUTE 6 +#define ICMP6_DST_UNREACH_REJECTROUTE 6 #endif - -#if !(defined (__FreeBSD__) || defined(__NetBSD__) || defined (__OpenBSD__) || defined(__APPLE__)) +#if !(defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)) /* Definitions for Linux */ - #ifndef _NETINET_ICMP6_H - #include - #endif - - #define ICMP6_NI_QUERY 139 /* node information request */ - #define ICMP6_NI_REPLY 140 /* node information reply */ - /* - * icmp6 namelookup - */ - - struct icmp6_namelookup { - struct icmp6_hdr icmp6_nl_hdr; - uint8_t icmp6_nl_nonce[8]; - int32_t icmp6_nl_ttl; - #if 0 +#ifndef _NETINET_ICMP6_H +#include +#endif + +#define ICMP6_NI_QUERY 139 /* node information request */ +#define ICMP6_NI_REPLY 140 /* node information reply */ +/* + * icmp6 namelookup + */ + +struct icmp6_namelookup { + struct icmp6_hdr icmp6_nl_hdr; + uint8_t icmp6_nl_nonce[8]; + int32_t icmp6_nl_ttl; +#if 0 uint8_t icmp6_nl_len; uint8_t icmp6_nl_name[3]; - #endif - /* could be followed by options */ - } __attribute__ ((__packed__)); - - /* - * icmp6 node information - */ - struct icmp6_nodeinfo { - struct icmp6_hdr icmp6_ni_hdr; - uint8_t icmp6_ni_nonce[8]; - /* could be followed by reply data */ - } __attribute__ ((__packed__)); - - #define ni_type icmp6_ni_hdr.icmp6_type - #define ni_code icmp6_ni_hdr.icmp6_code - #define ni_cksum icmp6_ni_hdr.icmp6_cksum - #define ni_qtype icmp6_ni_hdr.icmp6_data16[0] - #define ni_flags icmp6_ni_hdr.icmp6_data16[1] - - #define NI_QTYPE_NOOP 0 /* NOOP */ - #define NI_QTYPE_SUPTYPES 1 /* Supported Qtypes */ - #define NI_QTYPE_FQDN 2 /* FQDN (draft 04) */ - #define NI_QTYPE_DNSNAME 2 /* DNS Name */ - #define NI_QTYPE_NODEADDR 3 /* Node Addresses */ - #define NI_QTYPE_IPV4ADDR 4 /* IPv4 Addresses */ - - #if __BYTE_ORDER == __BIG_ENDIAN - #define NI_SUPTYPE_FLAG_COMPRESS 0x1 - #define NI_FQDN_FLAG_VALIDTTL 0x1 - #elif __BYTE_ORDER == __LITTLE_ENDIAN - #define NI_SUPTYPE_FLAG_COMPRESS 0x0100 - #define NI_FQDN_FLAG_VALIDTTL 0x0100 - #endif - - #if __BYTE_ORDER == __BIG_ENDIAN - #define NI_NODEADDR_FLAG_TRUNCATE 0x1 - #define NI_NODEADDR_FLAG_ALL 0x2 - #define NI_NODEADDR_FLAG_COMPAT 0x4 - #define NI_NODEADDR_FLAG_LINKLOCAL 0x8 - #define NI_NODEADDR_FLAG_SITELOCAL 0x10 - #define NI_NODEADDR_FLAG_GLOBAL 0x20 - #define NI_NODEADDR_FLAG_ANYCAST 0x40 /* just experimental. not in spec */ - #elif __BYTE_ORDER == __LITTLE_ENDIAN - #define NI_NODEADDR_FLAG_TRUNCATE 0x0100 - #define NI_NODEADDR_FLAG_ALL 0x0200 - #define NI_NODEADDR_FLAG_COMPAT 0x0400 - #define NI_NODEADDR_FLAG_LINKLOCAL 0x0800 - #define NI_NODEADDR_FLAG_SITELOCAL 0x1000 - #define NI_NODEADDR_FLAG_GLOBAL 0x2000 - #define NI_NODEADDR_FLAG_ANYCAST 0x4000 /* just experimental. not in spec */ - #endif - - struct ni_reply_fqdn { - uint32_t ni_fqdn_ttl; /* TTL */ - uint8_t ni_fqdn_namelen; /* length in octets of the FQDN */ - uint8_t ni_fqdn_name[3]; /* XXX: alignment */ - } __attribute__ ((__packed__)); +#endif + /* could be followed by options */ +} __attribute__((__packed__)); +/* + * icmp6 node information + */ +struct icmp6_nodeinfo { + struct icmp6_hdr icmp6_ni_hdr; + uint8_t icmp6_ni_nonce[8]; + /* could be followed by reply data */ +} __attribute__((__packed__)); + +#define ni_type icmp6_ni_hdr.icmp6_type +#define ni_code icmp6_ni_hdr.icmp6_code +#define ni_cksum icmp6_ni_hdr.icmp6_cksum +#define ni_qtype icmp6_ni_hdr.icmp6_data16[0] +#define ni_flags icmp6_ni_hdr.icmp6_data16[1] + +#define NI_QTYPE_NOOP 0 /* NOOP */ +#define NI_QTYPE_SUPTYPES 1 /* Supported Qtypes */ +#define NI_QTYPE_FQDN 2 /* FQDN (draft 04) */ +#define NI_QTYPE_DNSNAME 2 /* DNS Name */ +#define NI_QTYPE_NODEADDR 3 /* Node Addresses */ +#define NI_QTYPE_IPV4ADDR 4 /* IPv4 Addresses */ + +#if __BYTE_ORDER == __BIG_ENDIAN +#define NI_SUPTYPE_FLAG_COMPRESS 0x1 +#define NI_FQDN_FLAG_VALIDTTL 0x1 +#elif __BYTE_ORDER == __LITTLE_ENDIAN +#define NI_SUPTYPE_FLAG_COMPRESS 0x0100 +#define NI_FQDN_FLAG_VALIDTTL 0x0100 #endif +#if __BYTE_ORDER == __BIG_ENDIAN +#define NI_NODEADDR_FLAG_TRUNCATE 0x1 +#define NI_NODEADDR_FLAG_ALL 0x2 +#define NI_NODEADDR_FLAG_COMPAT 0x4 +#define NI_NODEADDR_FLAG_LINKLOCAL 0x8 +#define NI_NODEADDR_FLAG_SITELOCAL 0x10 +#define NI_NODEADDR_FLAG_GLOBAL 0x20 +#define NI_NODEADDR_FLAG_ANYCAST 0x40 /* just experimental. not in spec */ +#elif __BYTE_ORDER == __LITTLE_ENDIAN +#define NI_NODEADDR_FLAG_TRUNCATE 0x0100 +#define NI_NODEADDR_FLAG_ALL 0x0200 +#define NI_NODEADDR_FLAG_COMPAT 0x0400 +#define NI_NODEADDR_FLAG_LINKLOCAL 0x0800 +#define NI_NODEADDR_FLAG_SITELOCAL 0x1000 +#define NI_NODEADDR_FLAG_GLOBAL 0x2000 +#define NI_NODEADDR_FLAG_ANYCAST 0x4000 /* just experimental. not in spec */ +#endif -struct ni_reply_ip6 { - uint32_t ni_ip6_ttl; /* TTL */ - struct in6_addr ip6; /* IPv6 address */ -} __attribute__ ((__packed__)); +struct ni_reply_fqdn { + uint32_t ni_fqdn_ttl; /* TTL */ + uint8_t ni_fqdn_namelen; /* length in octets of the FQDN */ + uint8_t ni_fqdn_name[3]; /* XXX: alignment */ +} __attribute__((__packed__)); + +#endif +struct ni_reply_ip6 { + uint32_t ni_ip6_ttl; /* TTL */ + struct in6_addr ip6; /* IPv6 address */ +} __attribute__((__packed__)); struct ni_reply_ip { - uint32_t ni_ip_ttl; /* TTL */ - struct in_addr ip; /* IPv6 address */ -} __attribute__ ((__packed__)); + uint32_t ni_ip_ttl; /* TTL */ + struct in_addr ip; /* IPv6 address */ +} __attribute__((__packed__)); struct ni_reply_name { - uint32_t ni_name_ttl; /* TTL */ - unsigned char ni_name_name; /* IPv6 address */ -} __attribute__ ((__packed__)); - + uint32_t ni_name_ttl; /* TTL */ + unsigned char ni_name_name; /* IPv6 address */ +} __attribute__((__packed__)); /* ICMPv6 Types/Codes not defined in some OSes */ #ifndef ICMP6_DST_UNREACH_FAILEDPOLICY - #define ICMP6_DST_UNREACH_FAILEDPOLICY 5 +#define ICMP6_DST_UNREACH_FAILEDPOLICY 5 #endif #ifndef ICMP6_DST_UNREACH_REJECTROUTE - #define ICMP6_DST_UNREACH_REJECTROUTE 6 +#define ICMP6_DST_UNREACH_REJECTROUTE 6 #endif - -struct packet{ - unsigned char *link; - unsigned char *ipv6; - unsigned char *upper; - unsigned long maxsize; +struct packet { + unsigned char *link; + unsigned char *ipv6; + unsigned char *upper; + unsigned long maxsize; }; -struct iface_data{ - char iface[IFACE_LENGTH]; - unsigned char iface_f; - pcap_t *pfd; - int ifindex; - unsigned char ifindex_f; - struct iface_list iflist; - unsigned int type; - unsigned int flags; - int fd; - unsigned int pending_write_f; - void *pending_write_data; - unsigned int pending_write_size; - fd_set *rset; - fd_set *wset; - fd_set *eset; - unsigned int write_errors; - struct ether_addr ether; - unsigned int ether_flag; - unsigned int linkhsize; - unsigned int max_packet_size; - struct in6_addr ip6_local; - unsigned int ip6_local_flag; - struct prefix_list ip6_global; - unsigned int ip6_global_flag; - struct in6_addr router_ip6; - struct ether_addr router_ether; - struct prefix_list prefix_ac; - struct prefix_list prefix_ol; - unsigned int local_retrans; - unsigned int local_timeout; - unsigned int mtu; - struct ether_addr hsrcaddr; - unsigned int hsrcaddr_f; - struct ether_addr hdstaddr; - unsigned int hdstaddr_f; - struct in6_addr srcaddr; - unsigned int src_f; /* XXX Set when a source address has been selected (even if automatically) */ - unsigned int srcaddr_f; - unsigned char srcpreflen; - unsigned char srcprefix_f; - struct in6_addr dstaddr; - unsigned int dstaddr_f; - unsigned int verbose_f; - unsigned char listen_f; - unsigned char fragh_f; - - /* XXX - The next four variables are kind of a duplicate of router_ip6 and router_ether above. - May remove them at some point - */ - - struct in6_addr nhaddr; - unsigned char nhaddr_f; - struct ether_addr nhhaddr; - unsigned char nhhaddr_f; - int nhifindex; - unsigned char nhifindex_f; - char nhiface[IFACE_LENGTH]; - unsigned char nh_f; -}; +struct iface_data { + char iface[IFACE_LENGTH]; + unsigned char iface_f; + pcap_t *pfd; + int ifindex; + unsigned char ifindex_f; + struct iface_list iflist; + unsigned int type; + unsigned int flags; + int fd; + unsigned int pending_write_f; + void *pending_write_data; + unsigned int pending_write_size; + fd_set *rset; + fd_set *wset; + fd_set *eset; + unsigned int write_errors; + struct ether_addr ether; + unsigned int ether_flag; + unsigned int linkhsize; + unsigned int max_packet_size; + struct in6_addr ip6_local; + unsigned int ip6_local_flag; + struct prefix_list ip6_global; + unsigned int ip6_global_flag; + struct in6_addr router_ip6; + struct ether_addr router_ether; + struct prefix_list prefix_ac; + struct prefix_list prefix_ol; + unsigned int local_retrans; + unsigned int local_timeout; + unsigned int mtu; + struct ether_addr hsrcaddr; + unsigned int hsrcaddr_f; + struct ether_addr hdstaddr; + unsigned int hdstaddr_f; + struct in6_addr srcaddr; + unsigned int src_f; /* XXX Set when a source address has been selected (even if automatically) */ + unsigned int srcaddr_f; + unsigned char srcpreflen; + unsigned char srcprefix_f; + struct in6_addr dstaddr; + unsigned int dstaddr_f; + unsigned int verbose_f; + unsigned char listen_f; + unsigned char fragh_f; + + /* XXX + The next four variables are kind of a duplicate of router_ip6 and router_ether above. + May remove them at some point + */ + struct in6_addr nhaddr; + unsigned char nhaddr_f; + struct ether_addr nhhaddr; + unsigned char nhhaddr_f; + int nhifindex; + unsigned char nhifindex_f; + char nhiface[IFACE_LENGTH]; + unsigned char nh_f; +}; #ifdef __linux__ /* Consulting the routing table */ @@ -903,124 +864,120 @@ struct iface_data{ #define SLL_ADDRLEN 0 -struct sll_linux{ - uint16_t sll_pkttype; /* packet type */ - uint16_t sll_hatype; /* link-layer address type */ - uint16_t sll_halen; /* link-layer address length */ - uint8_t sll_addr[SLL_ADDRLEN]; /* link-layer address */ - uint16_t sll_protocol; /* protocol */ -} __attribute__ ((__packed__)); +struct sll_linux { + uint16_t sll_pkttype; /* packet type */ + uint16_t sll_hatype; /* link-layer address type */ + uint16_t sll_halen; /* link-layer address length */ + uint8_t sll_addr[SLL_ADDRLEN]; /* link-layer address */ + uint16_t sll_protocol; /* protocol */ +} __attribute__((__packed__)); #endif - -struct next_hop{ - struct in6_addr srcaddr; - unsigned char srcaddr_f; - struct in6_addr dstaddr; - unsigned char dstaddr_f; - struct in6_addr nhaddr; - unsigned char nhaddr_f; - struct ether_addr nhhaddr; - unsigned char nhhaddr_f; - int ifindex; - unsigned char ifindex_f; +struct next_hop { + struct in6_addr srcaddr; + unsigned char srcaddr_f; + struct in6_addr dstaddr; + unsigned char dstaddr_f; + struct in6_addr nhaddr; + unsigned char nhaddr_f; + struct ether_addr nhhaddr; + unsigned char nhhaddr_f; + int ifindex; + unsigned char ifindex_f; }; - /* Flags that specify what the load_dst_and_pcap() function should do */ -#define LOAD_PCAP_ONLY 0x01 -#define LOAD_SRC_NXT_HOP 0x02 +#define LOAD_PCAP_ONLY 0x01 +#define LOAD_SRC_NXT_HOP 0x02 /* Constants to signal special interface types */ -#define IFACE_LOOPBACK 1 -#define IFACE_TUNNEL 2 +#define IFACE_LOOPBACK 1 +#define IFACE_TUNNEL 2 #ifndef SA_SIZE #if defined(__APPLE__) -#define SA_SIZE(sa) \ - ( (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ? \ - sizeof(long) : \ - ((struct sockaddr *)(sa))->sa_len ) -#elif defined (__FreeBSD__) || defined(__NetBSD__) || defined (__OpenBSD__) -#define SA_SIZE(sa) \ - ( (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ? \ - sizeof(long) : \ - 1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) ) +#define SA_SIZE(sa) \ + ((!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ? sizeof(long) : ((struct sockaddr *)(sa))->sa_len) +#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) +#define SA_SIZE(sa) \ + ((!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) \ + ? sizeof(long) \ + : 1 + ((((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1))) #else - #define SA_SIZE(sa) sizeof(struct sockaddr) +#define SA_SIZE(sa) sizeof(struct sockaddr) #endif #endif -int address_contains_colons(char *); -int address_contains_ranges(char *); -void change_endianness(uint32_t *, unsigned int); -void debug_print_ifaces_data(struct iface_list *); -uint16_t dec_to_hex(uint16_t); -void decode_ipv6_address(struct decode6 *); -int dns_decode(unsigned char *, unsigned int, unsigned char *, char *, unsigned int, unsigned char **); -int dns_str2wire(char *, unsigned int, char *, unsigned int); -void dump_hex(void *, size_t); -struct ether_addr ether_multicast(const struct in6_addr *); -int ether_ntop(const struct ether_addr *, char *, size_t); -int ether_pton(const char *, struct ether_addr *, unsigned int); -void ether_to_ipv6_linklocal(struct ether_addr *etheraddr, struct in6_addr *ipv6addr); -void *find_iface_by_index(struct iface_list *, int); -void *find_iface_by_name(struct iface_list *, char *); -void *find_iface_by_addr(struct iface_list *, struct in6_addr *); -int find_ipv6_router(pcap_t *, struct ether_addr *, struct in6_addr *, struct ether_addr *, struct in6_addr *); -int find_ipv6_router_full(pcap_t *, struct iface_data *); -struct iface_entry *find_matching_address(struct iface_data *, struct iface_list *, struct in6_addr *, struct in6_addr *); -void generate_slaac_address(struct in6_addr *, struct ether_addr *, struct in6_addr *); -int get_if_addrs(struct iface_data *); -int get_local_addrs(struct iface_data *); +int address_contains_colons(char *); +int address_contains_ranges(char *); +void change_endianness(uint32_t *, unsigned int); +void debug_print_ifaces_data(struct iface_list *); +uint16_t dec_to_hex(uint16_t); +void decode_ipv6_address(struct decode6 *); +int dns_decode(unsigned char *, unsigned int, unsigned char *, char *, unsigned int, unsigned char **); +int dns_str2wire(char *, unsigned int, char *, unsigned int); +void dump_hex(void *, size_t); +struct ether_addr ether_multicast(const struct in6_addr *); +int ether_ntop(const struct ether_addr *, char *, size_t); +int ether_pton(const char *, struct ether_addr *, unsigned int); +void ether_to_ipv6_linklocal(struct ether_addr *etheraddr, struct in6_addr *ipv6addr); +void *find_iface_by_index(struct iface_list *, int); +void *find_iface_by_name(struct iface_list *, char *); +void *find_iface_by_addr(struct iface_list *, struct in6_addr *); +int find_ipv6_router(pcap_t *, struct ether_addr *, struct in6_addr *, struct ether_addr *, struct in6_addr *); +int find_ipv6_router_full(pcap_t *, struct iface_data *); +struct iface_entry *find_matching_address(struct iface_data *, struct iface_list *, struct in6_addr *, + struct in6_addr *); +void generate_slaac_address(struct in6_addr *, struct ether_addr *, struct in6_addr *); +int get_if_addrs(struct iface_data *); +int get_local_addrs(struct iface_data *); /* XXX Looks like this had been removed */ /* int get_ipv6_address(struct in6_addr *, char *); */ -int get_ipv6_target(struct target_ipv6 *); -int inc_sdev(uint32_t *, unsigned int, uint32_t *, double *); -const char * inet_ntof(int, const void *, char *, socklen_t); -int init_iface_data(struct iface_data *); -int init_filters(struct filters *); -uint16_t in_chksum(void *, void *, size_t, uint8_t); -int insert_pad_opt(unsigned char *ptrhdr, const unsigned char *, unsigned int); -int ipv6_to_ether(pcap_t *, struct iface_data *, struct in6_addr *, struct ether_addr *); -unsigned int ip6_longest_match(struct in6_addr *, struct in6_addr *); -int is_iid_null(struct in6_addr *, uint8_t); -int is_ip6_in_address_list(struct prefix_list *, struct in6_addr *); -int is_ip6_in_iface_entry(struct iface_list *, int, struct in6_addr *); -int is_ip6_in_list(struct in6_addr *, struct host_list *); -int is_ip6_in_prefix_list(struct in6_addr *, struct prefix_list *); -int is_eq_in6_addr(struct in6_addr *, struct in6_addr *); -unsigned int is_service_port(uint16_t); -int is_time_elapsed(struct timeval *, struct timeval *, unsigned long); -int keyval(char *, unsigned int, char **, char **); -int load_dst_and_pcap(struct iface_data *, unsigned int); -unsigned int match_ether(struct ether_addr *, unsigned int, struct ether_addr *); -unsigned int match_ipv6(struct in6_addr *, uint8_t *, unsigned int, struct in6_addr *); -void print_filters(struct iface_data *, struct filters *); -void print_filter_result(struct iface_data *, const u_char *, unsigned char); -unsigned int print_ipv6_address(char *s, struct in6_addr *); -unsigned int print_ipv6_address_rev(struct in6_addr *); -int print_local_addrs(struct iface_data *); -void randomize_ether_addr(struct ether_addr *); -void randomize_ipv6_addr(struct in6_addr *, const struct in6_addr *, uint8_t); -void randomize_port(uint16_t *, uint16_t , uint8_t); -int read_ipv6_address(char *, unsigned int, struct in6_addr *); -int read_prefix(char *, unsigned int, char **); -void release_privileges(void); -void sanitize_ipv4_prefix(struct prefix4_entry *); -void sanitize_ipv6_prefix(struct in6_addr *, uint8_t); -void sanitize_port(uint16_t *, uint8_t); -int send_neighbor_advert(struct iface_data *, pcap_t *, const u_char *); -int send_neighbor_solicit(struct iface_data *, struct in6_addr *); -int sel_src_addr(struct iface_data *); -struct in6_addr * sel_src_addr_ra(struct iface_data *, struct in6_addr *); -int sel_next_hop(struct iface_data *); -int sel_next_hop_ra(struct iface_data *); -void sig_alarm(int); -struct in6_addr solicited_node(const struct in6_addr *); -int string_escapes(char *, unsigned int *, unsigned int); -size_t Strnlen(const char *, size_t); -struct timeval timeval_sub(struct timeval *, struct timeval *); -float time_diff_ms(struct timeval *, struct timeval *); -unsigned int zero_byte_iid(struct in6_addr *); - +int get_ipv6_target(struct target_ipv6 *); +int inc_sdev(uint32_t *, unsigned int, uint32_t *, double *); +const char *inet_ntof(int, const void *, char *, socklen_t); +int init_iface_data(struct iface_data *); +int init_filters(struct filters *); +uint16_t in_chksum(void *, void *, size_t, uint8_t); +int insert_pad_opt(unsigned char *ptrhdr, const unsigned char *, unsigned int); +int ipv6_to_ether(pcap_t *, struct iface_data *, struct in6_addr *, struct ether_addr *); +unsigned int ip6_longest_match(struct in6_addr *, struct in6_addr *); +int is_iid_null(struct in6_addr *, uint8_t); +int is_ip6_in_address_list(struct prefix_list *, struct in6_addr *); +int is_ip6_in_iface_entry(struct iface_list *, int, struct in6_addr *); +int is_ip6_in_list(struct in6_addr *, struct host_list *); +int is_ip6_in_prefix_list(struct in6_addr *, struct prefix_list *); +int is_eq_in6_addr(struct in6_addr *, struct in6_addr *); +unsigned int is_service_port(uint16_t); +int is_time_elapsed(struct timeval *, struct timeval *, unsigned long); +int keyval(char *, unsigned int, char **, char **); +int load_dst_and_pcap(struct iface_data *, unsigned int); +unsigned int match_ether(struct ether_addr *, unsigned int, struct ether_addr *); +unsigned int match_ipv6(struct in6_addr *, uint8_t *, unsigned int, struct in6_addr *); +void print_filters(struct iface_data *, struct filters *); +void print_filter_result(struct iface_data *, const u_char *, unsigned char); +unsigned int print_ipv6_address(char *s, struct in6_addr *); +unsigned int print_ipv6_address_rev(struct in6_addr *); +int print_local_addrs(struct iface_data *); +void randomize_ether_addr(struct ether_addr *); +void randomize_ipv6_addr(struct in6_addr *, const struct in6_addr *, uint8_t); +void randomize_port(uint16_t *, uint16_t, uint8_t); +int read_ipv6_address(char *, unsigned int, struct in6_addr *); +int read_prefix(char *, unsigned int, char **); +void release_privileges(void); +void sanitize_ipv4_prefix(struct prefix4_entry *); +void sanitize_ipv6_prefix(struct in6_addr *, uint8_t); +void sanitize_port(uint16_t *, uint8_t); +int send_neighbor_advert(struct iface_data *, pcap_t *, const u_char *); +int send_neighbor_solicit(struct iface_data *, struct in6_addr *); +int sel_src_addr(struct iface_data *); +struct in6_addr *sel_src_addr_ra(struct iface_data *, struct in6_addr *); +int sel_next_hop(struct iface_data *); +int sel_next_hop_ra(struct iface_data *); +void sig_alarm(int); +struct in6_addr solicited_node(const struct in6_addr *); +int string_escapes(char *, unsigned int *, unsigned int); +size_t Strnlen(const char *, size_t); +struct timeval timeval_sub(struct timeval *, struct timeval *); +float time_diff_ms(struct timeval *, struct timeval *); +unsigned int zero_byte_iid(struct in6_addr *); diff --git a/tools/mldq6.c b/tools/mldq6.c index 5378596..0914956 100644 --- a/tools/mldq6.c +++ b/tools/mldq6.c @@ -17,7 +17,7 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . - * + * * Build with: make mldq6 * * The libpcap library must be previously installed on your system. @@ -25,570 +25,564 @@ * Please send any bug reports to Fernando Gont */ -#include #include #include +#include +#include +#include #include #include -#include +#include #include #include -#include -#include -#include #include -#include #include +#include +#include -#include "mldq6.h" -#include "libipv6.h" #include "ipv6toolkit.h" +#include "libipv6.h" +#include "mldq6.h" + +void init_packet_data(struct iface_data *); +void send_packet(struct iface_data *); +void print_attack_info(struct iface_data *); +void usage(void); +void print_help(void); + +struct pcap_pkthdr *pkthdr; +const u_char *pktdata; +struct in6_addr *pkt_ipv6addr; +bpf_u_int32 my_netmask; +bpf_u_int32 my_ip; +struct bpf_program pcap_filter; +char dev[64], errbuf[PCAP_ERRBUF_SIZE]; +char all_nodes_addr[] = ALL_NODES_MULTICAST_ADDR; + +unsigned char buffer[65556]; +unsigned char *v6buffer, *ptr, *startofprefixes; + +struct ip6_hdr *ipv6, *pkt_ipv6; +struct mld_hdr *mldq; +struct ether_header *ethernet, *pkt_ether; +struct nd_opt_slla *sllaopt; +char *lasts, *endptr; + +int nw; +unsigned long ul_res, ul_val; + +unsigned int i, j, sources, nsources, startrand; + +uint16_t mask; +uint8_t hoplimit = 1; +struct in6_addr mldaddr; +uint32_t mldrespdelay = 10000; + +struct ether_addr linkaddr[MAX_SLLA_OPTION]; +unsigned int nlinkaddr = 0, linkaddrs; +unsigned int nsleep; -void init_packet_data(struct iface_data *); -void send_packet(struct iface_data *); -void print_attack_info(struct iface_data *); -void usage(void); -void print_help(void); - - -struct pcap_pkthdr *pkthdr; -const u_char *pktdata; -struct in6_addr *pkt_ipv6addr; -bpf_u_int32 my_netmask; -bpf_u_int32 my_ip; -struct bpf_program pcap_filter; -char dev[64], errbuf[PCAP_ERRBUF_SIZE]; -char all_nodes_addr[]= ALL_NODES_MULTICAST_ADDR; - -unsigned char buffer[65556]; -unsigned char *v6buffer, *ptr, *startofprefixes; - -struct ip6_hdr *ipv6, *pkt_ipv6; -struct mld_hdr *mldq; -struct ether_header *ethernet, *pkt_ether; -struct nd_opt_slla *sllaopt; -char *lasts, *endptr; - -int nw; -unsigned long ul_res, ul_val; - -unsigned int i, j, sources, nsources, startrand; - -uint16_t mask; -uint8_t hoplimit = 1; -struct in6_addr mldaddr; -uint32_t mldrespdelay = 10000; - - -struct ether_addr linkaddr[MAX_SLLA_OPTION]; -unsigned int nlinkaddr=0, linkaddrs; -unsigned int nsleep; - -char *charptr; - -char plinkaddr[ETHER_ADDR_PLEN], phsrcaddr[ETHER_ADDR_PLEN], phdstaddr[ETHER_ADDR_PLEN]; -char psrcaddr[INET6_ADDRSTRLEN], pdstaddr[INET6_ADDRSTRLEN], pprefix[INET6_ADDRSTRLEN]; -unsigned char sllopt_f=0, sllopta_f=0, loop_f = 0, sleep_f=0, floods_f=0, hoplimit_f=0; -unsigned char mldaddr_f=0, mldrespdelay_f=0; - -unsigned char newdata_f=0; +char *charptr; + +char plinkaddr[ETHER_ADDR_PLEN], phsrcaddr[ETHER_ADDR_PLEN], phdstaddr[ETHER_ADDR_PLEN]; +char psrcaddr[INET6_ADDRSTRLEN], pdstaddr[INET6_ADDRSTRLEN], pprefix[INET6_ADDRSTRLEN]; +unsigned char sllopt_f = 0, sllopta_f = 0, loop_f = 0, sleep_f = 0, floods_f = 0, hoplimit_f = 0; +unsigned char mldaddr_f = 0, mldrespdelay_f = 0; + +unsigned char newdata_f = 0; /* Support for IPv6 extension headers */ -unsigned int dstopthdrs, dstoptuhdrs, hbhopthdrs; -unsigned char hbhopthdr_f=0, dstoptuhdr_f=0, dstopthdr_f=0; -unsigned char *dstopthdr[MAX_DST_OPT_HDR], *dstoptuhdr[MAX_DST_OPT_U_HDR]; -unsigned char *hbhopthdr[MAX_HBH_OPT_HDR]; -unsigned int dstopthdrlen[MAX_DST_OPT_HDR], dstoptuhdrlen[MAX_DST_OPT_U_HDR]; -unsigned int hbhopthdrlen[MAX_HBH_OPT_HDR], m, pad; +unsigned int dstopthdrs, dstoptuhdrs, hbhopthdrs; +unsigned char hbhopthdr_f = 0, dstoptuhdr_f = 0, dstopthdr_f = 0; +unsigned char *dstopthdr[MAX_DST_OPT_HDR], *dstoptuhdr[MAX_DST_OPT_U_HDR]; +unsigned char *hbhopthdr[MAX_HBH_OPT_HDR]; +unsigned int dstopthdrlen[MAX_DST_OPT_HDR], dstoptuhdrlen[MAX_DST_OPT_U_HDR]; +unsigned int hbhopthdrlen[MAX_HBH_OPT_HDR], m, pad; /* The Hop-by-hop option used in MLD query messages */ const struct { - struct ip6_hbh hbh; - struct ip6_opt_router rtr_alert; - struct ip6_opt pad1; -} __attribute__ ((__packed__)) mld_hbh = { - .hbh = { - .ip6h_nxt = IPPROTO_ICMPV6, - .ip6h_len = 0, - }, - .rtr_alert = { - .ip6or_type = IP6OPT_ROUTER_ALERT, - .ip6or_len = 2, - .ip6or_value = IP6_ALERT_MLD, - }, - .pad1 = { - .ip6o_type = IP6OPT_PAD1, - .ip6o_len = 0, - }, + struct ip6_hbh hbh; + struct ip6_opt_router rtr_alert; + struct ip6_opt pad1; +} __attribute__((__packed__)) mld_hbh = { + .hbh = + { + .ip6h_nxt = IPPROTO_ICMPV6, + .ip6h_len = 0, + }, + .rtr_alert = + { + .ip6or_type = IP6OPT_ROUTER_ALERT, + .ip6or_len = 2, + .ip6or_value = IP6_ALERT_MLD, + }, + .pad1 = + { + .ip6o_type = IP6OPT_PAD1, + .ip6o_len = 0, + }, }; +struct ip6_frag fraghdr, *fh; +struct ip6_hdr *fipv6; +unsigned char fragbuffer[ETHER_HDR_LEN + MIN_IPV6_HLEN + MAX_IPV6_PAYLOAD]; +unsigned char *fragpart, *fptr, *fptrend, *ptrend, *ptrhdr, *ptrhdrend; +unsigned int hdrlen, ndstopthdr = 0, nhbhopthdr = 0, ndstoptuhdr = 0; +unsigned int nfrags, fragsize; +unsigned char *prev_nh, *startoffragment; + +struct iface_data idata; + +int main(int argc, char **argv) { + extern char *optarg; + int r; + + static struct option longopts[] = {{"interface", required_argument, 0, 'i'}, + {"src-addr", required_argument, 0, 's'}, + {"dst-addr", required_argument, 0, 'd'}, + {"hop-limit", required_argument, 0, 'A'}, + {"dst-opt-hdr", required_argument, 0, 'u'}, + {"dst-opt-u-hdr", required_argument, 0, 'U'}, + {"hbh-opt-hdr", required_argument, 0, 'H'}, + {"frag-hdr", required_argument, 0, 'y'}, + {"link-src-addr", required_argument, 0, 'S'}, + {"link-dst-addr", required_argument, 0, 'D'}, + {"add-slla-opt", no_argument, 0, 'e'}, + {"src-link-opt", required_argument, 0, 'E'}, + {"mld-addr", required_argument, 0, 'm'}, + {"mld-resp-delay", required_argument, 0, 'r'}, + {"flood-sources", required_argument, 0, 'F'}, + {"loop", no_argument, 0, 'l'}, + {"sleep", no_argument, 0, 'z'}, + {"verbose", no_argument, 0, 'v'}, + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0}}; + + const char shortopts[] = "i:s:d:A:u:U:H:y:S:D:eE:m:r:F:lz:vh"; + char option; + + if (argc <= 1) { + usage(); + exit(EXIT_FAILURE); + } + + if (init_iface_data(&idata) == FAILURE) { + puts("Error initializing internal data structure"); + exit(EXIT_FAILURE); + } + + while ((r = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { + option = r; + + switch (option) { + case 'i': /* Interface */ + strncpy(idata.iface, optarg, IFACE_LENGTH); + idata.iface[IFACE_LENGTH - 1] = 0; + idata.iface_f = TRUE; + break; + + case 's': /* IPv6 Source Address */ + if ((charptr = strtok_r(optarg, "/", &lasts)) == NULL) { + puts("Error in IPv6 Source Address ('-s' option)"); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, charptr, &(idata.srcaddr)) <= 0) { + puts("inet_pton(): address not valid"); + exit(EXIT_FAILURE); + } -struct ip6_frag fraghdr, *fh; -struct ip6_hdr *fipv6; -unsigned char fragbuffer[ETHER_HDR_LEN+MIN_IPV6_HLEN+MAX_IPV6_PAYLOAD]; -unsigned char *fragpart, *fptr, *fptrend, *ptrend, *ptrhdr, *ptrhdrend; -unsigned int hdrlen, ndstopthdr=0, nhbhopthdr=0, ndstoptuhdr=0; -unsigned int nfrags, fragsize; -unsigned char *prev_nh, *startoffragment; - -struct iface_data idata; - -int main(int argc, char **argv){ - extern char *optarg; - int r; - - static struct option longopts[] = { - {"interface", required_argument, 0, 'i'}, - {"src-addr", required_argument, 0, 's'}, - {"dst-addr", required_argument, 0, 'd'}, - {"hop-limit", required_argument, 0, 'A'}, - {"dst-opt-hdr", required_argument, 0, 'u'}, - {"dst-opt-u-hdr", required_argument, 0, 'U'}, - {"hbh-opt-hdr", required_argument, 0, 'H'}, - {"frag-hdr", required_argument, 0, 'y'}, - {"link-src-addr", required_argument, 0, 'S'}, - {"link-dst-addr", required_argument, 0, 'D'}, - {"add-slla-opt", no_argument, 0, 'e'}, - {"src-link-opt", required_argument, 0, 'E'}, - {"mld-addr", required_argument, 0, 'm'}, - {"mld-resp-delay", required_argument, 0, 'r'}, - {"flood-sources", required_argument, 0, 'F'}, - {"loop", no_argument, 0, 'l'}, - {"sleep", no_argument, 0, 'z'}, - {"verbose", no_argument, 0, 'v'}, - {"help", no_argument, 0, 'h'}, - {0, 0, 0, 0 } - }; - - const char shortopts[]= "i:s:d:A:u:U:H:y:S:D:eE:m:r:F:lz:vh"; - char option; - - if(argc<=1){ - usage(); - exit(EXIT_FAILURE); - } - - if(init_iface_data(&idata) == FAILURE){ - puts("Error initializing internal data structure"); - exit(EXIT_FAILURE); - } - - while((r=getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { - option= r; - - switch(option) { - case 'i': /* Interface */ - strncpy(idata.iface, optarg, IFACE_LENGTH); - idata.iface[IFACE_LENGTH-1]=0; - idata.iface_f=TRUE; - break; - - case 's': /* IPv6 Source Address */ - if((charptr = strtok_r(optarg, "/", &lasts)) == NULL){ - puts("Error in IPv6 Source Address ('-s' option)"); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, charptr, &(idata.srcaddr)) <= 0){ - puts("inet_pton(): address not valid"); - exit(EXIT_FAILURE); - } - - idata.srcaddr_f = 1; - - if((charptr = strtok_r(NULL, " ", &lasts)) != NULL){ - idata.srcpreflen = atoi(charptr); - - if(idata.srcpreflen>128){ - puts("Prefix length error in IPv6 Source Address"); - exit(EXIT_FAILURE); - } - - sanitize_ipv6_prefix(&(idata.srcaddr), idata.srcpreflen); - idata.srcprefix_f=1; - } - - break; - - case 'd': /* IPv6 Destination Address */ - if( inet_pton(AF_INET6, optarg, &(idata.dstaddr)) <= 0){ - puts("inet_pton(): address not valid"); - exit(EXIT_FAILURE); - } - - idata.dstaddr_f = 1; - break; - - case 'A': /* Hop Limit */ - hoplimit= atoi(optarg); - hoplimit_f=1; - break; - - case 'y': /* Fragment header */ - nfrags= atoi(optarg); - - if(nfrags < 8){ - puts("Error in Fragmentation option: Fragment Size must be at least 8 bytes"); - exit(EXIT_FAILURE); - } - - idata.fragh_f= 1; - break; - - case 'u': /* Destinations Options Header */ - if(ndstopthdr >= MAX_DST_OPT_HDR){ - puts("Too many Destination Options Headers"); - exit(EXIT_FAILURE); - } - - hdrlen= atoi(optarg); - - if(hdrlen < 8){ - puts("Bad length in Destination Options Header"); - exit(EXIT_FAILURE); - } - - hdrlen = ((hdrlen+7)/8) * 8; - dstopthdrlen[ndstopthdr]= hdrlen; - - if( (dstopthdr[ndstopthdr]= malloc(hdrlen)) == NULL){ - puts("Not enough memory for Destination Options Header"); - exit(EXIT_FAILURE); - } - - ptrhdr= dstopthdr[ndstopthdr] + 2; - ptrhdrend= dstopthdr[ndstopthdr] + hdrlen; - - while( ptrhdr < ptrhdrend){ - if( (ptrhdrend-ptrhdr)>257) - pad= 257; - else - pad= ptrhdrend-ptrhdr; - - if(!insert_pad_opt(ptrhdr, ptrhdrend, pad)){ - puts("Destination Options Header Too Big"); - exit(EXIT_FAILURE); - } - - ptrhdr= ptrhdr + pad; - } - - *(dstopthdr[ndstopthdr]+1)= (hdrlen/8)-1; - ndstopthdr++; - dstopthdr_f=1; - break; - - case 'U': /* Destination Options Header (Unfragmentable Part) */ - if(ndstoptuhdr >= MAX_DST_OPT_U_HDR){ - puts("Too many Destination Options Headers (Unfragmentable Part)"); - exit(EXIT_FAILURE); - } - - hdrlen= atoi(optarg); - - if(hdrlen < 8){ - puts("Bad length in Destination Options Header (Unfragmentable Part)"); - exit(EXIT_FAILURE); - } - - hdrlen = ((hdrlen+7)/8) * 8; - dstoptuhdrlen[ndstoptuhdr]= hdrlen; - - if( (dstoptuhdr[ndstoptuhdr]= malloc(hdrlen)) == NULL){ - puts("Not enough memory for Destination Options Header (Unfragmentable Part)"); - exit(EXIT_FAILURE); - } - - ptrhdr= dstoptuhdr[ndstoptuhdr]+2; - ptrhdrend= dstoptuhdr[ndstoptuhdr] + hdrlen; - - while( ptrhdr < ptrhdrend){ - - if( (ptrhdrend-ptrhdr)>257) - pad= 257; - else - pad= ptrhdrend-ptrhdr; - - if(!insert_pad_opt(ptrhdr, ptrhdrend, pad)){ - puts("Destination Options Header (Unfragmentable Part) Too Big"); - exit(EXIT_FAILURE); - } - - ptrhdr = ptrhdr + pad; - } - - *(dstoptuhdr[ndstoptuhdr]+1)= (hdrlen/8) - 1; - ndstoptuhdr++; - dstoptuhdr_f=1; - break; - - case 'H': /* Hop-by-Hop Options Header */ - if(nhbhopthdr >= MAX_HBH_OPT_HDR){ - puts("Too many Hop-by-Hop Options Headers"); - exit(EXIT_FAILURE); - } - - hdrlen= atoi(optarg); - - if(hdrlen == 0 ){ - nhbhopthdr=0; - hbhopthdr_f=1; - break; - } else if(hdrlen < 8){ - puts("Bad length in Hop-by-Hop Options Header"); - exit(EXIT_FAILURE); - } - - hdrlen = ((hdrlen+7)/8) * 8; - hbhopthdrlen[nhbhopthdr]= hdrlen; - - if( (hbhopthdr[nhbhopthdr]= malloc(hdrlen)) == NULL){ - puts("Not enough memory for Hop-by-Hop Options Header"); - exit(EXIT_FAILURE); - } - - ptrhdr= hbhopthdr[nhbhopthdr] + 2; - ptrhdrend= hbhopthdr[nhbhopthdr] + hdrlen; - - - while( ptrhdr < ptrhdrend){ - - if( (ptrhdrend-ptrhdr)>257) - pad= 257; - else - pad= ptrhdrend-ptrhdr; - - if(!insert_pad_opt(ptrhdr, ptrhdrend, pad)){ - puts("Hop-by-Hop Options Header Too Big"); - exit(EXIT_FAILURE); - } - - ptrhdr = ptrhdr + pad; - } - - *(hbhopthdr[nhbhopthdr]+1)= (hdrlen/8) - 1; - nhbhopthdr++; - hbhopthdr_f=1; - break; - - case 'S': /* Source Ethernet address */ - idata.hsrcaddr_f = 1; - - if(ether_pton(optarg, &(idata.hsrcaddr), sizeof(idata.hsrcaddr)) == 0){ - puts("Error in Source link-layer address."); - exit(EXIT_FAILURE); - } - break; - - case 'D': /* Destination Ethernet Address */ - idata.hdstaddr_f = 1; - - if(ether_pton(optarg, &(idata.hdstaddr), sizeof(idata.hdstaddr)) == 0){ - puts("Error in Source link-layer address."); - exit(EXIT_FAILURE); - } - break; - - case 'E': /* Source link-layer option */ - sllopt_f = 1; - - if(ether_pton(optarg, &linkaddr[nlinkaddr], sizeof(struct ether_addr)) == 0){ - puts("Error in Source link-layer address option."); - exit(EXIT_FAILURE); - } - - sllopta_f=1; - nlinkaddr++; - break; - - case 'e': /* Add Source link-layer option */ - sllopt_f = 1; - break; - - case 'm': /* MLD Query Multicast Address */ - if( inet_pton(AF_INET6, optarg, &mldaddr) <= 0){ - puts("inet_pton(): address not valid"); - exit(EXIT_FAILURE); - } - - mldaddr_f = 1; - break; - - case 'r': /* MLD Query Maximum Response Delay */ - mldrespdelay= atoi(optarg); - mldrespdelay_f= 1; - break; - - case 'F': /* Flood sources */ - nsources= atoi(optarg); - if(nsources == 0){ - puts("Invalid number of sources in option -F"); - exit(EXIT_FAILURE); - } - - floods_f= 1; - break; - - case 'l': /* "Loop mode */ - loop_f = 1; - break; - - case 'z': /* Sleep option */ - nsleep=atoi(optarg); - if(nsleep==0){ - puts("Invalid number of seconds in '-z' option"); - exit(EXIT_FAILURE); - } - - sleep_f=1; - break; - - case 'v': /* Be verbose */ - idata.verbose_f=1; - break; - - case 'h': /* Help */ - print_help(); - - exit(EXIT_FAILURE); - break; - - default: - usage(); - exit(EXIT_FAILURE); - break; - } /* switch */ + idata.srcaddr_f = 1; + + if ((charptr = strtok_r(NULL, " ", &lasts)) != NULL) { + idata.srcpreflen = atoi(charptr); + + if (idata.srcpreflen > 128) { + puts("Prefix length error in IPv6 Source Address"); + exit(EXIT_FAILURE); + } + + sanitize_ipv6_prefix(&(idata.srcaddr), idata.srcpreflen); + idata.srcprefix_f = 1; + } + + break; + + case 'd': /* IPv6 Destination Address */ + if (inet_pton(AF_INET6, optarg, &(idata.dstaddr)) <= 0) { + puts("inet_pton(): address not valid"); + exit(EXIT_FAILURE); + } + + idata.dstaddr_f = 1; + break; + + case 'A': /* Hop Limit */ + hoplimit = atoi(optarg); + hoplimit_f = 1; + break; + + case 'y': /* Fragment header */ + nfrags = atoi(optarg); + + if (nfrags < 8) { + puts("Error in Fragmentation option: Fragment Size must be at least 8 bytes"); + exit(EXIT_FAILURE); + } + + idata.fragh_f = 1; + break; + + case 'u': /* Destinations Options Header */ + if (ndstopthdr >= MAX_DST_OPT_HDR) { + puts("Too many Destination Options Headers"); + exit(EXIT_FAILURE); + } + + hdrlen = atoi(optarg); + + if (hdrlen < 8) { + puts("Bad length in Destination Options Header"); + exit(EXIT_FAILURE); + } + + hdrlen = ((hdrlen + 7) / 8) * 8; + dstopthdrlen[ndstopthdr] = hdrlen; + + if ((dstopthdr[ndstopthdr] = malloc(hdrlen)) == NULL) { + puts("Not enough memory for Destination Options Header"); + exit(EXIT_FAILURE); + } + + ptrhdr = dstopthdr[ndstopthdr] + 2; + ptrhdrend = dstopthdr[ndstopthdr] + hdrlen; + + while (ptrhdr < ptrhdrend) { + if ((ptrhdrend - ptrhdr) > 257) + pad = 257; + else + pad = ptrhdrend - ptrhdr; + + if (!insert_pad_opt(ptrhdr, ptrhdrend, pad)) { + puts("Destination Options Header Too Big"); + exit(EXIT_FAILURE); + } + + ptrhdr = ptrhdr + pad; + } + + *(dstopthdr[ndstopthdr] + 1) = (hdrlen / 8) - 1; + ndstopthdr++; + dstopthdr_f = 1; + break; + + case 'U': /* Destination Options Header (Unfragmentable Part) */ + if (ndstoptuhdr >= MAX_DST_OPT_U_HDR) { + puts("Too many Destination Options Headers (Unfragmentable Part)"); + exit(EXIT_FAILURE); + } + + hdrlen = atoi(optarg); + + if (hdrlen < 8) { + puts("Bad length in Destination Options Header (Unfragmentable Part)"); + exit(EXIT_FAILURE); + } + + hdrlen = ((hdrlen + 7) / 8) * 8; + dstoptuhdrlen[ndstoptuhdr] = hdrlen; + + if ((dstoptuhdr[ndstoptuhdr] = malloc(hdrlen)) == NULL) { + puts("Not enough memory for Destination Options Header (Unfragmentable Part)"); + exit(EXIT_FAILURE); + } + + ptrhdr = dstoptuhdr[ndstoptuhdr] + 2; + ptrhdrend = dstoptuhdr[ndstoptuhdr] + hdrlen; + + while (ptrhdr < ptrhdrend) { + + if ((ptrhdrend - ptrhdr) > 257) + pad = 257; + else + pad = ptrhdrend - ptrhdr; + + if (!insert_pad_opt(ptrhdr, ptrhdrend, pad)) { + puts("Destination Options Header (Unfragmentable Part) Too Big"); + exit(EXIT_FAILURE); + } + + ptrhdr = ptrhdr + pad; + } + + *(dstoptuhdr[ndstoptuhdr] + 1) = (hdrlen / 8) - 1; + ndstoptuhdr++; + dstoptuhdr_f = 1; + break; + + case 'H': /* Hop-by-Hop Options Header */ + if (nhbhopthdr >= MAX_HBH_OPT_HDR) { + puts("Too many Hop-by-Hop Options Headers"); + exit(EXIT_FAILURE); + } + + hdrlen = atoi(optarg); + + if (hdrlen == 0) { + nhbhopthdr = 0; + hbhopthdr_f = 1; + break; + } + else if (hdrlen < 8) { + puts("Bad length in Hop-by-Hop Options Header"); + exit(EXIT_FAILURE); + } + + hdrlen = ((hdrlen + 7) / 8) * 8; + hbhopthdrlen[nhbhopthdr] = hdrlen; + + if ((hbhopthdr[nhbhopthdr] = malloc(hdrlen)) == NULL) { + puts("Not enough memory for Hop-by-Hop Options Header"); + exit(EXIT_FAILURE); + } + + ptrhdr = hbhopthdr[nhbhopthdr] + 2; + ptrhdrend = hbhopthdr[nhbhopthdr] + hdrlen; + + while (ptrhdr < ptrhdrend) { + + if ((ptrhdrend - ptrhdr) > 257) + pad = 257; + else + pad = ptrhdrend - ptrhdr; + + if (!insert_pad_opt(ptrhdr, ptrhdrend, pad)) { + puts("Hop-by-Hop Options Header Too Big"); + exit(EXIT_FAILURE); + } + + ptrhdr = ptrhdr + pad; + } + + *(hbhopthdr[nhbhopthdr] + 1) = (hdrlen / 8) - 1; + nhbhopthdr++; + hbhopthdr_f = 1; + break; + + case 'S': /* Source Ethernet address */ + idata.hsrcaddr_f = 1; + + if (ether_pton(optarg, &(idata.hsrcaddr), sizeof(idata.hsrcaddr)) == 0) { + puts("Error in Source link-layer address."); + exit(EXIT_FAILURE); + } + break; + + case 'D': /* Destination Ethernet Address */ + idata.hdstaddr_f = 1; + + if (ether_pton(optarg, &(idata.hdstaddr), sizeof(idata.hdstaddr)) == 0) { + puts("Error in Source link-layer address."); + exit(EXIT_FAILURE); + } + break; + + case 'E': /* Source link-layer option */ + sllopt_f = 1; + + if (ether_pton(optarg, &linkaddr[nlinkaddr], sizeof(struct ether_addr)) == 0) { + puts("Error in Source link-layer address option."); + exit(EXIT_FAILURE); + } + + sllopta_f = 1; + nlinkaddr++; + break; + + case 'e': /* Add Source link-layer option */ + sllopt_f = 1; + break; + + case 'm': /* MLD Query Multicast Address */ + if (inet_pton(AF_INET6, optarg, &mldaddr) <= 0) { + puts("inet_pton(): address not valid"); + exit(EXIT_FAILURE); + } + + mldaddr_f = 1; + break; + + case 'r': /* MLD Query Maximum Response Delay */ + mldrespdelay = atoi(optarg); + mldrespdelay_f = 1; + break; + + case 'F': /* Flood sources */ + nsources = atoi(optarg); + if (nsources == 0) { + puts("Invalid number of sources in option -F"); + exit(EXIT_FAILURE); + } + + floods_f = 1; + break; + + case 'l': /* "Loop mode */ + loop_f = 1; + break; + + case 'z': /* Sleep option */ + nsleep = atoi(optarg); + if (nsleep == 0) { + puts("Invalid number of seconds in '-z' option"); + exit(EXIT_FAILURE); + } + + sleep_f = 1; + break; + + case 'v': /* Be verbose */ + idata.verbose_f = 1; + break; + + case 'h': /* Help */ + print_help(); + + exit(EXIT_FAILURE); + break; + + default: + usage(); + exit(EXIT_FAILURE); + break; + } /* switch */ } /* while(getopt) */ - if(geteuid()) { - puts("mldq6 needs root privileges to run."); - exit(EXIT_FAILURE); - } + if (geteuid()) { + puts("mldq6 needs root privileges to run."); + exit(EXIT_FAILURE); + } + + if (!idata.iface_f) { + puts("Must specify the network interface with the -i option"); + exit(EXIT_FAILURE); + } - if(!idata.iface_f){ - puts("Must specify the network interface with the -i option"); - exit(EXIT_FAILURE); - } + if (load_dst_and_pcap(&idata, (idata.dstaddr_f ? LOAD_SRC_NXT_HOP : LOAD_PCAP_ONLY)) == FAILURE) { + puts("Error while learning Source Address and Next Hop"); + exit(EXIT_FAILURE); + } - if(load_dst_and_pcap(&idata, (idata.dstaddr_f?LOAD_SRC_NXT_HOP:LOAD_PCAP_ONLY)) == FAILURE){ - puts("Error while learning Source Address and Next Hop"); - exit(EXIT_FAILURE); - } + release_privileges(); - release_privileges(); + if (pcap_datalink(idata.pfd) != DLT_EN10MB) { + printf("Error: Interface %s is not an Ethernet interface\n", idata.iface); + exit(EXIT_FAILURE); + } - if( pcap_datalink(idata.pfd) != DLT_EN10MB){ - printf("Error: Interface %s is not an Ethernet interface\n", idata.iface); - exit(EXIT_FAILURE); - } + if (pcap_compile(idata.pfd, &pcap_filter, PCAP_NOPACKETS_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1) { + printf("pcap_compile(): %s", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } - if(pcap_compile(idata.pfd, &pcap_filter, PCAP_NOPACKETS_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1){ - printf("pcap_compile(): %s", pcap_geterr(idata.pfd)); - exit(EXIT_FAILURE); - } - - if(pcap_setfilter(idata.pfd, &pcap_filter) == -1){ - printf("pcap_setfilter(): %s", pcap_geterr(idata.pfd)); - exit(EXIT_FAILURE); - } + if (pcap_setfilter(idata.pfd, &pcap_filter) == -1) { + printf("pcap_setfilter(): %s", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } - pcap_freecode(&pcap_filter); + pcap_freecode(&pcap_filter); - srandom(time(NULL)); + srandom(time(NULL)); - /* + /* If the IPv6 Source Address has not been specified, and the "-F" (flood) option has not been specified, select a random link-local unicast address. */ - if(!idata.srcaddr_f && !floods_f){ - /* When randomizing a link-local IPv6 address, select addresses that belong to the - prefix fe80::/64 (that's what a link-local address looks-like in legitimate cases). - The KAME implementation discards addresses in which the second highe-order 16 bits - (srcaddr.s6_addr16[1] in our case) are not zero. - */ - if ( inet_pton(AF_INET6, "fe80::", &(idata.srcaddr)) <= 0){ - puts("inet_pton(): Error when converting address"); - exit(EXIT_FAILURE); - } - - randomize_ipv6_addr(&(idata.srcaddr), &(idata.srcaddr), 64); + if (!idata.srcaddr_f && !floods_f) { + /* When randomizing a link-local IPv6 address, select addresses that belong to the + prefix fe80::/64 (that's what a link-local address looks-like in legitimate cases). + The KAME implementation discards addresses in which the second highe-order 16 bits + (srcaddr.s6_addr16[1] in our case) are not zero. + */ + if (inet_pton(AF_INET6, "fe80::", &(idata.srcaddr)) <= 0) { + puts("inet_pton(): Error when converting address"); + exit(EXIT_FAILURE); + } + + randomize_ipv6_addr(&(idata.srcaddr), &(idata.srcaddr), 64); } - /* If the flood option ("-F") has been specified, but no prefix has been specified, select the random Source Addresses from the link-local unicast prefix (fe80::/64). */ - if(floods_f && !idata.srcprefix_f){ - if ( inet_pton(AF_INET6, "fe80::", &(idata.srcaddr)) <= 0){ - puts("inet_pton(): Error when converting address"); - exit(EXIT_FAILURE); - } - - randomize_ipv6_addr(&(idata.srcaddr), &(idata.srcaddr), 64); - idata.srcpreflen=64; + if (floods_f && !idata.srcprefix_f) { + if (inet_pton(AF_INET6, "fe80::", &(idata.srcaddr)) <= 0) { + puts("inet_pton(): Error when converting address"); + exit(EXIT_FAILURE); + } + + randomize_ipv6_addr(&(idata.srcaddr), &(idata.srcaddr), 64); + idata.srcpreflen = 64; + } + + if (!idata.dstaddr_f) { /* Destination Address defaults to all-nodes (ff02::1) */ + if (inet_pton(AF_INET6, ALL_NODES_MULTICAST_ADDR, &(idata.dstaddr)) <= 0) { + puts("inet_pton(): address not valid"); + exit(EXIT_FAILURE); + } } - if(!idata.dstaddr_f){ /* Destination Address defaults to all-nodes (ff02::1) */ - if( inet_pton(AF_INET6, ALL_NODES_MULTICAST_ADDR, &(idata.dstaddr)) <= 0){ - puts("inet_pton(): address not valid"); - exit(EXIT_FAILURE); - } - } - - if(!idata.hsrcaddr_f) /* Source link-layer address is randomized by default */ - randomize_ether_addr(&(idata.hsrcaddr)); - - if(!idata.hdstaddr_f) /* Destination link-layer address defaults to all-nodes */ - if(ether_pton(ETHER_ALLNODES_LINK_ADDR, &(idata.hdstaddr), sizeof(idata.hdstaddr)) == 0){ - puts("ether_pton(): Error converting all-nodes multicast address"); - exit(EXIT_FAILURE); - } - - if(sllopt_f && !sllopta_f){ /* The value of the source link-layer address option */ - linkaddr[0]= idata.hsrcaddr; /* defaults to the source Ethernet address */ - nlinkaddr++; - } - - if(!floods_f) - nsources=1; - - if(!sleep_f) - nsleep=120; - - if( !idata.fragh_f && dstoptuhdr_f){ - puts("Dst. Options Header (Unfragmentable Part) set, but Fragmentation not specified"); - exit(EXIT_FAILURE); - } - - if(idata.verbose_f){ - print_attack_info(&idata); - } + if (!idata.hsrcaddr_f) /* Source link-layer address is randomized by default */ + randomize_ether_addr(&(idata.hsrcaddr)); + + if (!idata.hdstaddr_f) /* Destination link-layer address defaults to all-nodes */ + if (ether_pton(ETHER_ALLNODES_LINK_ADDR, &(idata.hdstaddr), sizeof(idata.hdstaddr)) == 0) { + puts("ether_pton(): Error converting all-nodes multicast address"); + exit(EXIT_FAILURE); + } + + if (sllopt_f && !sllopta_f) { /* The value of the source link-layer address option */ + linkaddr[0] = idata.hsrcaddr; /* defaults to the source Ethernet address */ + nlinkaddr++; + } + + if (!floods_f) + nsources = 1; + + if (!sleep_f) + nsleep = 120; + + if (!idata.fragh_f && dstoptuhdr_f) { + puts("Dst. Options Header (Unfragmentable Part) set, but Fragmentation not specified"); + exit(EXIT_FAILURE); + } + + if (idata.verbose_f) { + print_attack_info(&idata); + } /* Set initial contents of the attack packet */ init_packet_data(&idata); - + send_packet(&idata); - - if(idata.verbose_f) - puts("Initial attack packet(s) sent successfully."); - - if(loop_f && idata.verbose_f) - printf("Now sending MLD Queries every %u second%s...\n", nsleep, \ - ((nsleep>1)?"s":"")); - - while(loop_f){ - sleep(nsleep); - send_packet(&idata); - } - - exit(EXIT_SUCCESS); -} + if (idata.verbose_f) + puts("Initial attack packet(s) sent successfully."); + + if (loop_f && idata.verbose_f) + printf("Now sending MLD Queries every %u second%s...\n", nsleep, ((nsleep > 1) ? "s" : "")); + + while (loop_f) { + sleep(nsleep); + send_packet(&idata); + } + exit(EXIT_SUCCESS); +} /* * Function: init_packet_data() @@ -596,161 +590,162 @@ int main(int argc, char **argv){ * Initialize the contents of the attack packet (Ethernet header, IPv6 Header, and ICMPv6 header) * that are expected to remain constant for the specified attack. */ -void init_packet_data(struct iface_data *idata){ - struct dlt_null *dlt_null; - ethernet= (struct ether_header *) buffer; - dlt_null= (struct dlt_null *) buffer; - v6buffer = buffer + idata->linkhsize; - ipv6 = (struct ip6_hdr *) v6buffer; - - if(idata->type == DLT_EN10MB){ - ethernet->ether_type = htons(ETHERTYPE_IPV6); - - if(!(idata->flags & IFACE_LOOPBACK)){ - ethernet->src = idata->hsrcaddr; - ethernet->dst = idata->hdstaddr; - } - } - else if(idata->type == DLT_NULL){ - dlt_null->family= PF_INET6; - } -#if defined (__OpenBSD__) - else if(idata->type == DLT_LOOP){ - dlt_null->family= htonl(PF_INET6); - } +void init_packet_data(struct iface_data *idata) { + struct dlt_null *dlt_null; + ethernet = (struct ether_header *)buffer; + dlt_null = (struct dlt_null *)buffer; + v6buffer = buffer + idata->linkhsize; + ipv6 = (struct ip6_hdr *)v6buffer; + + if (idata->type == DLT_EN10MB) { + ethernet->ether_type = htons(ETHERTYPE_IPV6); + + if (!(idata->flags & IFACE_LOOPBACK)) { + ethernet->src = idata->hsrcaddr; + ethernet->dst = idata->hdstaddr; + } + } + else if (idata->type == DLT_NULL) { + dlt_null->family = PF_INET6; + } +#if defined(__OpenBSD__) + else if (idata->type == DLT_LOOP) { + dlt_null->family = htonl(PF_INET6); + } #endif - ipv6->ip6_flow=0; - ipv6->ip6_vfc= 0x60; - ipv6->ip6_hlim= hoplimit; - ipv6->ip6_src= idata->srcaddr; - ipv6->ip6_dst= idata->dstaddr; - prev_nh = (unsigned char *) &(ipv6->ip6_nxt); - - ptr = (unsigned char *) v6buffer + MIN_IPV6_HLEN; - - /* add a non-standard Hop-by-hop header ("-H n", n >=8 ) */ - if(hbhopthdr_f && nhbhopthdr != 0){ - hbhopthdrs=0; - - while(hbhopthdrs < nhbhopthdr){ - if((ptr+ hbhopthdrlen[hbhopthdrs]) > (v6buffer+ idata->mtu)){ - puts("Packet too large while processing HBH Opt. Header"); - exit(EXIT_FAILURE); - } - - *prev_nh = IPPROTO_HOPOPTS; - prev_nh = ptr; - memcpy(ptr, hbhopthdr[hbhopthdrs], hbhopthdrlen[hbhopthdrs]); - ptr = ptr + hbhopthdrlen[hbhopthdrs]; - hbhopthdrs++; - } - /* add standard MLD Hop-by-hop header */ - } else if (!hbhopthdr_f){ - if((ptr+ sizeof(mld_hbh)) > (v6buffer+ idata->mtu)){ - puts("Packet too large while processing HBH Opt. Header"); - exit(EXIT_FAILURE); - } - - *prev_nh = IPPROTO_HOPOPTS; - prev_nh = ptr; - memcpy(ptr, &mld_hbh, sizeof(mld_hbh)); - ptr = ptr + sizeof(mld_hbh); - } /* else: -H 0 => omit hbh header to create an invalid MLD Query */ - - if(dstoptuhdr_f){ - dstoptuhdrs=0; - - while(dstoptuhdrs < ndstoptuhdr){ - if((ptr+ dstoptuhdrlen[dstoptuhdrs]) > (v6buffer+ idata->mtu)){ - puts("Packet too large while processing Dest. Opt. Header (Unfrag. Part)"); - exit(EXIT_FAILURE); - } - - *prev_nh = IPPROTO_DSTOPTS; - prev_nh = ptr; - memcpy(ptr, dstoptuhdr[dstoptuhdrs], dstoptuhdrlen[dstoptuhdrs]); - ptr = ptr + dstoptuhdrlen[dstoptuhdrs]; - dstoptuhdrs++; - } - } - - /* Everything that follows is the Fragmentable Part of the packet */ - fragpart = ptr; - - if(idata->fragh_f){ - /* Check that we are able to send the Unfragmentable Part, together with a - Fragment Header and a chunk data over our link layer - */ - if( (fragpart+sizeof(fraghdr)+nfrags) > (v6buffer+idata->mtu)){ - printf("Unfragmentable part too large for current MTU (%u bytes)\n", idata->mtu); - exit(EXIT_FAILURE); - } - - /* We prepare a separete Fragment Header, but we do not include it in the packet to be sent. - This Fragment Header will be used (an assembled with the rest of the packet by the - send_packet() function. - */ - memset(&fraghdr, 0, FRAG_HDR_SIZE); - *prev_nh = IPPROTO_FRAGMENT; - prev_nh = (unsigned char *) &fraghdr; - } - - if(dstopthdr_f){ - dstopthdrs=0; - - while(dstopthdrs < ndstopthdr){ - if((ptr+ dstopthdrlen[dstopthdrs]) > (v6buffer+idata->max_packet_size)){ - puts("Packet too large while processing Dest. Opt. Header (U. part) (should be using the Frag. option?)"); - exit(EXIT_FAILURE); - } - - *prev_nh = IPPROTO_DSTOPTS; - prev_nh = ptr; - memcpy(ptr, dstopthdr[dstopthdrs], dstopthdrlen[dstopthdrs]); - ptr = ptr + dstopthdrlen[dstopthdrs]; - dstopthdrs++; - } - } - - *prev_nh = IPPROTO_ICMPV6; - - if( (ptr+sizeof(struct mld_hdr)) > (v6buffer+idata->max_packet_size)){ - puts("Packet too large while inserting MLD Query header (should be using Frag. option?)"); - exit(EXIT_FAILURE); - } - - mldq= (struct mld_hdr *) (ptr); - mldq->mld_type = MLD_LISTENER_QUERY; - mldq->mld_code = 0; - mldq->mld_maxdelay = htons(mldrespdelay); - mldq->mld_reserved = 0; - - if (mldaddr_f) - memcpy(&mldq->mld_addr, &mldaddr, sizeof(mldq->mld_addr)); - else - memset(&mldq->mld_addr, 0, sizeof(mldq->mld_addr)); - - ptr += sizeof(struct mld_hdr); - - /* If a single source link-layer address is specified, it is included in all packets */ - if(sllopt_f && nlinkaddr==1){ - if( (ptr+sizeof(struct nd_opt_slla)) <= (v6buffer+idata->max_packet_size)){ - sllaopt = (struct nd_opt_slla *) ptr; - sllaopt->type= ND_OPT_SOURCE_LINKADDR; - sllaopt->length= SLLA_OPT_LEN; - memcpy(sllaopt->address, linkaddr[0].a, ETH_ALEN); - ptr += sizeof(struct nd_opt_slla); - } - else{ - puts("Packet too large while processing source link-layer address opt. (should be using Frag. option?)"); - exit(EXIT_FAILURE); - } - } - - startofprefixes = ptr; -} + ipv6->ip6_flow = 0; + ipv6->ip6_vfc = 0x60; + ipv6->ip6_hlim = hoplimit; + ipv6->ip6_src = idata->srcaddr; + ipv6->ip6_dst = idata->dstaddr; + prev_nh = (unsigned char *)&(ipv6->ip6_nxt); + + ptr = (unsigned char *)v6buffer + MIN_IPV6_HLEN; + + /* add a non-standard Hop-by-hop header ("-H n", n >=8 ) */ + if (hbhopthdr_f && nhbhopthdr != 0) { + hbhopthdrs = 0; + + while (hbhopthdrs < nhbhopthdr) { + if ((ptr + hbhopthdrlen[hbhopthdrs]) > (v6buffer + idata->mtu)) { + puts("Packet too large while processing HBH Opt. Header"); + exit(EXIT_FAILURE); + } + + *prev_nh = IPPROTO_HOPOPTS; + prev_nh = ptr; + memcpy(ptr, hbhopthdr[hbhopthdrs], hbhopthdrlen[hbhopthdrs]); + ptr = ptr + hbhopthdrlen[hbhopthdrs]; + hbhopthdrs++; + } + /* add standard MLD Hop-by-hop header */ + } + else if (!hbhopthdr_f) { + if ((ptr + sizeof(mld_hbh)) > (v6buffer + idata->mtu)) { + puts("Packet too large while processing HBH Opt. Header"); + exit(EXIT_FAILURE); + } + + *prev_nh = IPPROTO_HOPOPTS; + prev_nh = ptr; + memcpy(ptr, &mld_hbh, sizeof(mld_hbh)); + ptr = ptr + sizeof(mld_hbh); + } /* else: -H 0 => omit hbh header to create an invalid MLD Query */ + + if (dstoptuhdr_f) { + dstoptuhdrs = 0; + + while (dstoptuhdrs < ndstoptuhdr) { + if ((ptr + dstoptuhdrlen[dstoptuhdrs]) > (v6buffer + idata->mtu)) { + puts("Packet too large while processing Dest. Opt. Header (Unfrag. Part)"); + exit(EXIT_FAILURE); + } + + *prev_nh = IPPROTO_DSTOPTS; + prev_nh = ptr; + memcpy(ptr, dstoptuhdr[dstoptuhdrs], dstoptuhdrlen[dstoptuhdrs]); + ptr = ptr + dstoptuhdrlen[dstoptuhdrs]; + dstoptuhdrs++; + } + } + + /* Everything that follows is the Fragmentable Part of the packet */ + fragpart = ptr; + + if (idata->fragh_f) { + /* Check that we are able to send the Unfragmentable Part, together with a + Fragment Header and a chunk data over our link layer + */ + if ((fragpart + sizeof(fraghdr) + nfrags) > (v6buffer + idata->mtu)) { + printf("Unfragmentable part too large for current MTU (%u bytes)\n", idata->mtu); + exit(EXIT_FAILURE); + } + + /* We prepare a separete Fragment Header, but we do not include it in the packet to be sent. + This Fragment Header will be used (an assembled with the rest of the packet by the + send_packet() function. + */ + memset(&fraghdr, 0, FRAG_HDR_SIZE); + *prev_nh = IPPROTO_FRAGMENT; + prev_nh = (unsigned char *)&fraghdr; + } + + if (dstopthdr_f) { + dstopthdrs = 0; + + while (dstopthdrs < ndstopthdr) { + if ((ptr + dstopthdrlen[dstopthdrs]) > (v6buffer + idata->max_packet_size)) { + puts("Packet too large while processing Dest. Opt. Header (U. part) (should be using the Frag. " + "option?)"); + exit(EXIT_FAILURE); + } + + *prev_nh = IPPROTO_DSTOPTS; + prev_nh = ptr; + memcpy(ptr, dstopthdr[dstopthdrs], dstopthdrlen[dstopthdrs]); + ptr = ptr + dstopthdrlen[dstopthdrs]; + dstopthdrs++; + } + } + *prev_nh = IPPROTO_ICMPV6; + + if ((ptr + sizeof(struct mld_hdr)) > (v6buffer + idata->max_packet_size)) { + puts("Packet too large while inserting MLD Query header (should be using Frag. option?)"); + exit(EXIT_FAILURE); + } + + mldq = (struct mld_hdr *)(ptr); + mldq->mld_type = MLD_LISTENER_QUERY; + mldq->mld_code = 0; + mldq->mld_maxdelay = htons(mldrespdelay); + mldq->mld_reserved = 0; + + if (mldaddr_f) + memcpy(&mldq->mld_addr, &mldaddr, sizeof(mldq->mld_addr)); + else + memset(&mldq->mld_addr, 0, sizeof(mldq->mld_addr)); + + ptr += sizeof(struct mld_hdr); + + /* If a single source link-layer address is specified, it is included in all packets */ + if (sllopt_f && nlinkaddr == 1) { + if ((ptr + sizeof(struct nd_opt_slla)) <= (v6buffer + idata->max_packet_size)) { + sllaopt = (struct nd_opt_slla *)ptr; + sllaopt->type = ND_OPT_SOURCE_LINKADDR; + sllaopt->length = SLLA_OPT_LEN; + memcpy(sllaopt->address, linkaddr[0].a, ETH_ALEN); + ptr += sizeof(struct nd_opt_slla); + } + else { + puts("Packet too large while processing source link-layer address opt. (should be using Frag. option?)"); + exit(EXIT_FAILURE); + } + } + + startofprefixes = ptr; +} /* * Function: send_packet() @@ -758,268 +753,256 @@ void init_packet_data(struct iface_data *idata){ * Initialize the remaining fields of the MLD Query Message, and * send the attack packet(s). */ -void send_packet(struct iface_data *idata){ - sources=0; - - do{ - if(floods_f){ - /* - Randomize the IPv6 Source address based on the specified prefix and prefix length - (defaults to fe80::/64). - */ - randomize_ipv6_addr(&(ipv6->ip6_src), &(idata->srcaddr), idata->srcpreflen); - - if(!idata->hsrcaddr_f){ - randomize_ether_addr(&(ethernet->src)); - - /* - If the source-link layer address must be included, but no value was - specified we set it to the randomized Ethernet Source Address - */ - if(sllopt_f && !sllopta_f){ - memcpy(sllaopt->address, ethernet->src.a, ETH_ALEN); - } - } - } - - if(nlinkaddr==1) - linkaddrs=1; - else - linkaddrs=0; - - do{ - newdata_f=0; - ptr = startofprefixes; - - while(linkaddrsmax_packet_size){ - sllaopt = (struct nd_opt_slla *) ptr; - sllaopt->type= ND_OPT_SOURCE_LINKADDR; - sllaopt->length= SLLA_OPT_LEN; - memcpy(sllaopt->address, linkaddr[linkaddrs].a, ETH_ALEN); - ptr += sizeof(struct nd_opt_slla); - linkaddrs++; - newdata_f=1; - } - - - mldq->mld_cksum = 0; - mldq->mld_cksum = in_chksum(v6buffer, mldq, ptr-((unsigned char *)mldq), IPPROTO_ICMPV6); - - - if(!idata->fragh_f){ - ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); - - if((nw=pcap_inject(idata->pfd, buffer, ptr - buffer)) == -1){ - printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); - exit(EXIT_FAILURE); - } - - if(nw != (ptr-buffer)){ - printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, \ - (LUI) (ptr-buffer)); - exit(EXIT_FAILURE); - } - } - else{ - ptrend= ptr; - ptr= fragpart; - fptr = fragbuffer; - fipv6 = (struct ip6_hdr *) (fragbuffer + ETHER_HDR_LEN); - fptrend = fptr + ETHER_HDR_LEN+MIN_IPV6_HLEN+MAX_IPV6_PAYLOAD; - memcpy(fptr, buffer, fragpart-buffer); - fptr = fptr + (fragpart-buffer); - - if( (fptr+FRAG_HDR_SIZE)> fptrend){ - puts("Unfragmentable Part is Too Large"); - exit(EXIT_FAILURE); - } - - memcpy(fptr, (char *) &fraghdr, FRAG_HDR_SIZE); - fh= (struct ip6_frag *) fptr; - fh->ip6f_ident=random(); - startoffragment = fptr + FRAG_HDR_SIZE; - - /* - * Check that the selected fragment size is not larger than the largest fragment - * size that can be sent - */ - - if(nfrags > (fptrend - fptr)) - nfrags= (fptrend-fptr); - - m=IP6F_MORE_FRAG; - - while((ptr< ptrend) && m==IP6F_MORE_FRAG){ - fptr= startoffragment; - - if( (ptrend-ptr) <= nfrags){ - fragsize= ptrend-ptr; - m=0; - } - else{ - fragsize = (nfrags + 7) & ntohs(IP6F_OFF_MASK); - } - - memcpy(fptr, ptr, fragsize); - fh->ip6f_offlg = (htons(ptr-fragpart) & IP6F_OFF_MASK) | m; - ptr+=fragsize; - fptr+=fragsize; - - fipv6->ip6_plen = htons((fptr - fragbuffer) - MIN_IPV6_HLEN - ETHER_HDR_LEN); - - if((nw=pcap_inject(idata->pfd, fragbuffer, fptr - fragbuffer)) == -1){ - printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); - exit(EXIT_FAILURE); - } - - if(nw != (fptr- fragbuffer)){ - printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw,\ - (LUI) (ptr-buffer)); - exit(EXIT_FAILURE); - } - } - } - }while(linkaddrs>nlinkaddr && newdata_f); - - sources++; - }while(sourcesip6_src), &(idata->srcaddr), idata->srcpreflen); + + if (!idata->hsrcaddr_f) { + randomize_ether_addr(&(ethernet->src)); + + /* + If the source-link layer address must be included, but no value was + specified we set it to the randomized Ethernet Source Address + */ + if (sllopt_f && !sllopta_f) { + memcpy(sllaopt->address, ethernet->src.a, ETH_ALEN); + } + } + } + + if (nlinkaddr == 1) + linkaddrs = 1; + else + linkaddrs = 0; + + do { + newdata_f = 0; + ptr = startofprefixes; + + while (linkaddrs < nlinkaddr && (ptr + sizeof(struct nd_opt_slla) - v6buffer) <= idata->max_packet_size) { + sllaopt = (struct nd_opt_slla *)ptr; + sllaopt->type = ND_OPT_SOURCE_LINKADDR; + sllaopt->length = SLLA_OPT_LEN; + memcpy(sllaopt->address, linkaddr[linkaddrs].a, ETH_ALEN); + ptr += sizeof(struct nd_opt_slla); + linkaddrs++; + newdata_f = 1; + } + + mldq->mld_cksum = 0; + mldq->mld_cksum = in_chksum(v6buffer, mldq, ptr - ((unsigned char *)mldq), IPPROTO_ICMPV6); + + if (!idata->fragh_f) { + ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); + + if ((nw = pcap_inject(idata->pfd, buffer, ptr - buffer)) == -1) { + printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); + exit(EXIT_FAILURE); + } + + if (nw != (ptr - buffer)) { + printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, (LUI)(ptr - buffer)); + exit(EXIT_FAILURE); + } + } + else { + ptrend = ptr; + ptr = fragpart; + fptr = fragbuffer; + fipv6 = (struct ip6_hdr *)(fragbuffer + ETHER_HDR_LEN); + fptrend = fptr + ETHER_HDR_LEN + MIN_IPV6_HLEN + MAX_IPV6_PAYLOAD; + memcpy(fptr, buffer, fragpart - buffer); + fptr = fptr + (fragpart - buffer); + + if ((fptr + FRAG_HDR_SIZE) > fptrend) { + puts("Unfragmentable Part is Too Large"); + exit(EXIT_FAILURE); + } + + memcpy(fptr, (char *)&fraghdr, FRAG_HDR_SIZE); + fh = (struct ip6_frag *)fptr; + fh->ip6f_ident = random(); + startoffragment = fptr + FRAG_HDR_SIZE; + + /* + * Check that the selected fragment size is not larger than the largest fragment + * size that can be sent + */ + + if (nfrags > (fptrend - fptr)) + nfrags = (fptrend - fptr); + + m = IP6F_MORE_FRAG; + + while ((ptr < ptrend) && m == IP6F_MORE_FRAG) { + fptr = startoffragment; + + if ((ptrend - ptr) <= nfrags) { + fragsize = ptrend - ptr; + m = 0; + } + else { + fragsize = (nfrags + 7) & ntohs(IP6F_OFF_MASK); + } + + memcpy(fptr, ptr, fragsize); + fh->ip6f_offlg = (htons(ptr - fragpart) & IP6F_OFF_MASK) | m; + ptr += fragsize; + fptr += fragsize; + + fipv6->ip6_plen = htons((fptr - fragbuffer) - MIN_IPV6_HLEN - ETHER_HDR_LEN); + + if ((nw = pcap_inject(idata->pfd, fragbuffer, fptr - fragbuffer)) == -1) { + printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); + exit(EXIT_FAILURE); + } + + if (nw != (fptr - fragbuffer)) { + printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, (LUI)(ptr - buffer)); + exit(EXIT_FAILURE); + } + } + } + } while (linkaddrs > nlinkaddr && newdata_f); + + sources++; + } while (sources < nsources); } - - /* * Function: usage() * * Print the syntax of the mldq6 tool */ -void usage(void){ +void usage(void) { puts("usage: mldq6 -i INTERFACE [-s SRC_ADDR[/LEN]] [-d DST_ADDR] [-A HOP_LIMIT]" - " [-y FRAG_SIZE] [-u DST_OPT_HDR_SIZE] [-U DST_OPT_U_HDR_SIZE]" - " [-H HBH_OPT_HDR_SIZE] [-S LINK_SRC_ADDR] [-D LINK-DST-ADDR]" - " [-E LINK_ADDR] [-e] [-m MLD_ADDR] [-r MLD_RESP_DELAY ] [-F N_SOURCES]" - " [-z SECONDS] [-l] [-v] [-h]"); + " [-y FRAG_SIZE] [-u DST_OPT_HDR_SIZE] [-U DST_OPT_U_HDR_SIZE]" + " [-H HBH_OPT_HDR_SIZE] [-S LINK_SRC_ADDR] [-D LINK-DST-ADDR]" + " [-E LINK_ADDR] [-e] [-m MLD_ADDR] [-r MLD_RESP_DELAY ] [-F N_SOURCES]" + " [-z SECONDS] [-l] [-v] [-h]"); } - /* * Function: print_help() * * Print help information for the mldq6 tool */ -void print_help(void){ - puts(SI6_TOOLKIT); - puts( "mldq6: Security assessment tool for attack vectors based on MLD Query messages\n"); - usage(); - - puts("\nOPTIONS:\n" - " --interface, -i Network interface\n" - " --src-addr, -s IPv6 Source Address\n" - " --dst-addr, -d IPv6 Destination Address\n" - " --hop-limit, -A IPv6 Hop Limit\n" - " --frag-hdr. -y Fragment Header\n" - " --dst-opt-hdr, -u Destination Options Header (Fragmentable Part)\n" - " --dst-opt-u-hdr, -U Destination Options Header (Unfragmentable Part)\n" - " --hbh-opt-hdr, -H Hop by Hop Options Header\n" - " --link-src-addr, -S Link-layer Destination Address\n" - " --link-dst-addr, -D Link-layer Source Address\n" - " --src-link-opt, -E Source link-layer address option\n" - " --add-slla-opt, -e Add Source link-layer address option\n" - " --mld-addr, -m MLD Query Multicast Address\n" - " --mld-resp-delay, -r MLD Query Maximum Response Delay [ms]\n" - " --flood-sources, -F Number of Source Addresses to forge randomly\n" - " --loop, -l Send MLD Query periodically\n" - " --sleep, -z Pause between peiodic MLD Queries [sec]\n" - " --help, -h Print help for the mldq6 tool\n" - " --verbose, -v Be verbose\n" - "\n" - "Programmed by Fernando Gont for SI6 Networks \n" - "Please send any bug reports to " - ); +void print_help(void) { + puts(SI6_TOOLKIT); + puts("mldq6: Security assessment tool for attack vectors based on MLD Query messages\n"); + usage(); + + puts("\nOPTIONS:\n" + " --interface, -i Network interface\n" + " --src-addr, -s IPv6 Source Address\n" + " --dst-addr, -d IPv6 Destination Address\n" + " --hop-limit, -A IPv6 Hop Limit\n" + " --frag-hdr. -y Fragment Header\n" + " --dst-opt-hdr, -u Destination Options Header (Fragmentable Part)\n" + " --dst-opt-u-hdr, -U Destination Options Header (Unfragmentable Part)\n" + " --hbh-opt-hdr, -H Hop by Hop Options Header\n" + " --link-src-addr, -S Link-layer Destination Address\n" + " --link-dst-addr, -D Link-layer Source Address\n" + " --src-link-opt, -E Source link-layer address option\n" + " --add-slla-opt, -e Add Source link-layer address option\n" + " --mld-addr, -m MLD Query Multicast Address\n" + " --mld-resp-delay, -r MLD Query Maximum Response Delay [ms]\n" + " --flood-sources, -F Number of Source Addresses to forge randomly\n" + " --loop, -l Send MLD Query periodically\n" + " --sleep, -z Pause between peiodic MLD Queries [sec]\n" + " --help, -h Print help for the mldq6 tool\n" + " --verbose, -v Be verbose\n" + "\n" + "Programmed by Fernando Gont for SI6 Networks \n" + "Please send any bug reports to "); } - - /* * Function: print_attack_info() * * Print attack details (when the verbose ("-v") option is specified). */ -void print_attack_info(struct iface_data *idata){ - if(floods_f) - printf("Flooding the target from %u different IPv6 Source Addresses\n", nsources); - - if(!floods_f){ - if(ether_ntop(&(idata->hsrcaddr), plinkaddr, sizeof(plinkaddr)) == 0){ - puts("ether_ntop(): Error converting address"); - exit(EXIT_FAILURE); - } - - printf("Ethernet Source Address: %s%s\n", plinkaddr, ((!idata->hsrcaddr_f)?" (randomized)":"")); - } - else{ - if(idata->hsrcaddr_f){ - if(ether_ntop(&(idata->hsrcaddr), plinkaddr, sizeof(plinkaddr)) == 0){ - puts("ether_ntop(): Error converting address"); - exit(EXIT_FAILURE); - } - - printf("Ethernet Source Address: %s\n", plinkaddr); - } - else - puts("Ethernet Source Address: randomized for each packet"); - } - - if(ether_ntop(&(idata->hdstaddr), phdstaddr, sizeof(phdstaddr)) == 0){ - puts("ether_ntop(): Error converting address"); - exit(EXIT_FAILURE); - } - - printf("Ethernet Destination Address: %s%s\n", phdstaddr, \ - ((!idata->hdstaddr_f)?" (all-nodes multicast)":"")); - - - if(inet_ntop(AF_INET6, &(idata->srcaddr), psrcaddr, sizeof(psrcaddr)) == NULL){ - puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); - exit(EXIT_FAILURE); - } - - if(!floods_f){ - printf("IPv6 Source Address: %s%s\n", psrcaddr, ((!idata->srcaddr_f)?" (randomized)":"")); +void print_attack_info(struct iface_data *idata) { + if (floods_f) + printf("Flooding the target from %u different IPv6 Source Addresses\n", nsources); + + if (!floods_f) { + if (ether_ntop(&(idata->hsrcaddr), plinkaddr, sizeof(plinkaddr)) == 0) { + puts("ether_ntop(): Error converting address"); + exit(EXIT_FAILURE); + } + + printf("Ethernet Source Address: %s%s\n", plinkaddr, ((!idata->hsrcaddr_f) ? " (randomized)" : "")); + } + else { + if (idata->hsrcaddr_f) { + if (ether_ntop(&(idata->hsrcaddr), plinkaddr, sizeof(plinkaddr)) == 0) { + puts("ether_ntop(): Error converting address"); + exit(EXIT_FAILURE); + } + + printf("Ethernet Source Address: %s\n", plinkaddr); + } + else + puts("Ethernet Source Address: randomized for each packet"); + } + + if (ether_ntop(&(idata->hdstaddr), phdstaddr, sizeof(phdstaddr)) == 0) { + puts("ether_ntop(): Error converting address"); + exit(EXIT_FAILURE); + } + + printf("Ethernet Destination Address: %s%s\n", phdstaddr, ((!idata->hdstaddr_f) ? " (all-nodes multicast)" : "")); + + if (inet_ntop(AF_INET6, &(idata->srcaddr), psrcaddr, sizeof(psrcaddr)) == NULL) { + puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); + exit(EXIT_FAILURE); + } + + if (!floods_f) { + printf("IPv6 Source Address: %s%s\n", psrcaddr, ((!idata->srcaddr_f) ? " (randomized)" : "")); } - else{ - printf("IPv6 Source Address: randomized, from the %s/%u prefix%s\n", psrcaddr, idata->srcpreflen, \ - (!idata->srcprefix_f)?" (default)":""); + else { + printf("IPv6 Source Address: randomized, from the %s/%u prefix%s\n", psrcaddr, idata->srcpreflen, + (!idata->srcprefix_f) ? " (default)" : ""); } - if(inet_ntop(AF_INET6, &(idata->dstaddr), pdstaddr, sizeof(pdstaddr)) == NULL){ - perror("inet_ntop()"); - exit(EXIT_FAILURE); - } + if (inet_ntop(AF_INET6, &(idata->dstaddr), pdstaddr, sizeof(pdstaddr)) == NULL) { + perror("inet_ntop()"); + exit(EXIT_FAILURE); + } + + printf("IPv6 Destination Address: %s%s\n", pdstaddr, + ((!idata->dstaddr_f) ? " (all-nodes link-local multicast)" : "")); - printf("IPv6 Destination Address: %s%s\n", pdstaddr, \ - ((!idata->dstaddr_f)?" (all-nodes link-local multicast)":"")); + printf("IPv6 Hop Limit: %u%s\n", hoplimit, (hoplimit_f) ? "" : " (default)"); - printf("IPv6 Hop Limit: %u%s\n", hoplimit, (hoplimit_f)?"":" (default)"); + for (i = 0; i < ndstoptuhdr; i++) + printf("Destination Options Header (Unfragmentable part): %u bytes\n", dstoptuhdrlen[i]); - for(i=0; ifragh_f) + printf("Sending each packet in fragments of %u bytes (plus the Unfragmentable part)\n", nfrags); - if(idata->fragh_f) - printf("Sending each packet in fragments of %u bytes (plus the Unfragmentable part)\n", nfrags); - - for(i=0;i Address: %s\n", \ - ((floods_f && !sllopta_f)?"(randomized for each packet)":plinkaddr)); - } + printf("Source Link-layer Address option -> Address: %s\n", + ((floods_f && !sllopta_f) ? "(randomized for each packet)" : plinkaddr)); + } } diff --git a/tools/mldq6.h b/tools/mldq6.h index 1ae4370..9f99c82 100644 --- a/tools/mldq6.h +++ b/tools/mldq6.h @@ -2,5 +2,3 @@ * Header file for the mldq6 tool * */ - - diff --git a/tools/na6.c b/tools/na6.c index 21427f8..43c95f5 100644 --- a/tools/na6.c +++ b/tools/na6.c @@ -18,1246 +18,1284 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . - * + * * Build with: make na6 - * + * * The libpcap library must be previsously installed on your system. * * Please send any bug reports to Fernando Gont */ -#include #include -#include #include +#include +#include #include -#include +#include +#include #include +#include +#include #include -#include #include -#include -#include -#include #include -#include #include +#include +#include -#include "na6.h" -#include "libipv6.h" #include "ipv6toolkit.h" +#include "libipv6.h" +#include "na6.h" /* Function prototypes */ -void init_packet_data(struct iface_data *); -int send_packet(struct iface_data *, struct pcap_pkthdr *, const u_char *); -void print_attack_info(struct iface_data *); -void usage(void); -void print_help(void); - -struct pcap_pkthdr *pkthdr; -const u_char *pktdata; -struct in6_addr *pkt_ipv6addr; -bpf_u_int32 my_netmask; -bpf_u_int32 my_ip; -struct bpf_program pcap_filter; -char dev[64], errbuf[PCAP_ERRBUF_SIZE]; -char all_nodes_addr[]= ALL_NODES_MULTICAST_ADDR; -unsigned char buffer[65556]; -unsigned char *v6buffer, *ptr, *startofprefixes; - -struct ip6_hdr *ipv6, *pkt_ipv6; -struct nd_neighbor_advert *na; -struct icmp6_hdr *pkt_icmp6; - -struct nd_neighbor_solicit *pkt_ns; -struct ether_header *ethernet, *pkt_ether; -struct nd_opt_tlla *tllaopt; - -struct in6_addr targetaddr; -struct ether_addr linkaddr[MAX_TLLA_OPTION]; -unsigned int nlinkaddr=0, linkaddrs; - -char *lasts, *pref, *rpref, *endptr; -char *charptr; - -int nw; -unsigned long ul_res, ul_val; -unsigned int i, j, startrand; -unsigned int skip; -unsigned int ntargets, sources, nsources, targets, nsleep; -unsigned char targetpreflen; - -uint16_t mask; -uint8_t hoplimit; - -char plinkaddr[ETHER_ADDR_PLEN]; -char psrcaddr[INET6_ADDRSTRLEN], pdstaddr[INET6_ADDRSTRLEN], pv6addr[INET6_ADDRSTRLEN]; -unsigned char floodt_f=0, targetaddr_f=0; -unsigned char listen_f = 0, multicastdst_f=0, accepted_f=0, loop_f=0, sleep_f=0; -unsigned char tllaopt_f=0, tllaopta_f=0, targetprefix_f=0, hoplimit_f=0; -unsigned char newdata_f=0, floods_f=0; -uint32_t router_f=0, solicited_f=0, override_f=0; +void init_packet_data(struct iface_data *); +int send_packet(struct iface_data *, struct pcap_pkthdr *, const u_char *); +void print_attack_info(struct iface_data *); +void usage(void); +void print_help(void); + +struct pcap_pkthdr *pkthdr; +const u_char *pktdata; +struct in6_addr *pkt_ipv6addr; +bpf_u_int32 my_netmask; +bpf_u_int32 my_ip; +struct bpf_program pcap_filter; +char dev[64], errbuf[PCAP_ERRBUF_SIZE]; +char all_nodes_addr[] = ALL_NODES_MULTICAST_ADDR; +unsigned char buffer[65556]; +unsigned char *v6buffer, *ptr, *startofprefixes; + +struct ip6_hdr *ipv6, *pkt_ipv6; +struct nd_neighbor_advert *na; +struct icmp6_hdr *pkt_icmp6; + +struct nd_neighbor_solicit *pkt_ns; +struct ether_header *ethernet, *pkt_ether; +struct nd_opt_tlla *tllaopt; + +struct in6_addr targetaddr; +struct ether_addr linkaddr[MAX_TLLA_OPTION]; +unsigned int nlinkaddr = 0, linkaddrs; + +char *lasts, *pref, *rpref, *endptr; +char *charptr; + +int nw; +unsigned long ul_res, ul_val; +unsigned int i, j, startrand; +unsigned int skip; +unsigned int ntargets, sources, nsources, targets, nsleep; +unsigned char targetpreflen; + +uint16_t mask; +uint8_t hoplimit; + +char plinkaddr[ETHER_ADDR_PLEN]; +char psrcaddr[INET6_ADDRSTRLEN], pdstaddr[INET6_ADDRSTRLEN], pv6addr[INET6_ADDRSTRLEN]; +unsigned char floodt_f = 0, targetaddr_f = 0; +unsigned char listen_f = 0, multicastdst_f = 0, accepted_f = 0, loop_f = 0, sleep_f = 0; +unsigned char tllaopt_f = 0, tllaopta_f = 0, targetprefix_f = 0, hoplimit_f = 0; +unsigned char newdata_f = 0, floods_f = 0; +uint32_t router_f = 0, solicited_f = 0, override_f = 0; /* Support for Extension Headers */ -unsigned int dstopthdrs, dstoptuhdrs, hbhopthdrs; -unsigned char hbhopthdr_f=0, dstoptuhdr_f=0, dstopthdr_f=0; -unsigned char *dstopthdr[MAX_DST_OPT_HDR], *dstoptuhdr[MAX_DST_OPT_U_HDR]; -unsigned char *hbhopthdr[MAX_HBH_OPT_HDR]; -unsigned int dstopthdrlen[MAX_DST_OPT_HDR], dstoptuhdrlen[MAX_DST_OPT_U_HDR]; -unsigned int hbhopthdrlen[MAX_HBH_OPT_HDR], m, pad; - -struct ip6_frag fraghdr, *fh; -struct ip6_hdr *fipv6; -unsigned char fragbuffer[ETHER_HDR_LEN+MIN_IPV6_HLEN+MAX_IPV6_PAYLOAD]; -unsigned char *fragpart, *fptr, *fptrend, *ptrend, *ptrhdr, *ptrhdrend; -unsigned int hdrlen, ndstopthdr=0, nhbhopthdr=0, ndstoptuhdr=0; -unsigned int nfrags, fragsize; -unsigned char *prev_nh, *startoffragment; -struct filters filters; -struct iface_data idata; - -int main(int argc, char **argv){ - extern char *optarg; - int r, sel; - fd_set sset, rset; -#if defined(sun) || defined(__sun) || defined (__linux__) - struct timeval timeout; +unsigned int dstopthdrs, dstoptuhdrs, hbhopthdrs; +unsigned char hbhopthdr_f = 0, dstoptuhdr_f = 0, dstopthdr_f = 0; +unsigned char *dstopthdr[MAX_DST_OPT_HDR], *dstoptuhdr[MAX_DST_OPT_U_HDR]; +unsigned char *hbhopthdr[MAX_HBH_OPT_HDR]; +unsigned int dstopthdrlen[MAX_DST_OPT_HDR], dstoptuhdrlen[MAX_DST_OPT_U_HDR]; +unsigned int hbhopthdrlen[MAX_HBH_OPT_HDR], m, pad; + +struct ip6_frag fraghdr, *fh; +struct ip6_hdr *fipv6; +unsigned char fragbuffer[ETHER_HDR_LEN + MIN_IPV6_HLEN + MAX_IPV6_PAYLOAD]; +unsigned char *fragpart, *fptr, *fptrend, *ptrend, *ptrhdr, *ptrhdrend; +unsigned int hdrlen, ndstopthdr = 0, nhbhopthdr = 0, ndstoptuhdr = 0; +unsigned int nfrags, fragsize; +unsigned char *prev_nh, *startoffragment; +struct filters filters; +struct iface_data idata; + +int main(int argc, char **argv) { + extern char *optarg; + int r, sel; + fd_set sset, rset; +#if defined(sun) || defined(__sun) || defined(__linux__) + struct timeval timeout; #endif - struct target_ipv6 targetipv6; - - static struct option longopts[] = { - {"interface", required_argument, 0, 'i'}, - {"src-addr", required_argument, 0, 's'}, - {"dst-addr", required_argument, 0, 'd'}, - {"hop-limit", required_argument, 0, 'A'}, - {"dst-opt-hdr", required_argument, 0, 'u'}, - {"dst-opt-u-hdr", required_argument, 0, 'U'}, - {"hbh-opt-hdr", required_argument, 0, 'H'}, - {"frag-hdr", required_argument, 0, 'y'}, - {"link-src-addr", required_argument, 0, 'S'}, - {"link-dst-addr", required_argument, 0, 'D'}, - {"target", required_argument, 0, 't'}, - {"router", no_argument, 0, 'r'}, - {"solicited", no_argument, 0, 'c'}, - {"override", no_argument, 0, 'o'}, - {"target-addr-opt", required_argument, 0, 'E'}, - {"add-target-opt", no_argument, 0, 'e'}, - {"block-src-addr", required_argument, 0, 'j'}, - {"block-dst-addr", required_argument, 0, 'k'}, - {"block-link-src-addr", required_argument, 0, 'J'}, - {"block-link-dst-addr", required_argument, 0, 'K'}, - {"block-target-addr", required_argument, 0, 'w'}, - {"accept-src-addr", required_argument, 0, 'b'}, - {"accept-dst-addr", required_argument, 0, 'g'}, - {"accept-link-src-addr", required_argument, 0, 'B'}, - {"accept-link-dst-addr", required_argument, 0, 'G'}, - {"accept-target-addr", required_argument, 0, 'W'}, - {"flood-sources", required_argument, 0, 'F'}, - {"flood-targets", required_argument, 0, 'T'}, - {"loop", no_argument, 0, 'l'}, - {"sleep", required_argument, 0, 'z'}, - {"listen", no_argument, 0, 'L'}, - {"verbose", no_argument, 0, 'v'}, - {"help", no_argument, 0, 'h'}, - {0, 0, 0, 0 } - }; - - const char shortopts[]= "i:s:d:A:u:U:H:y:S:D:t:roceE:j:k:J:K:w:b:g:B:G:W:T:F:lz:vhL"; - - char option; - - if(argc<=1){ - usage(); - exit(EXIT_FAILURE); - } - - hoplimit=255; - - /* Initialize filters structure */ - if(init_filters(&filters) == -1){ - puts("Error initializing internal data structure"); - exit(EXIT_FAILURE); - } - - if(init_iface_data(&idata) == FAILURE){ - puts("Error initializing internal data structure"); - exit(EXIT_FAILURE); - } - - while((r=getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { - option= r; - - switch(option) { - case 'i': /* Interface */ - strncpy(idata.iface, optarg, IFACE_LENGTH); - idata.iface[IFACE_LENGTH-1]=0; - idata.iface_f=TRUE; - break; - - case 's': /* IPv6 Source Address */ - if(idata.srcaddr_f){ - puts("Error: Multiple '-s' options have been specified"); - exit(EXIT_FAILURE); - } - - if((charptr = strtok_r(optarg, "/", &lasts)) == NULL){ - puts("Error in Source Address"); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, charptr, &(idata.srcaddr)) <= 0){ - puts("inet_pton(): Source Address not valid"); - exit(EXIT_FAILURE); - } - - idata.srcaddr_f = 1; - - if((charptr = strtok_r(NULL, " ", &lasts)) != NULL){ - idata.srcpreflen = atoi(charptr); - - if(idata.srcpreflen>128){ - puts("Prefix length error in IPv6 Source Address"); - exit(EXIT_FAILURE); - } - - sanitize_ipv6_prefix(&(idata.srcaddr), idata.srcpreflen); - idata.srcprefix_f=1; - } - - break; - - case 'd': /* IPv6 Destination Address */ - strncpy( targetipv6.name, optarg, NI_MAXHOST); - targetipv6.name[NI_MAXHOST-1]= 0; - targetipv6.flags= AI_CANONNAME; - - if( (r=get_ipv6_target(&targetipv6)) != 0){ - - if(r < 0){ - printf("Unknown Destination: %s\n", gai_strerror(targetipv6.res)); - } - else{ - puts("Unknown Destination: No IPv6 address found for specified destination"); - } - - exit(EXIT_FAILURE); - } - - idata.dstaddr= targetipv6.ip6; - idata.dstaddr_f = 1; - break; - - case 'A': /* Hop Limit */ - hoplimit= atoi(optarg); - hoplimit_f=1; - break; - - case 'y': /* Fragment header */ - nfrags= atoi(optarg); - if(nfrags < 8){ - puts("Error in Fragmentation option: Fragment Size must be at least 8 bytes"); - exit(EXIT_FAILURE); - } - - idata.fragh_f= 1; - break; - - case 'u': /* Destinations Options Header */ - if(ndstopthdr >= MAX_DST_OPT_HDR){ - puts("Too many Destination Options Headers"); - exit(EXIT_FAILURE); - } - - hdrlen= atoi(optarg); - - if(hdrlen < 8){ - puts("Bad length in Destination Options Header"); - exit(EXIT_FAILURE); - } - - hdrlen = ((hdrlen+7)/8) * 8; - dstopthdrlen[ndstopthdr]= hdrlen; - - if( (dstopthdr[ndstopthdr]= malloc(hdrlen)) == NULL){ - puts("Not enough memory for Destination Options Header"); - exit(EXIT_FAILURE); - } - - ptrhdr= dstopthdr[ndstopthdr] + 2; - ptrhdrend= dstopthdr[ndstopthdr] + hdrlen; - - while( ptrhdr < ptrhdrend){ - - if( (ptrhdrend-ptrhdr)>257) - pad= 257; - else - pad= ptrhdrend-ptrhdr; - - if(!insert_pad_opt(ptrhdr, ptrhdrend, pad)){ - puts("Destination Options Header Too Big"); - exit(EXIT_FAILURE); - } - - ptrhdr= ptrhdr + pad; - } - - *(dstopthdr[ndstopthdr]+1)= (hdrlen/8)-1; - ndstopthdr++; - dstopthdr_f=1; - break; - - case 'U': /* Destination Options Header (Unfragmentable Part) */ - if(ndstoptuhdr >= MAX_DST_OPT_U_HDR){ - puts("Too many Destination Options Headers (Unfragmentable Part)"); - exit(EXIT_FAILURE); - } - - hdrlen= atoi(optarg); - - if(hdrlen < 8){ - puts("Bad length in Destination Options Header (Unfragmentable Part)"); - exit(EXIT_FAILURE); - } - - hdrlen = ((hdrlen+7)/8) * 8; - dstoptuhdrlen[ndstoptuhdr]= hdrlen; - - if( (dstoptuhdr[ndstoptuhdr]= malloc(hdrlen)) == NULL){ - puts("Not enough memory for Destination Options Header (Unfragmentable Part)"); - exit(EXIT_FAILURE); - } - - ptrhdr= dstoptuhdr[ndstoptuhdr]+2; - ptrhdrend= dstoptuhdr[ndstoptuhdr] + hdrlen; - - while( ptrhdr < ptrhdrend){ - - if( (ptrhdrend-ptrhdr)>257) - pad= 257; - else - pad= ptrhdrend-ptrhdr; - - if(!insert_pad_opt(ptrhdr, ptrhdrend, pad)){ - puts("Destination Options Header (Unfragmentable Part) Too Big"); - exit(EXIT_FAILURE); - } - - ptrhdr = ptrhdr + pad; - } - - *(dstoptuhdr[ndstoptuhdr]+1)= (hdrlen/8) - 1; - ndstoptuhdr++; - dstoptuhdr_f=1; - break; - - case 'H': /* Hop-by-Hop Options Header */ - if(nhbhopthdr >= MAX_HBH_OPT_HDR){ - puts("Too many Hop-by-Hop Options Headers"); - exit(EXIT_FAILURE); - } - - hdrlen= atoi(optarg); - - if(hdrlen < 8){ - puts("Bad length in Hop-by-Hop Options Header"); - exit(EXIT_FAILURE); - } - - hdrlen = ((hdrlen+7)/8) * 8; - hbhopthdrlen[nhbhopthdr]= hdrlen; - - if( (hbhopthdr[nhbhopthdr]= malloc(hdrlen)) == NULL){ - puts("Not enough memory for Hop-by-Hop Options Header"); - exit(EXIT_FAILURE); - } - - ptrhdr= hbhopthdr[nhbhopthdr] + 2; - ptrhdrend= hbhopthdr[nhbhopthdr] + hdrlen; - - while( ptrhdr < ptrhdrend){ - - if( (ptrhdrend-ptrhdr)>257) - pad= 257; - else - pad= ptrhdrend-ptrhdr; - - if(!insert_pad_opt(ptrhdr, ptrhdrend, pad)){ - puts("Hop-by-Hop Options Header Too Big"); - exit(EXIT_FAILURE); - } - - ptrhdr = ptrhdr + pad; - } - - *(hbhopthdr[nhbhopthdr]+1)= (hdrlen/8) - 1; - nhbhopthdr++; - hbhopthdr_f=1; - break; - - case 'S': /* Source Ethernet address */ - if(ether_pton(optarg, &(idata.hsrcaddr), sizeof(idata.hsrcaddr)) == 0){ - puts("Error in Source link-layer address."); - exit(EXIT_FAILURE); - } - - idata.hsrcaddr_f = 1; - break; - - case 'D': /* Destination Ethernet Address */ - if(ether_pton(optarg, &(idata.hdstaddr), sizeof(idata.hdstaddr)) == 0){ - puts("Error in Source link-layer address."); - exit(EXIT_FAILURE); - } - - idata.hdstaddr_f = 1; - break; - - case 't': /* NA Target address */ - if((charptr = strtok_r(optarg, "/", &lasts)) == NULL){ - puts("Target Address not valid"); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, charptr, &targetaddr) <= 0){ - puts("inet_pton(): Target Address not valid"); - exit(EXIT_FAILURE); - } - - targetaddr_f = 1; - - if((charptr = strtok_r(NULL, " ", &lasts)) != NULL){ - targetpreflen = atoi(charptr); - - if(targetpreflen>128){ - puts("Prefix length error in Target Address"); - exit(EXIT_FAILURE); - } - - sanitize_ipv6_prefix(&targetaddr, targetpreflen); - targetprefix_f=1; - } - - break; - - case 'r': /* "Router" flag */ - router_f = ND_NA_FLAG_ROUTER; - break; - - case 'o': /* "Override" flag */ - override_f = ND_NA_FLAG_OVERRIDE; - break; - - case 'c': /* Solicited flag */ - solicited_f = ND_NA_FLAG_SOLICITED; - break; - - case 'E': /* Target link-layer option */ - tllaopt_f = 1; - if(ether_pton(optarg, &linkaddr[nlinkaddr], sizeof(struct ether_addr)) == 0){ - puts("Error in Source link-layer address option."); - exit(EXIT_FAILURE); - } - - nlinkaddr++; - tllaopta_f=1; - break; - - case 'e': /* Add target link-layer option */ - tllaopt_f = 1; - break; - - case 'j': /* IPv6 Source Address (block) filter */ - if(filters.nblocksrc >= MAX_BLOCK_SRC){ - puts("Too many IPv6 Source Address (block) filters."); - exit(EXIT_FAILURE); - } - - if((pref = strtok_r(optarg, "/", &lasts)) == NULL){ - printf("Error in IPv6 Source Address (block) filter number %u.\n", \ - filters.nblocksrc+1); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, pref, &(filters.blocksrc[filters.nblocksrc])) <= 0){ - printf("Error in IPv6 Source Address (block) filter number %u.", \ - filters.nblocksrc+1); - exit(EXIT_FAILURE); - } - - if((charptr = strtok_r(NULL, " ", &lasts)) == NULL){ - filters.blocksrclen[filters.nblocksrc] = 128; - } - else{ - filters.blocksrclen[filters.nblocksrc] = atoi(charptr); - - if(filters.blocksrclen[filters.nblocksrc]>128){ - printf("Length error in IPv6 Source Address (block) filter number %u.\n", \ - filters.nblocksrc+1); - exit(EXIT_FAILURE); - } - } - - sanitize_ipv6_prefix(&(filters.blocksrc[filters.nblocksrc]), filters.blocksrclen[filters.nblocksrc]); - (filters.nblocksrc)++; - break; - - case 'k': /* IPv6 Destination Address (block) filter */ - if(filters.nblockdst >= MAX_BLOCK_DST){ - puts("Too many IPv6 Destination Address (block) filters."); - exit(EXIT_FAILURE); - } - - if((pref = strtok_r(optarg, "/", &lasts)) == NULL){ - printf("Error in IPv6 Destination Address (block) filter number %u.\n", \ - filters.nblockdst+1); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, pref, &(filters.blockdst[filters.nblockdst])) <= 0){ - printf("Error in IPv6 Source Address (block) filter number %u.", \ - filters.nblockdst+1); - exit(EXIT_FAILURE); - } - - if((charptr = strtok_r(NULL, " ", &lasts)) == NULL){ - filters.blockdstlen[filters.nblockdst] = 128; - } - else{ - filters.blockdstlen[filters.nblockdst] = atoi(charptr); - - if(filters.blockdstlen[filters.nblockdst]>128){ - printf("Length error in IPv6 Source Address (block) filter number %u.\n", \ - filters.nblockdst+1); - exit(EXIT_FAILURE); - } - } - - sanitize_ipv6_prefix(&(filters.blockdst[filters.nblockdst]), filters.blockdstlen[filters.nblockdst]); - (filters.nblockdst)++; - break; - - case 'J': /* Link Source Address (block) filter */ - if(filters.nblocklinksrc > MAX_BLOCK_LINK_SRC){ - puts("Too many link-layer Source Address (accept) filters."); - exit(EXIT_FAILURE); - } - - if(ether_pton(optarg, &(filters.blocklinksrc[filters.nblocklinksrc]), sizeof(struct ether_addr)) == 0){ - printf("Error in link-layer Source Address (blick) filter number %u.\n", \ - filters.nblocklinksrc+1); - exit(EXIT_FAILURE); - } - - (filters.nblocklinksrc)++; - break; - - case 'K': /* Link Destination Address (block) filter */ - if(filters.nblocklinkdst > MAX_BLOCK_LINK_DST){ - puts("Too many link-layer Destination Address (block) filters."); - exit(EXIT_FAILURE); - } - - if(ether_pton(optarg, &(filters.blocklinkdst[filters.nblocklinkdst]), sizeof(struct ether_addr)) == 0){ - printf("Error in link-layer Destination Address (blick) filter number %u.\n", \ - filters.nblocklinkdst+1); - exit(EXIT_FAILURE); - } - - filters.nblocklinkdst++; - break; - - case 'b': /* IPv6 Source Address (accept) filter */ - if(filters.nacceptsrc > MAX_ACCEPT_SRC){ - puts("Too many IPv6 Source Address (accept) filters."); - exit(EXIT_FAILURE); - } - - if((pref = strtok_r(optarg, "/", &lasts)) == NULL){ - printf("Error in IPv6 Source Address (accept) filter number %u.\n", \ - filters.nacceptsrc+1); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, pref, &(filters.acceptsrc[filters.nacceptsrc])) <= 0){ - printf("Error in IPv6 Source Address (accept) filter number %u.\n", \ - filters.nacceptsrc+1); - exit(EXIT_FAILURE); - } - - if((charptr = strtok_r(NULL, " ", &lasts)) == NULL){ - filters.acceptsrclen[filters.nacceptsrc] = 128; - } - else{ - filters.acceptsrclen[filters.nacceptsrc] = atoi(charptr); - - if(filters.acceptsrclen[filters.nacceptsrc]>128){ - printf("Length error in IPv6 Source Address (accept) filter number %u.\n", \ - filters.nacceptsrc+1); - exit(EXIT_FAILURE); - } - } - - sanitize_ipv6_prefix(&(filters.acceptsrc[filters.nacceptsrc]), filters.acceptsrclen[filters.nacceptsrc]); - (filters.nacceptsrc)++; - filters.acceptfilters_f=1; - break; - - - case 'g': /* IPv6 Destination Address (accept) filter */ - if(filters.nacceptdst > MAX_ACCEPT_DST){ - puts("Too many IPv6 Destination Address (accept) filters."); - exit(EXIT_FAILURE); - } - - if((pref = strtok_r(optarg, "/", &lasts)) == NULL){ - printf("Error in IPv6 Destination Address (accept) filter number %u.\n", \ - filters.nacceptdst+1); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, pref, &(filters.acceptdst[filters.nacceptdst])) <= 0){ - printf("Error in IPv6 Source Address (accept) filter number %u.\n", \ - filters.nacceptdst+1); - exit(EXIT_FAILURE); - } - - if((charptr = strtok_r(NULL, " ", &lasts)) == NULL){ - filters.acceptdstlen[filters.nacceptdst] = 128; - } - else{ - filters.acceptdstlen[filters.nacceptdst] = atoi(charptr); - - if(filters.acceptdstlen[filters.nacceptdst] > 128){ - printf("Length error in IPv6 Source Address (accept) filter number %u.\n", \ - filters.nacceptdst+1); - exit(EXIT_FAILURE); - } - } - - sanitize_ipv6_prefix(&(filters.acceptdst[filters.nacceptdst]), filters.acceptdstlen[filters.nacceptdst]); - (filters.nacceptdst)++; - filters.acceptfilters_f=1; - break; - - case 'B': /* Link-layer Source Address (accept) filter */ - if(filters.nacceptlinksrc > MAX_ACCEPT_LINK_SRC){ - puts("Too many link-later Source Address (accept) filters."); - exit(EXIT_FAILURE); - } - - if(ether_pton(optarg, &(filters.acceptlinksrc[filters.nacceptlinksrc]), sizeof(struct ether_addr)) == 0){ - printf("Error in link-layer Source Address (accept) filter number %u.\n", \ - filters.nacceptlinksrc+1); - exit(EXIT_FAILURE); - } - - (filters.nacceptlinksrc)++; - filters.acceptfilters_f=1; - break; - - case 'G': /* Link Destination Address (accept) filter */ - if(filters.nacceptlinkdst > MAX_ACCEPT_LINK_DST){ - puts("Too many link-layer Destination Address (accept) filters."); - exit(EXIT_FAILURE); - } - - if(ether_pton(optarg, &(filters.acceptlinkdst[filters.nacceptlinkdst]), sizeof(struct ether_addr)) == 0){ - printf("Error in link-layer Destination Address (accept) filter number %u.\n",\ - filters.nacceptlinkdst+1); - exit(EXIT_FAILURE); - } - - (filters.nacceptlinkdst)++; - filters.acceptfilters_f=1; - break; - - case 'w': /* ND Target Address (block) filter */ - if(filters.nblocktarget > MAX_BLOCK_TARGET){ - puts("Too many Target Address (block) filters."); - exit(EXIT_FAILURE); - } - - if((pref = strtok_r(optarg, "/", &lasts)) == NULL){ - printf("Error in Target Address (block) filter number %u.\n", filters.nblocktarget+1); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, pref, &(filters.blocktarget[filters.nblocktarget])) <= 0){ - printf("Error in Target Address (block) filter number %u.\n", filters.nblocktarget+1); - exit(EXIT_FAILURE); - } - - if((charptr = strtok_r(NULL, " ", &lasts)) == NULL){ - filters.blocktargetlen[filters.nblocktarget] = 128; - } - else{ - filters.blocktargetlen[filters.nblocktarget] = atoi(charptr); - - if(filters.blocktargetlen[filters.nblocktarget]>128){ - printf("Length error in Target Address (block) filter number %u.\n", filters.nblocktarget+1); - exit(EXIT_FAILURE); - } - } - - sanitize_ipv6_prefix(&(filters.blocktarget[filters.nblocktarget]), filters.blocktargetlen[filters.nblocktarget]); - filters.nblocktarget++; - break; - - case 'W': /* ND Target Address (accept) filter */ - if(filters.naccepttarget >= MAX_ACCEPT_TARGET){ - puts("Too many Target Address (accept) filters."); - exit(EXIT_FAILURE); - } - - if((pref = strtok_r(optarg, "/", &lasts)) == NULL){ - printf("Error in Target Address (accept) filter number %u.\n", filters.naccepttarget+1); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, pref, &(filters.accepttarget[filters.naccepttarget])) <= 0){ - printf("Error in Target Address (accept) filter number %u.\n", filters.naccepttarget+1); - exit(EXIT_FAILURE); - } - - if((charptr = strtok_r(NULL, " ", &lasts)) == NULL){ - filters.accepttargetlen[filters.naccepttarget] = 128; - } - else{ - filters.accepttargetlen[filters.naccepttarget] = atoi(charptr); - - if(filters.accepttargetlen[filters.naccepttarget]>128){ - printf("Length error in Target Address (accept) filter number %u.\n", \ - filters.naccepttarget+1); - exit(EXIT_FAILURE); - } - } - - sanitize_ipv6_prefix(&(filters.accepttarget[filters.naccepttarget]), filters.accepttargetlen[filters.naccepttarget]); - filters.naccepttarget++; - filters.acceptfilters_f=1; - break; - - case 'L': /* "Listen mode */ - listen_f = 1; - break; - - case 'T': /* Flood targets */ - ntargets= atoi(optarg); - if(ntargets == 0){ - puts("Invalid number of Target Addresses in option -T"); - exit(EXIT_FAILURE); - } - - floodt_f= 1; - break; - - case 'F': /* Flood sources */ - nsources= atoi(optarg); - if(nsources == 0){ - puts("Invalid number of sources in option -F"); - exit(EXIT_FAILURE); - } - - floods_f= 1; - break; - - case 'l': /* "Loop mode */ - loop_f = 1; - break; - - case 'z': /* Sleep option */ - nsleep=atoi(optarg); - if(nsleep==0){ - puts("Invalid number of seconds in '-z' option"); - exit(EXIT_FAILURE); - } - - sleep_f=1; - break; - - case 'v': /* Be verbose */ - idata.verbose_f++; - break; - - case 'h': /* Help */ - print_help(); - exit(EXIT_FAILURE); - break; - - default: - usage(); - exit(EXIT_FAILURE); - break; - } /* switch */ - } /* while(getopt) */ - - if(geteuid()) { - puts("na6 needs root privileges to run."); - exit(EXIT_FAILURE); - } - - if(!idata.iface_f){ - puts("Must specify the network interface with the -i option"); - exit(EXIT_FAILURE); - } - - if(load_dst_and_pcap(&idata, LOAD_PCAP_ONLY) == FAILURE){ - puts("Error while learning Source Address and Next Hop"); - exit(EXIT_FAILURE); - } - - release_privileges(); - - if(listen_f && loop_f){ - puts("'Error: listen' mode and 'loop' mode are incompatible"); - exit(EXIT_FAILURE); - } - - if(listen_f && floodt_f){ - puts("Error: 'listen' mode and 'flood targets' are incompatible"); - exit(EXIT_FAILURE); - } - - if(pcap_compile(idata.pfd, &pcap_filter, PCAP_ICMPV6_NS_FILTER, 0, PCAP_NETMASK_UNKNOWN) == -1){ - printf("pcap_compile(): %s", pcap_geterr(idata.pfd)); - exit(EXIT_FAILURE); - } - - - if(pcap_setfilter(idata.pfd, &pcap_filter) == -1){ - printf("pcap_setfilter(): %s", pcap_geterr(idata.pfd)); - exit(EXIT_FAILURE); - } - - pcap_freecode(&pcap_filter); - - srandom(time(NULL)); - - if(!(idata.srcaddr_f) && !floods_f){ - /* When randomizing a link-local IPv6 address, select addresses that belong to the - prefix fe80::/64 (that's what a link-local address looks-like in legitimate cases). - The KAME implementation discards addresses in which the second high-order 16 bits - (srcaddr.s6_addr16[1] in our case) are not zero. - */ - - if(idata.ip6_local_flag){ - idata.srcaddr= idata.ip6_local; - } - else{ - if ( inet_pton(AF_INET6, "fe80::", &(idata.srcaddr)) <= 0){ - puts("inet_pton(): Error when converting address"); - exit(EXIT_FAILURE); - } - - randomize_ipv6_addr(&(idata.srcaddr), &(idata.srcaddr), 64); - } - } - - /* - If the flood option ("-F") has been specified, but no prefix has been specified, - select the random Source Addresses from the link-local unicast prefix (fe80::/64). - */ - if(floods_f && !idata.srcprefix_f){ - if ( inet_pton(AF_INET6, "fe80::", &(idata.srcaddr)) <= 0){ - puts("inet_pton(): Error when converting address"); - exit(EXIT_FAILURE); - } - - randomize_ipv6_addr(&(idata.srcaddr), &(idata.srcaddr), 64); - - idata.srcpreflen=64; - } - - if(!idata.dstaddr_f){ /* Destination Address defaults to all-nodes (ff02::1) */ - if( inet_pton(AF_INET6, ALL_NODES_MULTICAST_ADDR, &(idata.dstaddr)) <= 0){ - puts("inet_pton(): Error converting all-nodes multicast address"); - exit(EXIT_FAILURE); - } - } - - if(!idata.hdstaddr_f) /* Destination link-layer address defaults to all-nodes */ - if(ether_pton(ETHER_ALLNODES_LINK_ADDR, &(idata.hdstaddr), sizeof(idata.hdstaddr)) == 0){ - puts("ether_pton(): Error converting all-nodes multicast address"); - exit(EXIT_FAILURE); - } - - if(tllaopt_f && !tllaopta_f){ /* The value of the target link-layer address */ - linkaddr[0] = idata.hsrcaddr; /* option defaults to the Ethernet Source Address */ - nlinkaddr++; - } - - - /* - If the flood target option ("-T") was specified, but no prefix was specified, - select the random Target Addresses from the link-local unicast prefix (fe80::/64). - */ - if(floodt_f && !targetprefix_f){ - if ( inet_pton(AF_INET6, "fe80::", &targetaddr) <= 0){ - puts("inet_pton(): Error when converting address"); - exit(EXIT_FAILURE); - } - - randomize_ipv6_addr(&targetaddr, &targetaddr, 64); - targetpreflen=64; - } - - if(!floods_f) - nsources=1; - - if(!floodt_f) - ntargets=1; - - if(!sleep_f) - nsleep=1; - - if(!idata.fragh_f && dstoptuhdr_f){ - puts("Dst. Options Header (Unfragmentable Part) set, but Fragmentation not specified"); - exit(EXIT_FAILURE); - } - - if(idata.verbose_f){ - print_attack_info(&idata); - } - - /* Set initial contents of the attack packet */ - init_packet_data(&idata); - - /* Fire a Neighbor Advertisement if a IPv6 Destination Address or an Ethernet - * Destination Address were specified - */ - if((idata.dstaddr_f || idata.hdstaddr_f) && (targetaddr_f || floodt_f)){ - if(send_packet(&idata, NULL, NULL) == FAILURE){ - puts("Error while sending packet"); - exit(EXIT_FAILURE); - } - - if(idata.verbose_f) - puts("Initial attack packet(s) sent successfully."); - - if(loop_f){ - if(idata.verbose_f) - printf("Now sending Neighbor Advertisements every %u second%s...\n", nsleep, \ - ((nsleep>1)?"s":"")); - while(loop_f){ - sleep(nsleep); - if(send_packet(&idata, NULL, NULL) == FAILURE){ - puts("Error while sending packet"); - exit(EXIT_FAILURE); - } - } - - exit(EXIT_SUCCESS); - } - } - - if(listen_f){ - FD_ZERO(&sset); - FD_SET(idata.fd, &sset); - - if(idata.verbose_f){ - print_filters(&idata, &filters); - puts("Listening to incoming ICMPv6 Neighbor Solicitation messages..."); - } - - while(listen_f){ - rset= sset; + struct target_ipv6 targetipv6; + + static struct option longopts[] = {{"interface", required_argument, 0, 'i'}, + {"src-addr", required_argument, 0, 's'}, + {"dst-addr", required_argument, 0, 'd'}, + {"hop-limit", required_argument, 0, 'A'}, + {"dst-opt-hdr", required_argument, 0, 'u'}, + {"dst-opt-u-hdr", required_argument, 0, 'U'}, + {"hbh-opt-hdr", required_argument, 0, 'H'}, + {"frag-hdr", required_argument, 0, 'y'}, + {"link-src-addr", required_argument, 0, 'S'}, + {"link-dst-addr", required_argument, 0, 'D'}, + {"target", required_argument, 0, 't'}, + {"router", no_argument, 0, 'r'}, + {"solicited", no_argument, 0, 'c'}, + {"override", no_argument, 0, 'o'}, + {"target-addr-opt", required_argument, 0, 'E'}, + {"add-target-opt", no_argument, 0, 'e'}, + {"block-src-addr", required_argument, 0, 'j'}, + {"block-dst-addr", required_argument, 0, 'k'}, + {"block-link-src-addr", required_argument, 0, 'J'}, + {"block-link-dst-addr", required_argument, 0, 'K'}, + {"block-target-addr", required_argument, 0, 'w'}, + {"accept-src-addr", required_argument, 0, 'b'}, + {"accept-dst-addr", required_argument, 0, 'g'}, + {"accept-link-src-addr", required_argument, 0, 'B'}, + {"accept-link-dst-addr", required_argument, 0, 'G'}, + {"accept-target-addr", required_argument, 0, 'W'}, + {"flood-sources", required_argument, 0, 'F'}, + {"flood-targets", required_argument, 0, 'T'}, + {"loop", no_argument, 0, 'l'}, + {"sleep", required_argument, 0, 'z'}, + {"listen", no_argument, 0, 'L'}, + {"verbose", no_argument, 0, 'v'}, + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0}}; + + const char shortopts[] = "i:s:d:A:u:U:H:y:S:D:t:roceE:j:k:J:K:w:b:g:B:G:W:T:F:lz:vhL"; + + char option; + + if (argc <= 1) { + usage(); + exit(EXIT_FAILURE); + } + + hoplimit = 255; + + /* Initialize filters structure */ + if (init_filters(&filters) == -1) { + puts("Error initializing internal data structure"); + exit(EXIT_FAILURE); + } + + if (init_iface_data(&idata) == FAILURE) { + puts("Error initializing internal data structure"); + exit(EXIT_FAILURE); + } + + while ((r = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { + option = r; + + switch (option) { + case 'i': /* Interface */ + strncpy(idata.iface, optarg, IFACE_LENGTH); + idata.iface[IFACE_LENGTH - 1] = 0; + idata.iface_f = TRUE; + break; + + case 's': /* IPv6 Source Address */ + if (idata.srcaddr_f) { + puts("Error: Multiple '-s' options have been specified"); + exit(EXIT_FAILURE); + } + + if ((charptr = strtok_r(optarg, "/", &lasts)) == NULL) { + puts("Error in Source Address"); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, charptr, &(idata.srcaddr)) <= 0) { + puts("inet_pton(): Source Address not valid"); + exit(EXIT_FAILURE); + } + + idata.srcaddr_f = 1; + + if ((charptr = strtok_r(NULL, " ", &lasts)) != NULL) { + idata.srcpreflen = atoi(charptr); + + if (idata.srcpreflen > 128) { + puts("Prefix length error in IPv6 Source Address"); + exit(EXIT_FAILURE); + } + + sanitize_ipv6_prefix(&(idata.srcaddr), idata.srcpreflen); + idata.srcprefix_f = 1; + } + + break; + + case 'd': /* IPv6 Destination Address */ + strncpy(targetipv6.name, optarg, NI_MAXHOST); + targetipv6.name[NI_MAXHOST - 1] = 0; + targetipv6.flags = AI_CANONNAME; + + if ((r = get_ipv6_target(&targetipv6)) != 0) { + + if (r < 0) { + printf("Unknown Destination: %s\n", gai_strerror(targetipv6.res)); + } + else { + puts("Unknown Destination: No IPv6 address found for " + "specified " + "destination"); + } + + exit(EXIT_FAILURE); + } + + idata.dstaddr = targetipv6.ip6; + idata.dstaddr_f = 1; + break; + + case 'A': /* Hop Limit */ + hoplimit = atoi(optarg); + hoplimit_f = 1; + break; + + case 'y': /* Fragment header */ + nfrags = atoi(optarg); + if (nfrags < 8) { + puts("Error in Fragmentation option: Fragment Size must be at " + "least 8 " + "bytes"); + exit(EXIT_FAILURE); + } + + idata.fragh_f = 1; + break; + + case 'u': /* Destinations Options Header */ + if (ndstopthdr >= MAX_DST_OPT_HDR) { + puts("Too many Destination Options Headers"); + exit(EXIT_FAILURE); + } + + hdrlen = atoi(optarg); + + if (hdrlen < 8) { + puts("Bad length in Destination Options Header"); + exit(EXIT_FAILURE); + } + + hdrlen = ((hdrlen + 7) / 8) * 8; + dstopthdrlen[ndstopthdr] = hdrlen; + + if ((dstopthdr[ndstopthdr] = malloc(hdrlen)) == NULL) { + puts("Not enough memory for Destination Options Header"); + exit(EXIT_FAILURE); + } + + ptrhdr = dstopthdr[ndstopthdr] + 2; + ptrhdrend = dstopthdr[ndstopthdr] + hdrlen; + + while (ptrhdr < ptrhdrend) { + + if ((ptrhdrend - ptrhdr) > 257) + pad = 257; + else + pad = ptrhdrend - ptrhdr; + + if (!insert_pad_opt(ptrhdr, ptrhdrend, pad)) { + puts("Destination Options Header Too Big"); + exit(EXIT_FAILURE); + } + + ptrhdr = ptrhdr + pad; + } + + *(dstopthdr[ndstopthdr] + 1) = (hdrlen / 8) - 1; + ndstopthdr++; + dstopthdr_f = 1; + break; + + case 'U': /* Destination Options Header (Unfragmentable Part) */ + if (ndstoptuhdr >= MAX_DST_OPT_U_HDR) { + puts("Too many Destination Options Headers (Unfragmentable " + "Part)"); + exit(EXIT_FAILURE); + } + + hdrlen = atoi(optarg); + + if (hdrlen < 8) { + puts("Bad length in Destination Options Header (Unfragmentable " + "Part)"); + exit(EXIT_FAILURE); + } + + hdrlen = ((hdrlen + 7) / 8) * 8; + dstoptuhdrlen[ndstoptuhdr] = hdrlen; + + if ((dstoptuhdr[ndstoptuhdr] = malloc(hdrlen)) == NULL) { + puts("Not enough memory for Destination Options Header " + "(Unfragmentable " + "Part)"); + exit(EXIT_FAILURE); + } + + ptrhdr = dstoptuhdr[ndstoptuhdr] + 2; + ptrhdrend = dstoptuhdr[ndstoptuhdr] + hdrlen; + + while (ptrhdr < ptrhdrend) { + + if ((ptrhdrend - ptrhdr) > 257) + pad = 257; + else + pad = ptrhdrend - ptrhdr; + + if (!insert_pad_opt(ptrhdr, ptrhdrend, pad)) { + puts("Destination Options Header (Unfragmentable Part) Too " + "Big"); + exit(EXIT_FAILURE); + } + + ptrhdr = ptrhdr + pad; + } + + *(dstoptuhdr[ndstoptuhdr] + 1) = (hdrlen / 8) - 1; + ndstoptuhdr++; + dstoptuhdr_f = 1; + break; + + case 'H': /* Hop-by-Hop Options Header */ + if (nhbhopthdr >= MAX_HBH_OPT_HDR) { + puts("Too many Hop-by-Hop Options Headers"); + exit(EXIT_FAILURE); + } + + hdrlen = atoi(optarg); + + if (hdrlen < 8) { + puts("Bad length in Hop-by-Hop Options Header"); + exit(EXIT_FAILURE); + } + + hdrlen = ((hdrlen + 7) / 8) * 8; + hbhopthdrlen[nhbhopthdr] = hdrlen; + + if ((hbhopthdr[nhbhopthdr] = malloc(hdrlen)) == NULL) { + puts("Not enough memory for Hop-by-Hop Options Header"); + exit(EXIT_FAILURE); + } + + ptrhdr = hbhopthdr[nhbhopthdr] + 2; + ptrhdrend = hbhopthdr[nhbhopthdr] + hdrlen; + + while (ptrhdr < ptrhdrend) { + + if ((ptrhdrend - ptrhdr) > 257) + pad = 257; + else + pad = ptrhdrend - ptrhdr; + + if (!insert_pad_opt(ptrhdr, ptrhdrend, pad)) { + puts("Hop-by-Hop Options Header Too Big"); + exit(EXIT_FAILURE); + } + + ptrhdr = ptrhdr + pad; + } + + *(hbhopthdr[nhbhopthdr] + 1) = (hdrlen / 8) - 1; + nhbhopthdr++; + hbhopthdr_f = 1; + break; + + case 'S': /* Source Ethernet address */ + if (ether_pton(optarg, &(idata.hsrcaddr), sizeof(idata.hsrcaddr)) == 0) { + puts("Error in Source link-layer address."); + exit(EXIT_FAILURE); + } + + idata.hsrcaddr_f = 1; + break; + + case 'D': /* Destination Ethernet Address */ + if (ether_pton(optarg, &(idata.hdstaddr), sizeof(idata.hdstaddr)) == 0) { + puts("Error in Source link-layer address."); + exit(EXIT_FAILURE); + } + + idata.hdstaddr_f = 1; + break; + + case 't': /* NA Target address */ + if ((charptr = strtok_r(optarg, "/", &lasts)) == NULL) { + puts("Target Address not valid"); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, charptr, &targetaddr) <= 0) { + puts("inet_pton(): Target Address not valid"); + exit(EXIT_FAILURE); + } + + targetaddr_f = 1; + + if ((charptr = strtok_r(NULL, " ", &lasts)) != NULL) { + targetpreflen = atoi(charptr); + + if (targetpreflen > 128) { + puts("Prefix length error in Target Address"); + exit(EXIT_FAILURE); + } + + sanitize_ipv6_prefix(&targetaddr, targetpreflen); + targetprefix_f = 1; + } + + break; + + case 'r': /* "Router" flag */ + router_f = ND_NA_FLAG_ROUTER; + break; + + case 'o': /* "Override" flag */ + override_f = ND_NA_FLAG_OVERRIDE; + break; + + case 'c': /* Solicited flag */ + solicited_f = ND_NA_FLAG_SOLICITED; + break; + + case 'E': /* Target link-layer option */ + tllaopt_f = 1; + if (ether_pton(optarg, &linkaddr[nlinkaddr], sizeof(struct ether_addr)) == 0) { + puts("Error in Source link-layer address option."); + exit(EXIT_FAILURE); + } + + nlinkaddr++; + tllaopta_f = 1; + break; + + case 'e': /* Add target link-layer option */ + tllaopt_f = 1; + break; + + case 'j': /* IPv6 Source Address (block) filter */ + if (filters.nblocksrc >= MAX_BLOCK_SRC) { + puts("Too many IPv6 Source Address (block) filters."); + exit(EXIT_FAILURE); + } + + if ((pref = strtok_r(optarg, "/", &lasts)) == NULL) { + printf("Error in IPv6 Source Address (block) filter number %u.\n", filters.nblocksrc + 1); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, pref, &(filters.blocksrc[filters.nblocksrc])) <= 0) { + printf("Error in IPv6 Source Address (block) filter number %u.", filters.nblocksrc + 1); + exit(EXIT_FAILURE); + } + + if ((charptr = strtok_r(NULL, " ", &lasts)) == NULL) { + filters.blocksrclen[filters.nblocksrc] = 128; + } + else { + filters.blocksrclen[filters.nblocksrc] = atoi(charptr); + + if (filters.blocksrclen[filters.nblocksrc] > 128) { + printf("Length error in IPv6 Source Address (block) filter " + "number %u.\n", + filters.nblocksrc + 1); + exit(EXIT_FAILURE); + } + } + + sanitize_ipv6_prefix(&(filters.blocksrc[filters.nblocksrc]), filters.blocksrclen[filters.nblocksrc]); + (filters.nblocksrc)++; + break; + + case 'k': /* IPv6 Destination Address (block) filter */ + if (filters.nblockdst >= MAX_BLOCK_DST) { + puts("Too many IPv6 Destination Address (block) filters."); + exit(EXIT_FAILURE); + } + + if ((pref = strtok_r(optarg, "/", &lasts)) == NULL) { + printf("Error in IPv6 Destination Address (block) filter " + "number %u.\n", + filters.nblockdst + 1); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, pref, &(filters.blockdst[filters.nblockdst])) <= 0) { + printf("Error in IPv6 Source Address (block) filter number %u.", filters.nblockdst + 1); + exit(EXIT_FAILURE); + } + + if ((charptr = strtok_r(NULL, " ", &lasts)) == NULL) { + filters.blockdstlen[filters.nblockdst] = 128; + } + else { + filters.blockdstlen[filters.nblockdst] = atoi(charptr); + + if (filters.blockdstlen[filters.nblockdst] > 128) { + printf("Length error in IPv6 Source Address (block) filter " + "number %u.\n", + filters.nblockdst + 1); + exit(EXIT_FAILURE); + } + } + + sanitize_ipv6_prefix(&(filters.blockdst[filters.nblockdst]), filters.blockdstlen[filters.nblockdst]); + (filters.nblockdst)++; + break; + + case 'J': /* Link Source Address (block) filter */ + if (filters.nblocklinksrc > MAX_BLOCK_LINK_SRC) { + puts("Too many link-layer Source Address (accept) filters."); + exit(EXIT_FAILURE); + } + + if (ether_pton(optarg, &(filters.blocklinksrc[filters.nblocklinksrc]), sizeof(struct ether_addr)) == 0) { + printf("Error in link-layer Source Address (blick) filter " + "number %u.\n", + filters.nblocklinksrc + 1); + exit(EXIT_FAILURE); + } + + (filters.nblocklinksrc)++; + break; + + case 'K': /* Link Destination Address (block) filter */ + if (filters.nblocklinkdst > MAX_BLOCK_LINK_DST) { + puts("Too many link-layer Destination Address (block) filters."); + exit(EXIT_FAILURE); + } + + if (ether_pton(optarg, &(filters.blocklinkdst[filters.nblocklinkdst]), sizeof(struct ether_addr)) == 0) { + printf("Error in link-layer Destination Address (blick) filter " + "number " + "%u.\n", + filters.nblocklinkdst + 1); + exit(EXIT_FAILURE); + } + + filters.nblocklinkdst++; + break; + + case 'b': /* IPv6 Source Address (accept) filter */ + if (filters.nacceptsrc > MAX_ACCEPT_SRC) { + puts("Too many IPv6 Source Address (accept) filters."); + exit(EXIT_FAILURE); + } + + if ((pref = strtok_r(optarg, "/", &lasts)) == NULL) { + printf("Error in IPv6 Source Address (accept) filter number %u.\n", filters.nacceptsrc + 1); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, pref, &(filters.acceptsrc[filters.nacceptsrc])) <= 0) { + printf("Error in IPv6 Source Address (accept) filter number %u.\n", filters.nacceptsrc + 1); + exit(EXIT_FAILURE); + } + + if ((charptr = strtok_r(NULL, " ", &lasts)) == NULL) { + filters.acceptsrclen[filters.nacceptsrc] = 128; + } + else { + filters.acceptsrclen[filters.nacceptsrc] = atoi(charptr); + + if (filters.acceptsrclen[filters.nacceptsrc] > 128) { + printf("Length error in IPv6 Source Address (accept) " + "filter number " + "%u.\n", + filters.nacceptsrc + 1); + exit(EXIT_FAILURE); + } + } + + sanitize_ipv6_prefix(&(filters.acceptsrc[filters.nacceptsrc]), filters.acceptsrclen[filters.nacceptsrc]); + (filters.nacceptsrc)++; + filters.acceptfilters_f = 1; + break; + + case 'g': /* IPv6 Destination Address (accept) filter */ + if (filters.nacceptdst > MAX_ACCEPT_DST) { + puts("Too many IPv6 Destination Address (accept) filters."); + exit(EXIT_FAILURE); + } + + if ((pref = strtok_r(optarg, "/", &lasts)) == NULL) { + printf("Error in IPv6 Destination Address (accept) filter " + "number %u.\n", + filters.nacceptdst + 1); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, pref, &(filters.acceptdst[filters.nacceptdst])) <= 0) { + printf("Error in IPv6 Source Address (accept) filter number %u.\n", filters.nacceptdst + 1); + exit(EXIT_FAILURE); + } + + if ((charptr = strtok_r(NULL, " ", &lasts)) == NULL) { + filters.acceptdstlen[filters.nacceptdst] = 128; + } + else { + filters.acceptdstlen[filters.nacceptdst] = atoi(charptr); + + if (filters.acceptdstlen[filters.nacceptdst] > 128) { + printf("Length error in IPv6 Source Address (accept) " + "filter number " + "%u.\n", + filters.nacceptdst + 1); + exit(EXIT_FAILURE); + } + } + + sanitize_ipv6_prefix(&(filters.acceptdst[filters.nacceptdst]), filters.acceptdstlen[filters.nacceptdst]); + (filters.nacceptdst)++; + filters.acceptfilters_f = 1; + break; + + case 'B': /* Link-layer Source Address (accept) filter */ + if (filters.nacceptlinksrc > MAX_ACCEPT_LINK_SRC) { + puts("Too many link-later Source Address (accept) filters."); + exit(EXIT_FAILURE); + } + + if (ether_pton(optarg, &(filters.acceptlinksrc[filters.nacceptlinksrc]), sizeof(struct ether_addr)) == 0) { + printf("Error in link-layer Source Address (accept) filter " + "number %u.\n", + filters.nacceptlinksrc + 1); + exit(EXIT_FAILURE); + } + + (filters.nacceptlinksrc)++; + filters.acceptfilters_f = 1; + break; + + case 'G': /* Link Destination Address (accept) filter */ + if (filters.nacceptlinkdst > MAX_ACCEPT_LINK_DST) { + puts("Too many link-layer Destination Address (accept) " + "filters."); + exit(EXIT_FAILURE); + } + + if (ether_pton(optarg, &(filters.acceptlinkdst[filters.nacceptlinkdst]), sizeof(struct ether_addr)) == 0) { + printf("Error in link-layer Destination Address (accept) " + "filter number " + "%u.\n", + filters.nacceptlinkdst + 1); + exit(EXIT_FAILURE); + } + + (filters.nacceptlinkdst)++; + filters.acceptfilters_f = 1; + break; + + case 'w': /* ND Target Address (block) filter */ + if (filters.nblocktarget > MAX_BLOCK_TARGET) { + puts("Too many Target Address (block) filters."); + exit(EXIT_FAILURE); + } + + if ((pref = strtok_r(optarg, "/", &lasts)) == NULL) { + printf("Error in Target Address (block) filter number %u.\n", filters.nblocktarget + 1); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, pref, &(filters.blocktarget[filters.nblocktarget])) <= 0) { + printf("Error in Target Address (block) filter number %u.\n", filters.nblocktarget + 1); + exit(EXIT_FAILURE); + } + + if ((charptr = strtok_r(NULL, " ", &lasts)) == NULL) { + filters.blocktargetlen[filters.nblocktarget] = 128; + } + else { + filters.blocktargetlen[filters.nblocktarget] = atoi(charptr); + + if (filters.blocktargetlen[filters.nblocktarget] > 128) { + printf("Length error in Target Address (block) filter " + "number %u.\n", + filters.nblocktarget + 1); + exit(EXIT_FAILURE); + } + } + + sanitize_ipv6_prefix(&(filters.blocktarget[filters.nblocktarget]), + filters.blocktargetlen[filters.nblocktarget]); + filters.nblocktarget++; + break; + + case 'W': /* ND Target Address (accept) filter */ + if (filters.naccepttarget >= MAX_ACCEPT_TARGET) { + puts("Too many Target Address (accept) filters."); + exit(EXIT_FAILURE); + } + + if ((pref = strtok_r(optarg, "/", &lasts)) == NULL) { + printf("Error in Target Address (accept) filter number %u.\n", filters.naccepttarget + 1); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, pref, &(filters.accepttarget[filters.naccepttarget])) <= 0) { + printf("Error in Target Address (accept) filter number %u.\n", filters.naccepttarget + 1); + exit(EXIT_FAILURE); + } + + if ((charptr = strtok_r(NULL, " ", &lasts)) == NULL) { + filters.accepttargetlen[filters.naccepttarget] = 128; + } + else { + filters.accepttargetlen[filters.naccepttarget] = atoi(charptr); + + if (filters.accepttargetlen[filters.naccepttarget] > 128) { + printf("Length error in Target Address (accept) filter " + "number %u.\n", + filters.naccepttarget + 1); + exit(EXIT_FAILURE); + } + } + + sanitize_ipv6_prefix(&(filters.accepttarget[filters.naccepttarget]), + filters.accepttargetlen[filters.naccepttarget]); + filters.naccepttarget++; + filters.acceptfilters_f = 1; + break; + + case 'L': /* "Listen mode */ + listen_f = 1; + break; + + case 'T': /* Flood targets */ + ntargets = atoi(optarg); + if (ntargets == 0) { + puts("Invalid number of Target Addresses in option -T"); + exit(EXIT_FAILURE); + } + + floodt_f = 1; + break; + + case 'F': /* Flood sources */ + nsources = atoi(optarg); + if (nsources == 0) { + puts("Invalid number of sources in option -F"); + exit(EXIT_FAILURE); + } + + floods_f = 1; + break; + + case 'l': /* "Loop mode */ + loop_f = 1; + break; + + case 'z': /* Sleep option */ + nsleep = atoi(optarg); + if (nsleep == 0) { + puts("Invalid number of seconds in '-z' option"); + exit(EXIT_FAILURE); + } + + sleep_f = 1; + break; + + case 'v': /* Be verbose */ + idata.verbose_f++; + break; + + case 'h': /* Help */ + print_help(); + exit(EXIT_FAILURE); + break; + + default: + usage(); + exit(EXIT_FAILURE); + break; + } /* switch */ + } /* while(getopt) */ + + if (geteuid()) { + puts("na6 needs root privileges to run."); + exit(EXIT_FAILURE); + } + + if (!idata.iface_f) { + puts("Must specify the network interface with the -i option"); + exit(EXIT_FAILURE); + } + + if (load_dst_and_pcap(&idata, LOAD_PCAP_ONLY) == FAILURE) { + puts("Error while learning Source Address and Next Hop"); + exit(EXIT_FAILURE); + } + + release_privileges(); + + if (listen_f && loop_f) { + puts("'Error: listen' mode and 'loop' mode are incompatible"); + exit(EXIT_FAILURE); + } + + if (listen_f && floodt_f) { + puts("Error: 'listen' mode and 'flood targets' are incompatible"); + exit(EXIT_FAILURE); + } + + if (pcap_compile(idata.pfd, &pcap_filter, PCAP_ICMPV6_NS_FILTER, 0, PCAP_NETMASK_UNKNOWN) == -1) { + printf("pcap_compile(): %s", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } + + if (pcap_setfilter(idata.pfd, &pcap_filter) == -1) { + printf("pcap_setfilter(): %s", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } + + pcap_freecode(&pcap_filter); + + srandom(time(NULL)); + + if (!(idata.srcaddr_f) && !floods_f) { + /* When randomizing a link-local IPv6 address, select addresses that + belong to the prefix fe80::/64 (that's what a link-local address + looks-like in legitimate cases). The KAME implementation discards + addresses in which the second high-order 16 bits + (srcaddr.s6_addr16[1] in our case) are not zero. + */ + + if (idata.ip6_local_flag) { + idata.srcaddr = idata.ip6_local; + } + else { + if (inet_pton(AF_INET6, "fe80::", &(idata.srcaddr)) <= 0) { + puts("inet_pton(): Error when converting address"); + exit(EXIT_FAILURE); + } + + randomize_ipv6_addr(&(idata.srcaddr), &(idata.srcaddr), 64); + } + } + + /* + If the flood option ("-F") has been specified, but no prefix has been + specified, select the random Source Addresses from the link-local unicast + prefix (fe80::/64). + */ + if (floods_f && !idata.srcprefix_f) { + if (inet_pton(AF_INET6, "fe80::", &(idata.srcaddr)) <= 0) { + puts("inet_pton(): Error when converting address"); + exit(EXIT_FAILURE); + } + + randomize_ipv6_addr(&(idata.srcaddr), &(idata.srcaddr), 64); + + idata.srcpreflen = 64; + } + + if (!idata.dstaddr_f) { /* Destination Address defaults to all-nodes + * (ff02::1) + */ + if (inet_pton(AF_INET6, ALL_NODES_MULTICAST_ADDR, &(idata.dstaddr)) <= 0) { + puts("inet_pton(): Error converting all-nodes multicast address"); + exit(EXIT_FAILURE); + } + } + + if (!idata.hdstaddr_f) /* Destination link-layer address defaults to + * all-nodes + */ + if (ether_pton(ETHER_ALLNODES_LINK_ADDR, &(idata.hdstaddr), sizeof(idata.hdstaddr)) == 0) { + puts("ether_pton(): Error converting all-nodes multicast address"); + exit(EXIT_FAILURE); + } + + if (tllaopt_f && !tllaopta_f) { /* The value of the target link-layer address */ + linkaddr[0] = idata.hsrcaddr; /* option defaults to the Ethernet Source Address */ + nlinkaddr++; + } + + /* + If the flood target option ("-T") was specified, but no prefix was + specified, select the random Target Addresses from the link-local unicast + prefix (fe80::/64). + */ + if (floodt_f && !targetprefix_f) { + if (inet_pton(AF_INET6, "fe80::", &targetaddr) <= 0) { + puts("inet_pton(): Error when converting address"); + exit(EXIT_FAILURE); + } + + randomize_ipv6_addr(&targetaddr, &targetaddr, 64); + targetpreflen = 64; + } + + if (!floods_f) + nsources = 1; + + if (!floodt_f) + ntargets = 1; + + if (!sleep_f) + nsleep = 1; + + if (!idata.fragh_f && dstoptuhdr_f) { + puts("Dst. Options Header (Unfragmentable Part) set, but Fragmentation " + "not " + "specified"); + exit(EXIT_FAILURE); + } + + if (idata.verbose_f) { + print_attack_info(&idata); + } + + /* Set initial contents of the attack packet */ + init_packet_data(&idata); + + /* Fire a Neighbor Advertisement if a IPv6 Destination Address or an + * Ethernet Destination Address were specified + */ + if ((idata.dstaddr_f || idata.hdstaddr_f) && (targetaddr_f || floodt_f)) { + if (send_packet(&idata, NULL, NULL) == FAILURE) { + puts("Error while sending packet"); + exit(EXIT_FAILURE); + } + + if (idata.verbose_f) + puts("Initial attack packet(s) sent successfully."); + + if (loop_f) { + if (idata.verbose_f) + printf("Now sending Neighbor Advertisements every %u " + "second%s...\n", + nsleep, ((nsleep > 1) ? "s" : "")); + while (loop_f) { + sleep(nsleep); + if (send_packet(&idata, NULL, NULL) == FAILURE) { + puts("Error while sending packet"); + exit(EXIT_FAILURE); + } + } + + exit(EXIT_SUCCESS); + } + } + + if (listen_f) { + FD_ZERO(&sset); + FD_SET(idata.fd, &sset); + + if (idata.verbose_f) { + print_filters(&idata, &filters); + puts("Listening to incoming ICMPv6 Neighbor Solicitation " + "messages..."); + } + + while (listen_f) { + rset = sset; #if defined(sun) || defined(__sun) || defined(__linux__) - timeout.tv_usec=1000; - timeout.tv_sec= 0; - if((sel=select(idata.fd+1, &rset, NULL, NULL, &timeout)) == -1){ + timeout.tv_usec = 1000; + timeout.tv_sec = 0; + if ((sel = select(idata.fd + 1, &rset, NULL, NULL, &timeout)) == -1) { #else - if((sel=select(idata.fd+1, &rset, NULL, NULL, NULL)) == -1){ + if ((sel = select(idata.fd + 1, &rset, NULL, NULL, NULL)) == -1) { #endif - if(errno == EINTR){ - continue; - } - else{ - puts("Error in select()"); - exit(EXIT_FAILURE); - } - } + if (errno == EINTR) { + continue; + } + else { + puts("Error in select()"); + exit(EXIT_FAILURE); + } + } #if defined(sun) || defined(__sun) || defined(__linux__) - if(TRUE){ + if (TRUE) { #else - if(sel && FD_ISSET(idata.fd, &rset)){ + if (sel && FD_ISSET(idata.fd, &rset)) { #endif - /* Read a Neighbor Solicitation message */ - if((r=pcap_next_ex(idata.pfd, &pkthdr, &pktdata)) == -1){ - printf("pcap_next_ex(): %s", pcap_geterr(idata.pfd)); - exit(EXIT_FAILURE); - } - else if(r == 1 && pktdata != NULL){ - /* XXX Code assumes no IPv6 Extension Headers */ - pkt_ether = (struct ether_header *) pktdata; - pkt_ipv6 = (struct ip6_hdr *)((char *) pkt_ether + idata.linkhsize); - pkt_ns = (struct nd_neighbor_solicit *) ((char *) pkt_ipv6 + MIN_IPV6_HLEN); - pkt_icmp6= (struct icmp6_hdr *) pkt_ns; - - /* XXX This should probably be removed when pcap filter problem is solved */ - if(pkt_ipv6->ip6_nxt != IPPROTO_ICMPV6 || pkt_icmp6->icmp6_type != ND_NEIGHBOR_SOLICIT || \ - pkt_icmp6->icmp6_code != 0) - continue; - - accepted_f=0; - - if(idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK)){ - if(filters.nblocklinksrc){ - if(match_ether(filters.blocklinksrc, filters.nblocklinksrc, &(pkt_ether->src))){ - if(idata.verbose_f>1) - print_filter_result(&idata, pktdata, BLOCKED); - - continue; - } - } - - if(filters.nblocklinkdst){ - if(match_ether(filters.blocklinkdst, filters.nblocklinkdst, &(pkt_ether->dst))){ - if(idata.verbose_f>1) - print_filter_result(&idata, pktdata, BLOCKED); - - continue; - } - } - } - - if(filters.nblocksrc){ - if(match_ipv6(filters.blocksrc, filters.blocksrclen, filters.nblocksrc, &(pkt_ipv6->ip6_src))){ - if(idata.verbose_f>1) - print_filter_result(&idata, pktdata, BLOCKED); - - continue; - } - } - - if(filters.nblockdst){ - if(match_ipv6(filters.blockdst, filters.blockdstlen, filters.nblockdst, &(pkt_ipv6->ip6_dst))){ - if(idata.verbose_f>1) - print_filter_result(&idata, pktdata, BLOCKED); - - continue; - } - } - - if(filters.nblocktarget){ - if(match_ipv6(filters.blocktarget, filters.blocktargetlen, filters.nblocktarget, &(pkt_ns->nd_ns_target))){ - if(idata.verbose_f>1) - print_filter_result(&idata, pktdata, BLOCKED); - - continue; - } - } - - if(idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK)){ - if(filters.nacceptlinksrc){ - if(match_ether(filters.acceptlinksrc, filters.nacceptlinksrc, &(pkt_ether->src))) - accepted_f=1; - } - - if(filters.nacceptlinkdst && !accepted_f){ - if(match_ether(filters.acceptlinkdst, filters.nacceptlinkdst, &(pkt_ether->dst))) - accepted_f= 1; - } - } - - if(filters.nacceptsrc && !accepted_f){ - if(match_ipv6(filters.acceptsrc, filters.acceptsrclen, filters.nacceptsrc, &(pkt_ipv6->ip6_src))) - accepted_f= 1; - } - - if(filters.nacceptdst && !accepted_f){ - if(match_ipv6(filters.acceptdst, filters.acceptdstlen, filters.nacceptdst, &(pkt_ipv6->ip6_dst))) - accepted_f=1; - } - - if(filters.naccepttarget && !accepted_f){ - if(match_ipv6(filters.accepttarget, filters.accepttargetlen, filters.naccepttarget, &(pkt_ns->nd_ns_target))) - accepted_f=1; - } - - if(filters.acceptfilters_f && !accepted_f){ - if(idata.verbose_f>1) - print_filter_result(&idata, pktdata, BLOCKED); - - continue; - } - - if(idata.verbose_f) - print_filter_result(&idata, pktdata, ACCEPTED); - - /* Send a Neighbor Advertisement */ - if(send_packet(&idata, pkthdr, pktdata) == FAILURE){ - puts("Error while sending packet"); - exit(EXIT_FAILURE); - } - } - } - } - - exit(EXIT_SUCCESS); - } - - - if(!((idata.dstaddr_f || idata.hdstaddr_f) && (targetaddr_f || floodt_f)) && !listen_f){ - puts("Error: Nothing to send! (Destination Address or ND Target Address missing?)"); - exit(EXIT_FAILURE); - } - - exit(EXIT_SUCCESS); -} + /* Read a Neighbor Solicitation message */ + if ((r = pcap_next_ex(idata.pfd, &pkthdr, &pktdata)) == -1) { + printf("pcap_next_ex(): %s", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } + else if (r == 1 && pktdata != NULL) { + /* XXX Code assumes no IPv6 Extension Headers */ + pkt_ether = (struct ether_header *)pktdata; + pkt_ipv6 = (struct ip6_hdr *)((char *)pkt_ether + idata.linkhsize); + pkt_ns = (struct nd_neighbor_solicit *)((char *)pkt_ipv6 + MIN_IPV6_HLEN); + pkt_icmp6 = (struct icmp6_hdr *)pkt_ns; + + /* XXX This should probably be removed when pcap filter + * problem is solved */ + if (pkt_ipv6->ip6_nxt != IPPROTO_ICMPV6 || pkt_icmp6->icmp6_type != ND_NEIGHBOR_SOLICIT || + pkt_icmp6->icmp6_code != 0) + continue; + + accepted_f = 0; + + if (idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK)) { + if (filters.nblocklinksrc) { + if (match_ether(filters.blocklinksrc, filters.nblocklinksrc, &(pkt_ether->src))) { + if (idata.verbose_f > 1) + print_filter_result(&idata, pktdata, BLOCKED); + + continue; + } + } + + if (filters.nblocklinkdst) { + if (match_ether(filters.blocklinkdst, filters.nblocklinkdst, &(pkt_ether->dst))) { + if (idata.verbose_f > 1) + print_filter_result(&idata, pktdata, BLOCKED); + + continue; + } + } + } + + if (filters.nblocksrc) { + if (match_ipv6(filters.blocksrc, filters.blocksrclen, filters.nblocksrc, + &(pkt_ipv6->ip6_src))) { + if (idata.verbose_f > 1) + print_filter_result(&idata, pktdata, BLOCKED); + + continue; + } + } + + if (filters.nblockdst) { + if (match_ipv6(filters.blockdst, filters.blockdstlen, filters.nblockdst, + &(pkt_ipv6->ip6_dst))) { + if (idata.verbose_f > 1) + print_filter_result(&idata, pktdata, BLOCKED); + + continue; + } + } + + if (filters.nblocktarget) { + if (match_ipv6(filters.blocktarget, filters.blocktargetlen, filters.nblocktarget, + &(pkt_ns->nd_ns_target))) { + if (idata.verbose_f > 1) + print_filter_result(&idata, pktdata, BLOCKED); + + continue; + } + } + + if (idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK)) { + if (filters.nacceptlinksrc) { + if (match_ether(filters.acceptlinksrc, filters.nacceptlinksrc, &(pkt_ether->src))) + accepted_f = 1; + } + + if (filters.nacceptlinkdst && !accepted_f) { + if (match_ether(filters.acceptlinkdst, filters.nacceptlinkdst, &(pkt_ether->dst))) + accepted_f = 1; + } + } + + if (filters.nacceptsrc && !accepted_f) { + if (match_ipv6(filters.acceptsrc, filters.acceptsrclen, filters.nacceptsrc, + &(pkt_ipv6->ip6_src))) + accepted_f = 1; + } + + if (filters.nacceptdst && !accepted_f) { + if (match_ipv6(filters.acceptdst, filters.acceptdstlen, filters.nacceptdst, + &(pkt_ipv6->ip6_dst))) + accepted_f = 1; + } + + if (filters.naccepttarget && !accepted_f) { + if (match_ipv6(filters.accepttarget, filters.accepttargetlen, filters.naccepttarget, + &(pkt_ns->nd_ns_target))) + accepted_f = 1; + } + + if (filters.acceptfilters_f && !accepted_f) { + if (idata.verbose_f > 1) + print_filter_result(&idata, pktdata, BLOCKED); + + continue; + } + + if (idata.verbose_f) + print_filter_result(&idata, pktdata, ACCEPTED); + + /* Send a Neighbor Advertisement */ + if (send_packet(&idata, pkthdr, pktdata) == FAILURE) { + puts("Error while sending packet"); + exit(EXIT_FAILURE); + } + } + } + } + + exit(EXIT_SUCCESS); + } + if (!((idata.dstaddr_f || idata.hdstaddr_f) && (targetaddr_f || floodt_f)) && !listen_f) { + puts("Error: Nothing to send! (Destination Address or ND Target Address " + "missing?)"); + exit(EXIT_FAILURE); + } + exit(EXIT_SUCCESS); +} /* * Function: init_packet_data() * - * Initialize the contents of the attack packet (Ethernet header, IPv6 Header, and ICMPv6 header) - * that are expected to remain constant for the specified attack. + * Initialize the contents of the attack packet (Ethernet header, IPv6 Header, + * and ICMPv6 header) that are expected to remain constant for the specified + * attack. */ -void init_packet_data(struct iface_data *idata){ - struct dlt_null *dlt_null; - ethernet= (struct ether_header *) buffer; - dlt_null= (struct dlt_null *) buffer; - v6buffer = buffer + idata->linkhsize; - ipv6 = (struct ip6_hdr *) v6buffer; - - if(idata->type == DLT_EN10MB){ - ethernet->ether_type = htons(ETHERTYPE_IPV6); - - if(!(idata->flags & IFACE_LOOPBACK)){ - ethernet->src = idata->hsrcaddr; - ethernet->dst = idata->hdstaddr; - } - } - else if(idata->type == DLT_NULL){ - dlt_null->family= PF_INET6; - } -#if defined (__OpenBSD__) - else if(idata->type == DLT_LOOP){ - dlt_null->family= htonl(PF_INET6); - } +void init_packet_data(struct iface_data *idata) { + struct dlt_null *dlt_null; + ethernet = (struct ether_header *)buffer; + dlt_null = (struct dlt_null *)buffer; + v6buffer = buffer + idata->linkhsize; + ipv6 = (struct ip6_hdr *)v6buffer; + + if (idata->type == DLT_EN10MB) { + ethernet->ether_type = htons(ETHERTYPE_IPV6); + + if (!(idata->flags & IFACE_LOOPBACK)) { + ethernet->src = idata->hsrcaddr; + ethernet->dst = idata->hdstaddr; + } + } + else if (idata->type == DLT_NULL) { + dlt_null->family = PF_INET6; + } +#if defined(__OpenBSD__) + else if (idata->type == DLT_LOOP) { + dlt_null->family = htonl(PF_INET6); + } #endif - ipv6->ip6_flow=0; - ipv6->ip6_vfc= 0x60; - ipv6->ip6_hlim= hoplimit; - ipv6->ip6_src= idata->srcaddr; - ipv6->ip6_dst= idata->dstaddr; - - prev_nh = (unsigned char *) &(ipv6->ip6_nxt); - - ptr = (unsigned char *) v6buffer + MIN_IPV6_HLEN; - - if(hbhopthdr_f){ - hbhopthdrs=0; - - while(hbhopthdrs < nhbhopthdr){ - if((ptr+ hbhopthdrlen[hbhopthdrs]) > (v6buffer+ idata->mtu)){ - puts("Packet too large while processing HBH Opt. Header"); - exit(EXIT_FAILURE); - } - - *prev_nh = IPPROTO_HOPOPTS; - prev_nh = ptr; - memcpy(ptr, hbhopthdr[hbhopthdrs], hbhopthdrlen[hbhopthdrs]); - ptr = ptr + hbhopthdrlen[hbhopthdrs]; - hbhopthdrs++; - } - } - - if(dstoptuhdr_f){ - dstoptuhdrs=0; - - while(dstoptuhdrs < ndstoptuhdr){ - if((ptr+ dstoptuhdrlen[dstoptuhdrs]) > (v6buffer+ idata->mtu)){ - puts("Packet too large while processing Dest. Opt. Header (Unfrag. Part)"); - exit(EXIT_FAILURE); - } - - *prev_nh = IPPROTO_DSTOPTS; - prev_nh = ptr; - memcpy(ptr, dstoptuhdr[dstoptuhdrs], dstoptuhdrlen[dstoptuhdrs]); - ptr = ptr + dstoptuhdrlen[dstoptuhdrs]; - dstoptuhdrs++; - } - } - - /* Everything that follows is the Fragmentable Part of the packet */ - fragpart = ptr; - - if(idata->fragh_f){ - /* Check that we are able to send the Unfragmentable Part, together with a - Fragment Header and a chunk data over our link layer - */ - if( (fragpart+sizeof(fraghdr)+nfrags) > (v6buffer+idata->mtu)){ - printf("Unfragmentable part too large for current MTU (%u bytes)\n", idata->mtu); - exit(EXIT_FAILURE); - } - - /* We prepare a separete Fragment Header, but we do not include it in the packet to be sent. - This Fragment Header will be used (an assembled with the rest of the packet by the - send_packet() function. - */ - memset(&fraghdr, 0, FRAG_HDR_SIZE); - *prev_nh = IPPROTO_FRAGMENT; - prev_nh = (unsigned char *) &fraghdr; - } - - if(dstopthdr_f){ - dstopthdrs=0; - - while(dstopthdrs < ndstopthdr){ - if((ptr+ dstopthdrlen[dstopthdrs]) > (v6buffer+idata->max_packet_size)){ - puts("Packet too large while processing Dest. Opt. Header (should be using the Frag. option?)"); - exit(EXIT_FAILURE); - } - - *prev_nh = IPPROTO_DSTOPTS; - prev_nh = ptr; - memcpy(ptr, dstopthdr[dstopthdrs], dstopthdrlen[dstopthdrs]); - ptr = ptr + dstopthdrlen[dstopthdrs]; - dstopthdrs++; - } - } - - - *prev_nh = IPPROTO_ICMPV6; - - if( (ptr+sizeof(struct nd_neighbor_advert)) > (v6buffer+idata->max_packet_size)){ - puts("Packet too large while inserting Neighbor Advertisement header (should be using Frag. option?)"); - exit(EXIT_FAILURE); - } - - na= (struct nd_neighbor_advert *) ptr; - - na->nd_na_type = ND_NEIGHBOR_ADVERT; - na->nd_na_code = 0; - na->nd_na_flags_reserved = router_f | solicited_f | override_f; - na->nd_na_target = targetaddr; - - ptr += sizeof(struct nd_neighbor_advert); - - if(tllaopt_f && nlinkaddr==1){ - if( (ptr+sizeof(struct nd_opt_tlla)) <= (v6buffer+idata->max_packet_size) ){ - tllaopt = (struct nd_opt_tlla *) ptr; - tllaopt->type= ND_OPT_TARGET_LINKADDR; - tllaopt->length= TLLA_OPT_LEN; - memcpy(tllaopt->address, linkaddr[0].a, ETH_ALEN); - ptr += sizeof(struct nd_opt_tlla); - } - else{ - puts("Packet Too Large while processing target link-layer address option"); - exit(EXIT_FAILURE); - } - } - - startofprefixes=ptr; -} + ipv6->ip6_flow = 0; + ipv6->ip6_vfc = 0x60; + ipv6->ip6_hlim = hoplimit; + ipv6->ip6_src = idata->srcaddr; + ipv6->ip6_dst = idata->dstaddr; + + prev_nh = (unsigned char *)&(ipv6->ip6_nxt); + + ptr = (unsigned char *)v6buffer + MIN_IPV6_HLEN; + if (hbhopthdr_f) { + hbhopthdrs = 0; + while (hbhopthdrs < nhbhopthdr) { + if ((ptr + hbhopthdrlen[hbhopthdrs]) > (v6buffer + idata->mtu)) { + puts("Packet too large while processing HBH Opt. Header"); + exit(EXIT_FAILURE); + } + + *prev_nh = IPPROTO_HOPOPTS; + prev_nh = ptr; + memcpy(ptr, hbhopthdr[hbhopthdrs], hbhopthdrlen[hbhopthdrs]); + ptr = ptr + hbhopthdrlen[hbhopthdrs]; + hbhopthdrs++; + } + } + + if (dstoptuhdr_f) { + dstoptuhdrs = 0; + + while (dstoptuhdrs < ndstoptuhdr) { + if ((ptr + dstoptuhdrlen[dstoptuhdrs]) > (v6buffer + idata->mtu)) { + puts("Packet too large while processing Dest. Opt. Header " + "(Unfrag. " + "Part)"); + exit(EXIT_FAILURE); + } + + *prev_nh = IPPROTO_DSTOPTS; + prev_nh = ptr; + memcpy(ptr, dstoptuhdr[dstoptuhdrs], dstoptuhdrlen[dstoptuhdrs]); + ptr = ptr + dstoptuhdrlen[dstoptuhdrs]; + dstoptuhdrs++; + } + } + + /* Everything that follows is the Fragmentable Part of the packet */ + fragpart = ptr; + + if (idata->fragh_f) { + /* Check that we are able to send the Unfragmentable Part, together with + a Fragment Header and a chunk data over our link layer + */ + if ((fragpart + sizeof(fraghdr) + nfrags) > (v6buffer + idata->mtu)) { + printf("Unfragmentable part too large for current MTU (%u bytes)\n", idata->mtu); + exit(EXIT_FAILURE); + } + + /* We prepare a separete Fragment Header, but we do not include it in + the packet to be sent. This Fragment Header will be used (an + assembled with the rest of the packet by the send_packet() function. + */ + memset(&fraghdr, 0, FRAG_HDR_SIZE); + *prev_nh = IPPROTO_FRAGMENT; + prev_nh = (unsigned char *)&fraghdr; + } + + if (dstopthdr_f) { + dstopthdrs = 0; + + while (dstopthdrs < ndstopthdr) { + if ((ptr + dstopthdrlen[dstopthdrs]) > (v6buffer + idata->max_packet_size)) { + puts("Packet too large while processing Dest. Opt. Header " + "(should be " + "using the Frag. option?)"); + exit(EXIT_FAILURE); + } + + *prev_nh = IPPROTO_DSTOPTS; + prev_nh = ptr; + memcpy(ptr, dstopthdr[dstopthdrs], dstopthdrlen[dstopthdrs]); + ptr = ptr + dstopthdrlen[dstopthdrs]; + dstopthdrs++; + } + } + + *prev_nh = IPPROTO_ICMPV6; + + if ((ptr + sizeof(struct nd_neighbor_advert)) > (v6buffer + idata->max_packet_size)) { + puts("Packet too large while inserting Neighbor Advertisement header " + "(should be using Frag. option?)"); + exit(EXIT_FAILURE); + } + + na = (struct nd_neighbor_advert *)ptr; + + na->nd_na_type = ND_NEIGHBOR_ADVERT; + na->nd_na_code = 0; + na->nd_na_flags_reserved = router_f | solicited_f | override_f; + na->nd_na_target = targetaddr; + + ptr += sizeof(struct nd_neighbor_advert); + + if (tllaopt_f && nlinkaddr == 1) { + if ((ptr + sizeof(struct nd_opt_tlla)) <= (v6buffer + idata->max_packet_size)) { + tllaopt = (struct nd_opt_tlla *)ptr; + tllaopt->type = ND_OPT_TARGET_LINKADDR; + tllaopt->length = TLLA_OPT_LEN; + memcpy(tllaopt->address, linkaddr[0].a, ETH_ALEN); + ptr += sizeof(struct nd_opt_tlla); + } + else { + puts("Packet Too Large while processing target link-layer address " + "option"); + exit(EXIT_FAILURE); + } + } + + startofprefixes = ptr; +} /* * Function: send_packet() @@ -1265,406 +1303,426 @@ void init_packet_data(struct iface_data *idata){ * Initialize the remaining fields of the Neighbor Advertisement Message, and * send the attack packet(s). */ -int send_packet(struct iface_data *idata, struct pcap_pkthdr *pkthdr, const u_char *pktdata){ - if(pktdata == NULL){ - sources=0; - } - else{ /* Sending a response to a Neighbor Solicitation message */ - pkt_ether = (struct ether_header *) pktdata; - pkt_ipv6 = (struct ip6_hdr *)((char *) pkt_ether + idata->linkhsize); - pkt_ns = (struct nd_neighbor_solicit *) ((char *) pkt_ipv6 + MIN_IPV6_HLEN); - - /* If the IPv6 Source Address of the incoming Neighbor Solicitation is the unspecified - address (::), the Neighbor Advertisement must be directed to the IPv6 all-nodes - multicast address (and the Ethernet Destination address should be 33:33:33:00:00:01). - Otherwise, the Neighbor Advertisement is sent to the IPv6 Source Address (and - Ethernet Source Address) of the incoming Neighbor Solicitation message - */ - pkt_ipv6addr = &(pkt_ipv6->ip6_src); - - na->nd_na_flags_reserved = router_f | solicited_f | override_f; - - if(IN6_IS_ADDR_UNSPECIFIED(pkt_ipv6addr)){ - if ( inet_pton(AF_INET6, ALL_NODES_MULTICAST_ADDR, &(ipv6->ip6_dst)) <= 0){ - puts("inetr_pton(): Error converting all-nodes multicast address"); - return(FAILURE); - } - - if(ether_pton(ETHER_ALLNODES_LINK_ADDR, &(ethernet->dst), ETHER_ADDR_LEN) == 0){ - puts("ether_pton(): Error converting all-nodes link-local address"); - return(FAILURE); - } - } - else{ - ipv6->ip6_dst = pkt_ipv6->ip6_src; - ethernet->dst = pkt_ether->src; - - /* - Set the "Solicited" flag if NS was sent from an address other than the unspecified - address (i.e., the response will be unicast). - */ - - na->nd_na_flags_reserved = na->nd_na_flags_reserved | ND_NA_FLAG_SOLICITED; - } - - pkt_ipv6addr = &(pkt_ipv6->ip6_dst); - - /* - If the Neighbor Solicitation message was directed to a unicast address (unlikely), the - IPv6 Source Address and the Ethernet Source Address of the Neighbor Advertisement are set - to the IPv6 Destination Address and the Ethernet Destination Address of the incoming - Neighbor Solicitation, respectively. Otherwise, the IPv6 Source Address is set to the - ND Target Address (unless a specific IPv6 Source Address was specified with the "-s" - option), and the Ethernet is set to that specified by the "-S" option (or randomized). - */ - if(IN6_IS_ADDR_MULTICAST(pkt_ipv6addr)){ - if( !idata->srcaddr_f && IN6_IS_ADDR_LINKLOCAL(&(pkt_ns->nd_ns_target)) ) - ipv6->ip6_src = pkt_ns->nd_ns_target; - else - ipv6->ip6_src = idata->srcaddr; - - ethernet->src = idata->hsrcaddr; - sources=0; - multicastdst_f=1; - } - else{ - ipv6->ip6_src = pkt_ipv6->ip6_dst; - ethernet->src = pkt_ether->dst; - sources=nsources; - multicastdst_f=0; - } - - na->nd_na_target= pkt_ns->nd_ns_target; - } - - - do{ - if(floods_f && (pktdata==NULL || (pktdata != NULL && multicastdst_f))){ - /* - Randomizing the IPv6 Source address based on the prefix specified by - "srcaddr" and prefix length. - */ - randomize_ipv6_addr(&(ipv6->ip6_src), &(idata->srcaddr), idata->srcpreflen); - - if(!idata->hsrcaddr_f){ - randomize_ether_addr(&(ethernet->src)); - } - - if(tllaopt_f && !tllaopta_f){ - memcpy(tllaopt->address, ethernet->src.a, ETH_ALEN); - } - } - - targets=0; - - do{ - if(floodt_f){ - /* - Randomizing the ND Target Address based on the prefix specified by "targetaddr" - and targetpreflen. - */ - randomize_ipv6_addr(&(na->nd_na_target), &targetaddr, targetpreflen); - } - - /* - * If a single target link-layer address option is to be included, it is included - * by init_packet_data() - */ - if(nlinkaddr==1) - linkaddrs=1; - else - linkaddrs=0; - - do{ - newdata_f=0; - ptr=startofprefixes; - - while(linkaddrsmax_packet_size){ - tllaopt = (struct nd_opt_tlla *) ptr; - tllaopt->type= ND_OPT_TARGET_LINKADDR; - tllaopt->length= TLLA_OPT_LEN; - memcpy(tllaopt->address, linkaddr[linkaddrs].a, ETH_ALEN); - ptr += sizeof(struct nd_opt_tlla); - linkaddrs++; - newdata_f=1; - } - - na->nd_na_cksum = 0; - na->nd_na_cksum = in_chksum(v6buffer, na, ptr-((unsigned char *)na), IPPROTO_ICMPV6); - - - if(!idata->fragh_f){ - ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); - - if((nw=pcap_inject(idata->pfd, buffer, ptr - buffer)) == -1){ - printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); - return(FAILURE); - } - - if(nw != (ptr-buffer)){ - printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, \ - (LUI) (ptr-buffer)); - return(FAILURE); - } - } - else{ - ptrend= ptr; - ptr= fragpart; - fptr = fragbuffer; - fipv6 = (struct ip6_hdr *) (fragbuffer + ETHER_HDR_LEN); - fptrend = fptr + ETHER_HDR_LEN+MIN_IPV6_HLEN+MAX_IPV6_PAYLOAD; - memcpy(fptr, buffer, fragpart-buffer); - fptr = fptr + (fragpart-buffer); - - if( (fptr+FRAG_HDR_SIZE)> fptrend){ - puts("Unfragmentable Part is Too Large"); - return(FAILURE); - } - - memcpy(fptr, (char *) &fraghdr, FRAG_HDR_SIZE); - fh= (struct ip6_frag *) fptr; - fh->ip6f_ident=random(); - startoffragment = fptr + FRAG_HDR_SIZE; - - /* - * Check that the selected fragment size is not larger than the largest - * fragment size that can be sent - */ - if(nfrags > (fptrend - fptr)) - nfrags= (fptrend-fptr); - - m=IP6F_MORE_FRAG; - - while((ptr< ptrend) && m==IP6F_MORE_FRAG){ - fptr= startoffragment; - - if( (ptrend-ptr) <= nfrags){ - fragsize= ptrend-ptr; - m=0; - } - else{ - fragsize = (nfrags + 7) & ntohs(IP6F_OFF_MASK); - } - - memcpy(fptr, ptr, fragsize); - fh->ip6f_offlg = (htons(ptr-fragpart) & IP6F_OFF_MASK) | m; - ptr+=fragsize; - fptr+=fragsize; - - fipv6->ip6_plen = htons((fptr - fragbuffer) - MIN_IPV6_HLEN - ETHER_HDR_LEN); - - if((nw=pcap_inject(idata->pfd, fragbuffer, fptr - fragbuffer)) == -1){ - printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); - return(FAILURE); - } - - if(nw != (fptr- fragbuffer)){ - printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n"\ - , nw, (LUI) (ptr-buffer)); - return(FAILURE); - } - } - } - }while(linkaddrslinkhsize); + pkt_ns = (struct nd_neighbor_solicit *)((char *)pkt_ipv6 + MIN_IPV6_HLEN); + + /* If the IPv6 Source Address of the incoming Neighbor Solicitation is + the unspecified address (::), the Neighbor Advertisement must be + directed to the IPv6 all-nodes multicast address (and the Ethernet + Destination address should be 33:33:33:00:00:01). Otherwise, the + Neighbor Advertisement is sent to the IPv6 Source Address (and + Ethernet Source Address) of the incoming Neighbor Solicitation + message + */ + pkt_ipv6addr = &(pkt_ipv6->ip6_src); + + na->nd_na_flags_reserved = router_f | solicited_f | override_f; + + if (IN6_IS_ADDR_UNSPECIFIED(pkt_ipv6addr)) { + if (inet_pton(AF_INET6, ALL_NODES_MULTICAST_ADDR, &(ipv6->ip6_dst)) <= 0) { + puts("inetr_pton(): Error converting all-nodes multicast " + "address"); + return (FAILURE); + } + + if (ether_pton(ETHER_ALLNODES_LINK_ADDR, &(ethernet->dst), ETHER_ADDR_LEN) == 0) { + puts("ether_pton(): Error converting all-nodes link-local " + "address"); + return (FAILURE); + } + } + else { + ipv6->ip6_dst = pkt_ipv6->ip6_src; + ethernet->dst = pkt_ether->src; + + /* + Set the "Solicited" flag if NS was sent from an address other + than the unspecified address (i.e., the response will be + unicast). + */ + + na->nd_na_flags_reserved = na->nd_na_flags_reserved | ND_NA_FLAG_SOLICITED; + } + + pkt_ipv6addr = &(pkt_ipv6->ip6_dst); + + /* + If the Neighbor Solicitation message was directed to a unicast + address (unlikely), the IPv6 Source Address and the Ethernet Source + Address of the Neighbor Advertisement are set to the IPv6 Destination + Address and the Ethernet Destination Address of the incoming Neighbor + Solicitation, respectively. Otherwise, the IPv6 Source Address is set + to the ND Target Address (unless a specific IPv6 Source Address was + specified with the + "-s" option), and the Ethernet is set to that specified by the "-S" + option (or randomized). + */ + if (IN6_IS_ADDR_MULTICAST(pkt_ipv6addr)) { + if (!idata->srcaddr_f && IN6_IS_ADDR_LINKLOCAL(&(pkt_ns->nd_ns_target))) + ipv6->ip6_src = pkt_ns->nd_ns_target; + else + ipv6->ip6_src = idata->srcaddr; + + ethernet->src = idata->hsrcaddr; + sources = 0; + multicastdst_f = 1; + } + else { + ipv6->ip6_src = pkt_ipv6->ip6_dst; + ethernet->src = pkt_ether->dst; + sources = nsources; + multicastdst_f = 0; + } + + na->nd_na_target = pkt_ns->nd_ns_target; + } + do { + if (floods_f && (pktdata == NULL || (pktdata != NULL && multicastdst_f))) { + /* + Randomizing the IPv6 Source address based on the prefix specified + by "srcaddr" and prefix length. + */ + randomize_ipv6_addr(&(ipv6->ip6_src), &(idata->srcaddr), idata->srcpreflen); + + if (!idata->hsrcaddr_f) { + randomize_ether_addr(&(ethernet->src)); + } + + if (tllaopt_f && !tllaopta_f) { + memcpy(tllaopt->address, ethernet->src.a, ETH_ALEN); + } + } + + targets = 0; + + do { + if (floodt_f) { + /* + Randomizing the ND Target Address based on the prefix + specified by "targetaddr" and targetpreflen. + */ + randomize_ipv6_addr(&(na->nd_na_target), &targetaddr, targetpreflen); + } + + /* + * If a single target link-layer address option is to be included, + * it is included by init_packet_data() + */ + if (nlinkaddr == 1) + linkaddrs = 1; + else + linkaddrs = 0; + + do { + newdata_f = 0; + ptr = startofprefixes; + + while (linkaddrs < nlinkaddr && + ((ptr + sizeof(struct nd_opt_tlla)) - v6buffer) <= idata->max_packet_size) { + tllaopt = (struct nd_opt_tlla *)ptr; + tllaopt->type = ND_OPT_TARGET_LINKADDR; + tllaopt->length = TLLA_OPT_LEN; + memcpy(tllaopt->address, linkaddr[linkaddrs].a, ETH_ALEN); + ptr += sizeof(struct nd_opt_tlla); + linkaddrs++; + newdata_f = 1; + } + + na->nd_na_cksum = 0; + na->nd_na_cksum = in_chksum(v6buffer, na, ptr - ((unsigned char *)na), IPPROTO_ICMPV6); + + if (!idata->fragh_f) { + ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); + + if ((nw = pcap_inject(idata->pfd, buffer, ptr - buffer)) == -1) { + printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); + return (FAILURE); + } + + if (nw != (ptr - buffer)) { + printf("pcap_inject(): only wrote %d bytes (rather " + "than %lu bytes)\n", + nw, (LUI)(ptr - buffer)); + return (FAILURE); + } + } + else { + ptrend = ptr; + ptr = fragpart; + fptr = fragbuffer; + fipv6 = (struct ip6_hdr *)(fragbuffer + ETHER_HDR_LEN); + fptrend = fptr + ETHER_HDR_LEN + MIN_IPV6_HLEN + MAX_IPV6_PAYLOAD; + memcpy(fptr, buffer, fragpart - buffer); + fptr = fptr + (fragpart - buffer); + + if ((fptr + FRAG_HDR_SIZE) > fptrend) { + puts("Unfragmentable Part is Too Large"); + return (FAILURE); + } + + memcpy(fptr, (char *)&fraghdr, FRAG_HDR_SIZE); + fh = (struct ip6_frag *)fptr; + fh->ip6f_ident = random(); + startoffragment = fptr + FRAG_HDR_SIZE; + + /* + * Check that the selected fragment size is not larger than + * the largest fragment size that can be sent + */ + if (nfrags > (fptrend - fptr)) + nfrags = (fptrend - fptr); + + m = IP6F_MORE_FRAG; + + while ((ptr < ptrend) && m == IP6F_MORE_FRAG) { + fptr = startoffragment; + + if ((ptrend - ptr) <= nfrags) { + fragsize = ptrend - ptr; + m = 0; + } + else { + fragsize = (nfrags + 7) & ntohs(IP6F_OFF_MASK); + } + + memcpy(fptr, ptr, fragsize); + fh->ip6f_offlg = (htons(ptr - fragpart) & IP6F_OFF_MASK) | m; + ptr += fragsize; + fptr += fragsize; + + fipv6->ip6_plen = htons((fptr - fragbuffer) - MIN_IPV6_HLEN - ETHER_HDR_LEN); + + if ((nw = pcap_inject(idata->pfd, fragbuffer, fptr - fragbuffer)) == -1) { + printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); + return (FAILURE); + } + + if (nw != (fptr - fragbuffer)) { + printf("pcap_inject(): only wrote %d bytes (rather " + "than %lu " + "bytes)\n", + nw, (LUI)(ptr - buffer)); + return (FAILURE); + } + } + } + } while (linkaddrs < nlinkaddr && newdata_f); + + targets++; + + } while (targets < ntargets); + + sources++; + } while (sources < nsources); + + return (SUCCESS); +} /* * Function: usage() * * Prints the syntax of the na6 tool */ -void usage(void){ - puts("usage: na6 -i INTERFACE [-s SRC_ADDR[/LEN]] [-d DST_ADDR] [-S LINK_SRC_ADDR] " - "[-y FRAG_SIZE] [-u DST_OPT_HDR_SIZE] [-U DST_OPT_U_HDR_SIZE] [-H HBH_OPT_HDR_SIZE] " - "[-D LINK-DST-ADDR] [-t TARGET_ADDR[/LEN]] [-r] [-c] [-o] [-E LINK_ADDR] [-e] " - "[-j PREFIX[/LEN]] [-k PREFIX[/LEN]] [-J LINK_ADDR] [-K LINK_ADDR] [-w PREFIX[/LEN]] " - "[-b PREFIX[/LEN]] [-g PREFIX[/LEN]] [-B LINK_ADDR] [-G LINK_ADDR] [-W PREFIX[/LEN]] " - "[-F N_SOURCES] [-T N_TARGETS] [-L | -l] [-z] [-v] [-V] [-h]"); +void usage(void) { + puts("usage: na6 -i INTERFACE [-s SRC_ADDR[/LEN]] [-d DST_ADDR] [-S " + "LINK_SRC_ADDR] " + "[-y FRAG_SIZE] [-u DST_OPT_HDR_SIZE] [-U DST_OPT_U_HDR_SIZE] [-H " + "HBH_OPT_HDR_SIZE] " + "[-D LINK-DST-ADDR] [-t TARGET_ADDR[/LEN]] [-r] [-c] [-o] [-E " + "LINK_ADDR] [-e] " + "[-j PREFIX[/LEN]] [-k PREFIX[/LEN]] [-J LINK_ADDR] [-K LINK_ADDR] [-w " + "PREFIX[/LEN]] " + "[-b PREFIX[/LEN]] [-g PREFIX[/LEN]] [-B LINK_ADDR] [-G LINK_ADDR] [-W " + "PREFIX[/LEN]] " + "[-F N_SOURCES] [-T N_TARGETS] [-L | -l] [-z] [-v] [-V] [-h]"); } - /* * Function: print_help() * * Prints help information for the na6 tool */ -void print_help(void){ - puts(SI6_TOOLKIT); - puts("na6: Security Assessment tool for attack vectors based on NA messages\n"); - usage(); - +void print_help(void) { + puts(SI6_TOOLKIT); + puts("na6: Security Assessment tool for attack vectors based on NA " + "messages\n"); + usage(); + puts("\nOPTIONS:\n" - " --interface, -i Network interface\n" - " --src-addr, -s IPv6 Source Address\n" - " --dst-addr, -d IPv6 Destination Address\n" - " --frag-hdr. -y Fragment Header\n" - " --dst-opt-hdr, -u Destination Options Header (Fragmentable Part)\n" - " --dst-opt-u-hdr, -U Destination Options Header (Unfragmentable Part)\n" - " --hbh-opt-hdr, -H Hop by Hop Options Header\n" - " --link-src-addr, -S Link-layer Destination Address\n" - " --link-dst-addr, -D Link-layer Source Address\n" - " --target, -t ND IPv6 Target Address\n" - " --target-lla-opt, -E Source link-layer address option\n" - " --add-tlla-opt, -e Add Source link-layer address option\n" - " --router, -r Set the 'Router Flag'\n" - " --solicited, -c Set the 'Solicited' flag\n" - " --override, -o Set the 'Override' flag\n" - " --block-src, -j Block IPv6 Source Address prefix\n" - " --block-dst, -k Block IPv6 Destination Address prefix\n" - " --block-link-src, -J Block Ethernet Source Address\n" - " --block-link-dst, -K Block Ethernet Destination Address\n" - " --block-target, -w Block ND Target IPv6 prefix\n" - " --accept-src, -b Accept IPv6 Source Address prefix\n" - " --accept-dst, -g Accept IPv6 Destination Address prefix\n" - " --accept-link-src, -B Accept Ethernet Source Address\n" - " --accept-link-dst, -G Accept Ethernet Destination Address\n" - " --accept-target, -W Accept ND Target IPv6 prefix\n" - " --flood-targets, -T Flood with NA's for multiple Target Addresses\n" - " --flood-sources, -F Number of Source Addresses to forge randomly\n" - " --listen, -L Listen to Neighbor Solicitation messages\n" - " --loop, -l Send periodic Neighbor Advertisements\n" - " --sleep, -z Pause between sending NA messages\n" - " --help, -h Print help for the na6 tool\n" - " --verbose, -v Be verbose\n" - "\n" - "Programmed by Fernando Gont for SI6 Networks \n" - "Please send any bug reports to \n" - ); + " --interface, -i Network interface\n" + " --src-addr, -s IPv6 Source Address\n" + " --dst-addr, -d IPv6 Destination Address\n" + " --frag-hdr. -y Fragment Header\n" + " --dst-opt-hdr, -u Destination Options Header (Fragmentable " + "Part)\n" + " --dst-opt-u-hdr, -U Destination Options Header " + "(Unfragmentable Part)\n" + " --hbh-opt-hdr, -H Hop by Hop Options Header\n" + " --link-src-addr, -S Link-layer Destination Address\n" + " --link-dst-addr, -D Link-layer Source Address\n" + " --target, -t ND IPv6 Target Address\n" + " --target-lla-opt, -E Source link-layer address option\n" + " --add-tlla-opt, -e Add Source link-layer address option\n" + " --router, -r Set the 'Router Flag'\n" + " --solicited, -c Set the 'Solicited' flag\n" + " --override, -o Set the 'Override' flag\n" + " --block-src, -j Block IPv6 Source Address prefix\n" + " --block-dst, -k Block IPv6 Destination Address prefix\n" + " --block-link-src, -J Block Ethernet Source Address\n" + " --block-link-dst, -K Block Ethernet Destination Address\n" + " --block-target, -w Block ND Target IPv6 prefix\n" + " --accept-src, -b Accept IPv6 Source Address prefix\n" + " --accept-dst, -g Accept IPv6 Destination Address prefix\n" + " --accept-link-src, -B Accept Ethernet Source Address\n" + " --accept-link-dst, -G Accept Ethernet Destination Address\n" + " --accept-target, -W Accept ND Target IPv6 prefix\n" + " --flood-targets, -T Flood with NA's for multiple Target " + "Addresses\n" + " --flood-sources, -F Number of Source Addresses to forge " + "randomly\n" + " --listen, -L Listen to Neighbor Solicitation " + "messages\n" + " --loop, -l Send periodic Neighbor Advertisements\n" + " --sleep, -z Pause between sending NA messages\n" + " --help, -h Print help for the na6 tool\n" + " --verbose, -v Be verbose\n" + "\n" + "Programmed by Fernando Gont for SI6 Networks " + "\n" + "Please send any bug reports to \n"); } - /* * Function: print_attack_info() * * Prints attack details (when the verbose ("-v") option is specified). */ - -void print_attack_info(struct iface_data *idata){ - if(floods_f) - printf("Flooding the target from %u different IPv6 Source Addresses\n", nsources); - - if(floodt_f) - printf("Flooding the target with %u ND Target Addresses\n", ntargets); - - if(!floods_f){ - if(ether_ntop(&(idata->hsrcaddr), plinkaddr, sizeof(plinkaddr)) == 0){ - puts("ether_ntop(): Error converting address"); - exit(EXIT_FAILURE); - } - - printf("Ethernet Source Address: %s%s\n", plinkaddr, ((!idata->hsrcaddr_f)?" (automatically-selected)":"")); - } - else{ - if(idata->hsrcaddr_f){ - if(ether_ntop(&(idata->hsrcaddr), plinkaddr, sizeof(plinkaddr)) == 0){ - puts("ether_ntop(): Error converting address"); - exit(EXIT_FAILURE); - } - - printf("Ethernet Source Address: %s\n", plinkaddr); - } - else - puts("Ethernet Source Address: automatically-selected"); - } - - /* - Ethernet Destination Address only used if a IPv6 Destination Address or an - Ethernet Destination Address were specified. - */ - if(idata->dstaddr_f || idata->hdstaddr_f){ - if(ether_ntop(&(idata->hdstaddr), plinkaddr, sizeof(plinkaddr)) == 0){ - puts("ether_ntop(): Error converting address"); - exit(EXIT_FAILURE); - } - - printf("Ethernet Destination Address: %s%s\n", plinkaddr, \ - ((!idata->hdstaddr_f)?" (all-nodes multicast)":"")); + +void print_attack_info(struct iface_data *idata) { + if (floods_f) + printf("Flooding the target from %u different IPv6 Source Addresses\n", nsources); + + if (floodt_f) + printf("Flooding the target with %u ND Target Addresses\n", ntargets); + + if (!floods_f) { + if (ether_ntop(&(idata->hsrcaddr), plinkaddr, sizeof(plinkaddr)) == 0) { + puts("ether_ntop(): Error converting address"); + exit(EXIT_FAILURE); + } + + printf("Ethernet Source Address: %s%s\n", plinkaddr, ((!idata->hsrcaddr_f) ? " (automatically-selected)" : "")); + } + else { + if (idata->hsrcaddr_f) { + if (ether_ntop(&(idata->hsrcaddr), plinkaddr, sizeof(plinkaddr)) == 0) { + puts("ether_ntop(): Error converting address"); + exit(EXIT_FAILURE); + } + + printf("Ethernet Source Address: %s\n", plinkaddr); + } + else + puts("Ethernet Source Address: automatically-selected"); } + /* + Ethernet Destination Address only used if a IPv6 Destination Address or + an Ethernet Destination Address were specified. + */ + if (idata->dstaddr_f || idata->hdstaddr_f) { + if (ether_ntop(&(idata->hdstaddr), plinkaddr, sizeof(plinkaddr)) == 0) { + puts("ether_ntop(): Error converting address"); + exit(EXIT_FAILURE); + } + + printf("Ethernet Destination Address: %s%s\n", plinkaddr, + ((!idata->hdstaddr_f) ? " (all-nodes multicast)" : "")); + } - if(inet_ntop(AF_INET6, &(idata->srcaddr), psrcaddr, sizeof(psrcaddr)) == NULL){ - puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); - exit(EXIT_FAILURE); + if (inet_ntop(AF_INET6, &(idata->srcaddr), psrcaddr, sizeof(psrcaddr)) == NULL) { + puts("inet_ntop(): Error converting IPv6 Source Address to presentation " + "format"); + exit(EXIT_FAILURE); } - if(!floods_f && !(idata->srcprefix_f)){ - printf("IPv6 Source Address: %s%s\n", psrcaddr, ((!idata->srcaddr_f)?" (automatically-selected)":"")); + if (!floods_f && !(idata->srcprefix_f)) { + printf("IPv6 Source Address: %s%s\n", psrcaddr, ((!idata->srcaddr_f) ? " (automatically-selected)" : "")); } - else{ - printf("IPv6 Source Address: randomized, from the %s/%u prefix%s\n", psrcaddr, idata->srcpreflen, \ - (!idata->srcprefix_f)?" (default)":""); + else { + printf("IPv6 Source Address: randomized, from the %s/%u prefix%s\n", psrcaddr, idata->srcpreflen, + (!idata->srcprefix_f) ? " (default)" : ""); } - /* IPv6 Destination Address is only used if a target IPv6 address or a target Ethernet - * address were specified + /* IPv6 Destination Address is only used if a target IPv6 address or a + * target Ethernet address were specified */ - if(idata->dstaddr_f || idata->hdstaddr_f){ - if(inet_ntop(AF_INET6, &(idata->dstaddr), pdstaddr, sizeof(pdstaddr)) == NULL){ - puts("inet_ntop(): Error converting IPv6 Destination Address to presentation format"); - exit(EXIT_FAILURE); - } - - printf("IPv6 Destination Address: %s%s\n", pdstaddr, \ - ((!idata->dstaddr_f)?" (all-nodes link-local multicast)":"")); + if (idata->dstaddr_f || idata->hdstaddr_f) { + if (inet_ntop(AF_INET6, &(idata->dstaddr), pdstaddr, sizeof(pdstaddr)) == NULL) { + puts("inet_ntop(): Error converting IPv6 Destination Address to " + "presentation format"); + exit(EXIT_FAILURE); + } + + printf("IPv6 Destination Address: %s%s\n", pdstaddr, + ((!idata->dstaddr_f) ? " (all-nodes link-local multicast)" : "")); } - printf("IPv6 Hop Limit: %u%s\n", hoplimit, (hoplimit_f)?"":" (default)"); + printf("IPv6 Hop Limit: %u%s\n", hoplimit, (hoplimit_f) ? "" : " (default)"); - for(i=0; ifragh_f) - printf("Sending each packet in fragments of %u bytes (plus the Unfragmentable part)\n", nfrags); + if (idata->fragh_f) + printf("Sending each packet in fragments of %u bytes (plus the " + "Unfragmentable part)\n", + nfrags); - if(!floodt_f){ - if(targetaddr_f){ - if(inet_ntop(AF_INET6, &targetaddr, pv6addr, sizeof(pv6addr)) == NULL){ - puts("inet_ntop(): Error converting ND IPv6 Target Address to presentation format"); - exit(EXIT_FAILURE); - } + if (!floodt_f) { + if (targetaddr_f) { + if (inet_ntop(AF_INET6, &targetaddr, pv6addr, sizeof(pv6addr)) == NULL) { + puts("inet_ntop(): Error converting ND IPv6 Target Address to " + "presentation format"); + exit(EXIT_FAILURE); + } - printf("ND Target Address: %s\n", pv6addr); - } + printf("ND Target Address: %s\n", pv6addr); + } } - else{ - if(inet_ntop(AF_INET6, &targetaddr, pv6addr, sizeof(pv6addr)) == NULL){ - puts("inet_ntop(): Error converting ND IPv6 Target Address to presentation format"); - exit(EXIT_FAILURE); - } - - printf("ND Target Address: randomized, from the %s/%u prefix%s\n", pv6addr, targetpreflen,\ - (!targetprefix_f)?" (default)":""); - } - - printf("Flags: %s%s%s%s\n", ((router_f)?"R":""), ((solicited_f)?"S":""), ((override_f)?"O":""),\ - ((!router_f && !solicited_f && !override_f)?"none":"")); - - for(i=0;i Address: %s\n", \ - ((floods_f && !tllaopta_f)?"(randomized for each packet)":plinkaddr)); + else { + if (inet_ntop(AF_INET6, &targetaddr, pv6addr, sizeof(pv6addr)) == NULL) { + puts("inet_ntop(): Error converting ND IPv6 Target Address to " + "presentation format"); + exit(EXIT_FAILURE); + } + + printf("ND Target Address: randomized, from the %s/%u prefix%s\n", pv6addr, targetpreflen, + (!targetprefix_f) ? " (default)" : ""); } -} + printf("Flags: %s%s%s%s\n", ((router_f) ? "R" : ""), ((solicited_f) ? "S" : ""), ((override_f) ? "O" : ""), + ((!router_f && !solicited_f && !override_f) ? "none" : "")); + for (i = 0; i < nlinkaddr; i++) { + if (ether_ntop(&linkaddr[i], plinkaddr, sizeof(plinkaddr)) == 0) { + puts("ether_ntop(): Error converting address"); + exit(EXIT_FAILURE); + } + + printf("Target Link-layer Address option -> Address: %s\n", + ((floods_f && !tllaopta_f) ? "(randomized for each packet)" : plinkaddr)); + } +} diff --git a/tools/na6.h b/tools/na6.h index 6511244..5b1dcbc 100644 --- a/tools/na6.h +++ b/tools/na6.h @@ -2,5 +2,3 @@ * Header file for the na6 tool * */ - - diff --git a/tools/ni6.c b/tools/ni6.c index 13c1e1f..19d0371 100644 --- a/tools/ni6.c +++ b/tools/ni6.c @@ -18,1318 +18,1295 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . - * + * * Build with: make ni6 - * + * * It requires that the libpcap library be installed on your system. * * Please send any bug reports to Fernando Gont */ -#include #include #include +#include #include +#include +#include #include +#include #include #include -#include -#include -#include +#include +#include #include #include -#include #include -#include -#include +#include +#include #include +#include +#include #include -#include #include -#include -#include -#include "ni6.h" #include "ipv6toolkit.h" #include "libipv6.h" - +#include "ni6.h" /* Function prototypes */ -void init_packet_data(struct iface_data *); -int send_packet(struct iface_data *, const u_char *, struct pcap_pkthdr *); -void print_attack_info(struct iface_data *); -void usage(void); -void print_help(void); -int print_ni_data(struct iface_data *, const u_char *, struct pcap_pkthdr *); -int print_ni_addr(struct iface_data *, const u_char *, struct pcap_pkthdr *); -int print_ni_addr6(struct iface_data *, const u_char *, struct pcap_pkthdr *); -int print_ni_name(struct iface_data *, const u_char *, struct pcap_pkthdr *); -int print_ni_noop(struct iface_data *, const u_char *, struct pcap_pkthdr *); - +void init_packet_data(struct iface_data *); +int send_packet(struct iface_data *, const u_char *, struct pcap_pkthdr *); +void print_attack_info(struct iface_data *); +void usage(void); +void print_help(void); +int print_ni_data(struct iface_data *, const u_char *, struct pcap_pkthdr *); +int print_ni_addr(struct iface_data *, const u_char *, struct pcap_pkthdr *); +int print_ni_addr6(struct iface_data *, const u_char *, struct pcap_pkthdr *); +int print_ni_name(struct iface_data *, const u_char *, struct pcap_pkthdr *); +int print_ni_noop(struct iface_data *, const u_char *, struct pcap_pkthdr *); /* Variables used for learning the default router */ -struct iface_data idata; -struct ether_addr rs_ether; -struct in6_addr rs_ipv6; -struct in6_addr randprefix; -unsigned char randpreflen; - +struct iface_data idata; +struct ether_addr rs_ether; +struct in6_addr rs_ipv6; +struct in6_addr randprefix; +unsigned char randpreflen; /* Data structures for packets read from the wire */ -struct pcap_pkthdr *pkthdr; -const u_char *pktdata; -unsigned char *pkt_end; -struct ether_header *pkt_ether; -struct ip6_hdr *pkt_ipv6; -struct in6_addr *pkt_ipv6addr; +struct pcap_pkthdr *pkthdr; +const u_char *pktdata; +unsigned char *pkt_end; +struct ether_header *pkt_ether; +struct ip6_hdr *pkt_ipv6; +struct in6_addr *pkt_ipv6addr; struct icmp6_nodeinfo *pkt_ni; -unsigned int pktbytes; - - -bpf_u_int32 my_netmask; -bpf_u_int32 my_ip; -struct bpf_program pcap_filter; -char dev[64], errbuf[PCAP_ERRBUF_SIZE]; -unsigned char buffer[65556], buffrh[MIN_IPV6_HLEN + MIN_TCP_HLEN]; -char domain[MAX_DOMAIN_LEN]; -unsigned char *v6buffer, *ptr, *startofprefixes; -char *pref; - -struct ip6_hdr *ipv6; -struct icmp6_hdr *icmp6; +unsigned int pktbytes; + +bpf_u_int32 my_netmask; +bpf_u_int32 my_ip; +struct bpf_program pcap_filter; +char dev[64], errbuf[PCAP_ERRBUF_SIZE]; +unsigned char buffer[65556], buffrh[MIN_IPV6_HLEN + MIN_TCP_HLEN]; +char domain[MAX_DOMAIN_LEN]; +unsigned char *v6buffer, *ptr, *startofprefixes; +char *pref; + +struct ip6_hdr *ipv6; +struct icmp6_hdr *icmp6; struct icmp6_nodeinfo *ni; -struct ether_header *ethernet; +struct ether_header *ethernet; -char *lasts, *rpref; -char *charptr, *printname, *printnamed; +char *lasts, *rpref; +char *charptr, *printname, *printnamed; -int nw; -unsigned long ul_res, ul_val; -unsigned int i, j, startrand; -unsigned int skip; -unsigned int nsleep; -unsigned char srcpreflen; +int nw; +unsigned long ul_res, ul_val; +unsigned int i, j, startrand; +unsigned int skip; +unsigned int nsleep; +unsigned char srcpreflen; -uint16_t mask; -uint8_t hoplimit; +uint16_t mask; +uint8_t hoplimit; -char plinkaddr[ETHER_ADDR_PLEN]; -char psrcaddr[INET6_ADDRSTRLEN], pdstaddr[INET6_ADDRSTRLEN], pv6addr[INET6_ADDRSTRLEN]; -unsigned char iface_f=0; -unsigned char rand_src_f=0, forgeether_f=0; -unsigned char listen_f = 0, multicastdst_f=0, accepted_f=0, loop_f=0, sleep_f=0; -unsigned char srcprefix_f=0, hoplimit_f=0, flags_f=0, exceedp_f=0, snamedslabel_f=0; -unsigned char floods_f=0, name_f=0, fname_f=0, ipv6addr_f=0, ipv4addr_f=0, maxlabel_f=0; -unsigned char named_f=0, fnamed_f=0, ipv6addrd_f=0, ipv4addrd_f=0, exceedpd_f=0; -unsigned char payloadsize_f=0, qtype_f=0, code_f=0, snameslabel_f=0, sloopattack_f=0; -unsigned char dloopattack_f=0; +char plinkaddr[ETHER_ADDR_PLEN]; +char psrcaddr[INET6_ADDRSTRLEN], pdstaddr[INET6_ADDRSTRLEN], pv6addr[INET6_ADDRSTRLEN]; +unsigned char iface_f = 0; +unsigned char rand_src_f = 0, forgeether_f = 0; +unsigned char listen_f = 0, multicastdst_f = 0, accepted_f = 0, loop_f = 0, sleep_f = 0; +unsigned char srcprefix_f = 0, hoplimit_f = 0, flags_f = 0, exceedp_f = 0, snamedslabel_f = 0; +unsigned char floods_f = 0, name_f = 0, fname_f = 0, ipv6addr_f = 0, ipv4addr_f = 0, maxlabel_f = 0; +unsigned char named_f = 0, fnamed_f = 0, ipv6addrd_f = 0, ipv4addrd_f = 0, exceedpd_f = 0; +unsigned char payloadsize_f = 0, qtype_f = 0, code_f = 0, snameslabel_f = 0, sloopattack_f = 0; +unsigned char dloopattack_f = 0; /* Support for Extension Headers */ -unsigned int dstopthdrs, dstoptuhdrs, hbhopthdrs; -char hbhopthdr_f=0, dstoptuhdr_f=0, dstopthdr_f=0; -unsigned char *dstopthdr[MAX_DST_OPT_HDR], *dstoptuhdr[MAX_DST_OPT_U_HDR]; -unsigned char *hbhopthdr[MAX_HBH_OPT_HDR]; -unsigned int dstopthdrlen[MAX_DST_OPT_HDR], dstoptuhdrlen[MAX_DST_OPT_U_HDR]; -unsigned int hbhopthdrlen[MAX_HBH_OPT_HDR], m, pad; - -struct ip6_frag fraghdr, *fh; -struct ip6_hdr *fipv6; -unsigned char fragbuffer[ETHER_HDR_LEN+MIN_IPV6_HLEN+MAX_IPV6_PAYLOAD]; -unsigned char *fragpart, *fptr, *fptrend, *ptrend, *ptrhdr, *ptrhdrend; -unsigned int hdrlen, ndstopthdr=0, nhbhopthdr=0, ndstoptuhdr=0; -unsigned int nfrags, fragsize; -unsigned char *prev_nh, *startoffragment; +unsigned int dstopthdrs, dstoptuhdrs, hbhopthdrs; +char hbhopthdr_f = 0, dstoptuhdr_f = 0, dstopthdr_f = 0; +unsigned char *dstopthdr[MAX_DST_OPT_HDR], *dstoptuhdr[MAX_DST_OPT_U_HDR]; +unsigned char *hbhopthdr[MAX_HBH_OPT_HDR]; +unsigned int dstopthdrlen[MAX_DST_OPT_HDR], dstoptuhdrlen[MAX_DST_OPT_U_HDR]; +unsigned int hbhopthdrlen[MAX_HBH_OPT_HDR], m, pad; + +struct ip6_frag fraghdr, *fh; +struct ip6_hdr *fipv6; +unsigned char fragbuffer[ETHER_HDR_LEN + MIN_IPV6_HLEN + MAX_IPV6_PAYLOAD]; +unsigned char *fragpart, *fptr, *fptrend, *ptrend, *ptrhdr, *ptrhdrend; +unsigned int hdrlen, ndstopthdr = 0, nhbhopthdr = 0, ndstoptuhdr = 0; +unsigned int nfrags, fragsize; +unsigned char *prev_nh, *startoffragment; /* ICMPv6 NI */ -struct in_addr ipv4addr, ipv4addrd; -struct in6_addr ipv6addr, ipv6addrd; -unsigned int maxlabel, slvariant, slsize, dlvariant, dlsize; -char *name, *named; -unsigned int fnamelen, exceedp, fnamedlen, exceedpd, payloadsize; -int namelen, namedlen; -uint8_t qtype, type; -uint8_t code=0; -uint16_t flags=0; -unsigned char *slpointer, *dlpointer; - -struct filters filters; - - -int main(int argc, char **argv){ - extern char *optarg; - int r, sel; - fd_set sset, rset; - time_t curtime, lastni=0, start=0; - struct timeval timeout; - struct target_ipv6 targetipv6; - - /* For queries only: loops to the beginning of the same label (shouldn't work) */ - unsigned char dnsloopq0[]={0x04, 0x61, 0x61, 0x61, 0x61, 0x0c, 0x00}; - /* For queries only: loops on a single byte label (shouldn't work) */ - unsigned char dnsloopq1[]={0x04, 0x61, 0x61, 0x61, 0x61, 0x0c, 0x05}; - - /* Loops to the beginning of the same label */ - unsigned char dnsloopr0[]={0x04, 0x61, 0x61, 0x61, 0x61, 0x0c, 0x04}; - /* Loops on a single byte */ - unsigned char dnsloopr1[]={0x04, 0x61, 0x61 , 0x61, 0x61, 0x0c, 0x09}; - /* Loops to the beginning of a previous label */ - unsigned char dnsloopr2[]={0x04, 0x61, 0x61, 0x61, 0x61, 0x00, 0x03, 0x61 , 0x61, 0x61, 0x0c, 0x04}; - - static struct option longopts[] = { - {"interface", required_argument, 0, 'i'}, - {"src-addr", required_argument, 0, 's'}, - {"dst-addr", required_argument, 0, 'd'}, - {"hop-limit", required_argument, 0, 'c'}, - {"dst-opt-hdr", required_argument, 0, 'u'}, - {"dst-opt-u-hdr", required_argument, 0, 'U'}, - {"hbh-opt-hdr", required_argument, 0, 'H'}, - {"frag-hdr", required_argument, 0, 'y'}, - {"link-src-addr", required_argument, 0, 'S'}, - {"link-dst-addr", required_argument, 0, 'D'}, - {"payload-size", required_argument, 0, 'P'}, - {"subject-ipv4", required_argument, 0, '4'}, - {"subject-ipv6", required_argument, 0, '6'}, - {"subject-name", required_argument, 0, 'n'}, - {"subject-fname", required_argument, 0, 'N'}, - {"subject-ename", required_argument, 0, 'x'}, - {"subject-nloop", required_argument, 0, 'o'}, - {"max-label-size", required_argument, 0, 'Z'}, - {"sname-slabel", no_argument, 0, 'e'}, - {"code", required_argument, 0, 'C'}, - {"qtype", required_argument, 0, 'q'}, - {"flags", required_argument, 0, 'X'}, - {"data-ipv6", required_argument, 0, 'w'}, - {"data-ipv4", required_argument, 0, 'W'}, - {"data-name", required_argument, 0, 'a'}, - {"data-fname", required_argument, 0, 'A'}, - {"data-ename", required_argument, 0, 'Q'}, - {"data-nloop", required_argument, 0, 'O'}, - {"dname-slabel", no_argument, 0, 'E'}, - {"block-src-addr", required_argument, 0, 'j'}, - {"block-dst-addr", required_argument, 0, 'k'}, - {"block-link-src-addr", required_argument, 0, 'J'}, - {"block-link-dst-addr", required_argument, 0, 'K'}, - {"accept-src-addr", required_argument, 0, 'b'}, - {"accept-dst-addr", required_argument, 0, 'g'}, - {"accept-link-src-addr", required_argument, 0, 'B'}, - {"accept-link-dst-addr", required_argument, 0, 'G'}, - {"forge-src-addr", no_argument, 0, 'r'}, - {"forge-link-src-addr", no_argument, 0, 'R'}, - {"loop", no_argument, 0, 'l'}, - {"sleep", required_argument, 0, 'z'}, - {"listen", no_argument, 0, 'L'}, - {"verbose", no_argument, 0, 'v'}, - {"help", no_argument, 0, 'h'}, - {0, 0, 0, 0 } - }; - - char shortopts[]= "i:s:d:c:u:U:H:y:S:D:P:4:6:n:N:x:o:Z:eC:q:X:w:W:a:A:Q:O:Ej:k:J:K:b:g:B:G:lz:Lvh"; - - char option; - - if(argc<=1){ - usage(); - exit(EXIT_FAILURE); - } - - srandom(time(NULL)); - hoplimit=64+random()%180; - - /* Initialize filters structure */ - if(init_filters(&filters) == -1){ - puts("Error initializing internal data structure"); - exit(EXIT_FAILURE); - } - - if(init_iface_data(&idata) == FAILURE){ - puts("Error initializing internal data structure"); - exit(EXIT_FAILURE); - } - - while((r=getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { - option= r; - - switch(option){ - case 'i': /* Interface */ - strncpy(idata.iface, optarg, IFACE_LENGTH-1); - idata.iface[IFACE_LENGTH-1]=0; - idata.ifindex= if_nametoindex(idata.iface); - idata.iface_f=TRUE; - break; - - case 's': /* IPv6 Source Address */ - if((charptr = strtok_r(optarg, "/", &lasts)) == NULL){ - puts("Error in Source Address"); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, charptr, &(idata.srcaddr)) <= 0){ - puts("inet_pton(): Source Address not valid"); - exit(EXIT_FAILURE); - } - - idata.srcaddr_f = 1; - - if((charptr = strtok_r(NULL, " ", &lasts)) != NULL){ - srcpreflen = atoi(charptr); - - if(srcpreflen>128){ - puts("Prefix length error in IPv6 Source Address"); - exit(EXIT_FAILURE); - } - - sanitize_ipv6_prefix(&(idata.srcaddr), srcpreflen); - srcprefix_f=1; - } - - break; - - case 'd': /* IPv6 Destination Address */ - strncpy( targetipv6.name, optarg, NI_MAXHOST); - targetipv6.name[NI_MAXHOST-1]= 0; - targetipv6.flags= AI_CANONNAME; - - if( (r=get_ipv6_target(&targetipv6)) != 0){ - - if(r < 0){ - printf("Unknown Destination: %s\n", gai_strerror(targetipv6.res)); - } - else{ - puts("Unknown Destination: No IPv6 address found for specified destination"); - } - - exit(EXIT_FAILURE); - } - - idata.dstaddr= targetipv6.ip6; - idata.dstaddr_f = TRUE; - type= ICMP6_NI_QUERY; - break; - - case 'c': /* Hop Limit */ - hoplimit= atoi(optarg); - hoplimit_f=1; - break; - - case 'u': /* Destinations Options Header */ - if(ndstopthdr >= MAX_DST_OPT_HDR){ - puts("Too many Destination Options Headers"); - exit(EXIT_FAILURE); - } - - hdrlen= atoi(optarg); - - if(hdrlen < 8){ - puts("Bad length in Destination Options Header"); - exit(EXIT_FAILURE); - } - - hdrlen = ((hdrlen+7)/8) * 8; - dstopthdrlen[ndstopthdr]= hdrlen; - - if( (dstopthdr[ndstopthdr]= malloc(hdrlen)) == NULL){ - puts("Not enough memory for Destination Options Header"); - exit(EXIT_FAILURE); - } - - ptrhdr= dstopthdr[ndstopthdr] + 2; - ptrhdrend= dstopthdr[ndstopthdr] + hdrlen; - - while( ptrhdr < ptrhdrend){ - - if( (ptrhdrend-ptrhdr)>257) - pad= 257; - else - pad= ptrhdrend-ptrhdr; - - if(!insert_pad_opt(ptrhdr, ptrhdrend, pad)){ - puts("Destination Options Header Too Big"); - exit(EXIT_FAILURE); - } - - ptrhdr= ptrhdr + pad; - } - - *(dstopthdr[ndstopthdr]+1)= (hdrlen/8)-1; - ndstopthdr++; - dstopthdr_f=1; - break; - - case 'U': /* Destination Options Header (Unfragmentable Part) */ - if(ndstoptuhdr >= MAX_DST_OPT_U_HDR){ - puts("Too many Destination Options Headers (Unfragmentable Part)"); - exit(EXIT_FAILURE); - } - - hdrlen= atoi(optarg); - - if(hdrlen < 8){ - puts("Bad length in Destination Options Header (Unfragmentable Part)"); - exit(EXIT_FAILURE); - } - - hdrlen = ((hdrlen+7)/8) * 8; - dstoptuhdrlen[ndstoptuhdr]= hdrlen; - - if( (dstoptuhdr[ndstoptuhdr]= malloc(hdrlen)) == NULL){ - puts("Not enough memory for Destination Options Header (Unfragmentable Part)"); - exit(EXIT_FAILURE); - } - - ptrhdr= dstoptuhdr[ndstoptuhdr]+2; - ptrhdrend= dstoptuhdr[ndstoptuhdr] + hdrlen; - - while( ptrhdr < ptrhdrend){ - - if( (ptrhdrend-ptrhdr)>257) - pad= 257; - else - pad= ptrhdrend-ptrhdr; - - if(!insert_pad_opt(ptrhdr, ptrhdrend, pad)){ - puts("Destination Options Header (Unfragmentable Part) Too Big"); - exit(EXIT_FAILURE); - } - - ptrhdr = ptrhdr + pad; - } - - *(dstoptuhdr[ndstoptuhdr]+1)= (hdrlen/8) - 1; - ndstoptuhdr++; - dstoptuhdr_f=1; - break; - - case 'H': /* Hop-by-Hop Options Header */ - if(nhbhopthdr >= MAX_HBH_OPT_HDR){ - puts("Too many Hop-by-Hop Options Headers"); - exit(EXIT_FAILURE); - } - - hdrlen= atoi(optarg); - - if(hdrlen < 8){ - puts("Bad length in Hop-by-Hop Options Header"); - exit(EXIT_FAILURE); - } - - hdrlen = ((hdrlen+7)/8) * 8; - hbhopthdrlen[nhbhopthdr]= hdrlen; - - if( (hbhopthdr[nhbhopthdr]= malloc(hdrlen)) == NULL){ - puts("Not enough memory for Hop-by-Hop Options Header"); - exit(EXIT_FAILURE); - } - - ptrhdr= hbhopthdr[nhbhopthdr] + 2; - ptrhdrend= hbhopthdr[nhbhopthdr] + hdrlen; - - - while( ptrhdr < ptrhdrend){ - if( (ptrhdrend-ptrhdr)>257) - pad= 257; - else - pad= ptrhdrend-ptrhdr; - - if(!insert_pad_opt(ptrhdr, ptrhdrend, pad)){ - puts("Hop-by-Hop Options Header Too Big"); - exit(EXIT_FAILURE); - } - - ptrhdr = ptrhdr + pad; - } - - *(hbhopthdr[nhbhopthdr]+1)= (hdrlen/8) - 1; - nhbhopthdr++; - hbhopthdr_f=1; - break; - - case 'y': /* Fragment header */ - nfrags= atoi(optarg); - if(nfrags < 8){ - puts("Error in Fragmentation option: Fragment Size must be at least 8 bytes"); - exit(EXIT_FAILURE); - } - - idata.fragh_f= 1; - break; - - case 'S': /* Source Ethernet address */ - if(ether_pton(optarg, &(idata.hsrcaddr), sizeof(idata.hsrcaddr)) == 0){ - puts("Error in Source link-layer address."); - exit(EXIT_FAILURE); - } - - idata.hsrcaddr_f = 1; - break; - - case 'D': /* Destination Ethernet Address */ - if(ether_pton(optarg, &(idata.hdstaddr), sizeof(idata.hdstaddr)) == 0){ - puts("Error in Source link-layer address."); - exit(EXIT_FAILURE); - } - - idata.hdstaddr_f = 1; - break; - - case '6': /* Subject: IPv6 address */ - strncpy( targetipv6.name, optarg, NI_MAXHOST); - targetipv6.name[NI_MAXHOST-1]= 0; - targetipv6.flags= AI_CANONNAME; - - if( (r=get_ipv6_target(&targetipv6)) != 0){ - - if(r < 0){ - printf("Unknown Destination: %s\n", gai_strerror(targetipv6.res)); - } - else{ - puts("Unknown Destination: No IPv6 address found for specified destination"); - } - - exit(EXIT_FAILURE); - } - - ipv6addr= targetipv6.ip6; - ipv6addr_f = 1; - break; - - case '4': /* Subject: IPv4 address */ - - if( inet_pton(AF_INET, optarg, &ipv4addr) <= 0){ - puts("inet_pton(): Subject Address not valid"); - exit(EXIT_FAILURE); - } - - ipv4addr_f = 1; - break; - - case 'n': /* Subject: Name */ - printname= optarg; - namelen= strlen(optarg) + 1; - - - if( (name=malloc(namelen + 1)) == NULL){ - puts("Error allocating memory"); - exit(EXIT_FAILURE); - } - - if( (namelen=dns_str2wire(optarg, namelen, name, namelen+1)) == -1){ - puts("inet_pton(): Error while converting name to DNS wire format"); - exit(EXIT_FAILURE); - } - - name_f = 1; - break; - - case 'N': /* Subject: Name of an arbitrary length */ - fnamelen= atoi(optarg); - fname_f= 1; - break; - - case 'x': /* Subject: DNS wire label that exceeeds packet size */ - exceedp= atoi(optarg); - exceedp_f= 1; - break; - - case 'o': - slvariant=atoi(optarg); - sloopattack_f=1; - break; - - case 'P': /* Payload Size */ - payloadsize= atoi(optarg); - payloadsize_f= 1; - break; - - case 'w': /* Data: IPv6 address */ - strncpy( targetipv6.name, optarg, NI_MAXHOST); - targetipv6.name[NI_MAXHOST-1]= 0; - targetipv6.flags= AI_CANONNAME; - - if( (r=get_ipv6_target(&targetipv6)) != 0){ - - if(r < 0){ - printf("Unknown Destination: %s\n", gai_strerror(targetipv6.res)); - } - else{ - puts("Unknown Destination: No IPv6 address found for specified destination"); - } - - exit(EXIT_FAILURE); - } - - ipv6addrd= targetipv6.ip6; - ipv6addrd_f = 1; - break; - - case 'W': /* Data: IPv4 address */ - - if( inet_pton(AF_INET, optarg, &ipv4addrd) <= 0){ - puts("inet_pton(): Redirected Address not valid"); - exit(EXIT_FAILURE); - } - - ipv4addrd_f = 1; - break; - - case 'a': /* Data: Name */ - printnamed= optarg; - namedlen= strlen(optarg) + 1; - - if( (named=malloc(namedlen + 1)) == NULL){ - puts("Error allocating memory"); - exit(EXIT_FAILURE); - } - - if( (namedlen=dns_str2wire(optarg, namedlen, named, namedlen+1)) == -1){ - puts("inet_pton(): Error while converting name to DNS wire format"); - exit(EXIT_FAILURE); - } - - named_f = 1; - break; - - case 'A': /* Data: Name of an arbitrary length */ - fnamedlen= atoi(optarg); - fnamed_f= 1; - break; - - case 'Q': /* Data: DNS wire label that exceeeds packet size */ - exceedpd= atoi(optarg); - exceedpd_f= 1; - break; - - case 'O': - dlvariant=atoi(optarg); - dloopattack_f=1; - break; - - case 'E': /* Data is a Single label name */ - snamedslabel_f=1; - break; - - case 'Z': /* Max DNS label size (defaults to 63) */ - maxlabel= atoi(optarg); - - if(maxlabel < 1){ - puts("Error: max-label-size too small"); - exit(EXIT_FAILURE); - } - - maxlabel_f= 1; - break; - - case 'e': /* Subject is a Single label name */ - snameslabel_f=1; - break; - - case 'C': /* ICMPv6 code */ - code= atoi(optarg); - code_f= 1; - break; - - case 'q': /* Qtype */ - qtype= atoi(optarg); - qtype_f= 1; - break; - - case 'X': - charptr = optarg; - while(*charptr){ - switch(*charptr){ - case 'G': - flags= flags | NI_NODEADDR_FLAG_GLOBAL; - break; - - case 'S': - flags= flags | NI_NODEADDR_FLAG_SITELOCAL; - break; - - case 'L': - flags= flags | NI_NODEADDR_FLAG_LINKLOCAL; - break; - - case 'C': - flags= flags | NI_NODEADDR_FLAG_COMPAT; - break; - - case 'A': - flags= flags | NI_NODEADDR_FLAG_ALL; - break; - - case 'T': - flags= flags | NI_NODEADDR_FLAG_TRUNCATE; - break; - - case 'X': /* No flags */ - break; - - default: - printf("Unknown TCP flag '%c'\n", *charptr); - exit(EXIT_FAILURE); - break; - } - - if(*charptr == 'X') - break; - - charptr++; - } - - flags_f=1; - break; - - case 'j': /* IPv6 Source Address (block) filter */ - if(filters.nblocksrc >= MAX_BLOCK_SRC){ - puts("Too many IPv6 Source Address (block) filters."); - exit(EXIT_FAILURE); - } - - if((pref = strtok_r(optarg, "/", &lasts)) == NULL){ - printf("Error in IPv6 Source Address (block) filter number %u.\n", \ - filters.nblocksrc+1); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, pref, &(filters.blocksrc[filters.nblocksrc])) <= 0){ - printf("Error in IPv6 Source Address (block) filter number %u.", \ - filters.nblocksrc+1); - exit(EXIT_FAILURE); - } - - if((charptr = strtok_r(NULL, " ", &lasts)) == NULL){ - filters.blocksrclen[filters.nblocksrc] = 128; - } - else{ - filters.blocksrclen[filters.nblocksrc] = atoi(charptr); - - if(filters.blocksrclen[filters.nblocksrc]>128){ - printf("Length error in IPv6 Source Address (block) filter number %u.\n", \ - filters.nblocksrc+1); - exit(EXIT_FAILURE); - } - } - - sanitize_ipv6_prefix(&(filters.blocksrc[filters.nblocksrc]), filters.blocksrclen[filters.nblocksrc]); - (filters.nblocksrc)++; - break; - - case 'k': /* IPv6 Destination Address (block) filter */ - if(filters.nblockdst >= MAX_BLOCK_DST){ - puts("Too many IPv6 Destination Address (block) filters."); - exit(EXIT_FAILURE); - } - - if((pref = strtok_r(optarg, "/", &lasts)) == NULL){ - printf("Error in IPv6 Destination Address (block) filter number %u.\n", \ - filters.nblockdst+1); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, pref, &(filters.blockdst[filters.nblockdst])) <= 0){ - printf("Error in IPv6 Source Address (block) filter number %u.", \ - filters.nblockdst+1); - exit(EXIT_FAILURE); - } - - if((charptr = strtok_r(NULL, " ", &lasts)) == NULL){ - filters.blockdstlen[filters.nblockdst] = 128; - } - else{ - filters.blockdstlen[filters.nblockdst] = atoi(charptr); - - if(filters.blockdstlen[filters.nblockdst]>128){ - printf("Length error in IPv6 Source Address (block) filter number %u.\n", \ - filters.nblockdst+1); - exit(EXIT_FAILURE); - } - } - - sanitize_ipv6_prefix(&(filters.blockdst[filters.nblockdst]), filters.blockdstlen[filters.nblockdst]); - filters.nblockdst++; - break; - - case 'J': /* Link Source Address (block) filter */ - if(filters.nblocklinksrc > MAX_BLOCK_LINK_SRC){ - puts("Too many link-layer Source Address (accept) filters."); - exit(EXIT_FAILURE); - } - - if(ether_pton(optarg, &(filters.blocklinksrc[filters.nblocklinksrc]), sizeof(struct ether_addr)) == 0){ - printf("Error in link-layer Source Address (blick) filter number %u.\n", \ - filters.nblocklinksrc+1); - exit(EXIT_FAILURE); - } - - (filters.nblocklinksrc)++; - break; - - case 'K': /* Link Destination Address (block) filter */ - if(filters.nblocklinkdst > MAX_BLOCK_LINK_DST){ - puts("Too many link-layer Destination Address (block) filters."); - exit(EXIT_FAILURE); - } - - if(ether_pton(optarg, &(filters.blocklinkdst[filters.nblocklinkdst]), sizeof(struct ether_addr)) == 0){ - printf("Error in link-layer Destination Address (blick) filter number %u.\n", \ - filters.nblocklinkdst+1); - exit(EXIT_FAILURE); - } - - filters.nblocklinkdst++; - break; - - case 'b': /* IPv6 Source Address (accept) filter */ - if(filters.nacceptsrc > MAX_ACCEPT_SRC){ - puts("Too many IPv6 Source Address (accept) filters."); - exit(EXIT_FAILURE); - } - - if((pref = strtok_r(optarg, "/", &lasts)) == NULL){ - printf("Error in IPv6 Source Address (accept) filter number %u.\n", \ - filters.nacceptsrc+1); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, pref, &(filters.acceptsrc[filters.nacceptsrc])) <= 0){ - printf("Error in IPv6 Source Address (accept) filter number %u.\n", \ - filters.nacceptsrc+1); - exit(EXIT_FAILURE); - } - - if((charptr = strtok_r(NULL, " ", &lasts)) == NULL){ - filters.acceptsrclen[filters.nacceptsrc] = 128; - } - else{ - filters.acceptsrclen[filters.nacceptsrc] = atoi(charptr); - - if(filters.acceptsrclen[filters.nacceptsrc]>128){ - printf("Length error in IPv6 Source Address (accept) filter number %u.\n", \ - filters.nacceptsrc+1); - exit(EXIT_FAILURE); - } - } - - sanitize_ipv6_prefix(&(filters.acceptsrc[filters.nacceptsrc]), filters.acceptsrclen[filters.nacceptsrc]); - (filters.nacceptsrc)++; - filters.acceptfilters_f=1; - break; - - - case 'g': /* IPv6 Destination Address (accept) filter */ - if(filters.nacceptdst > MAX_ACCEPT_DST){ - puts("Too many IPv6 Destination Address (accept) filters."); - exit(EXIT_FAILURE); - } - - if((pref = strtok_r(optarg, "/", &lasts)) == NULL){ - printf("Error in IPv6 Destination Address (accept) filter number %u.\n", \ - filters.nacceptdst+1); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, pref, &(filters.acceptdst[filters.nacceptdst])) <= 0){ - printf("Error in IPv6 Source Address (accept) filter number %u.\n", \ - filters.nacceptdst+1); - exit(EXIT_FAILURE); - } - - if((charptr = strtok_r(NULL, " ", &lasts)) == NULL){ - filters.acceptdstlen[filters.nacceptdst] = 128; - } - else{ - filters.acceptdstlen[filters.nacceptdst] = atoi(charptr); - - if(filters.acceptdstlen[filters.nacceptdst] > 128){ - printf("Length error in IPv6 Source Address (accept) filter number %u.\n", \ - filters.nacceptdst+1); - exit(EXIT_FAILURE); - } - } - - sanitize_ipv6_prefix(&(filters.acceptdst[filters.nacceptdst]), filters.acceptdstlen[filters.nacceptdst]); - (filters.nacceptdst)++; - filters.acceptfilters_f=1; - break; - - case 'B': /* Link-layer Source Address (accept) filter */ - if(filters.nacceptlinksrc > MAX_ACCEPT_LINK_SRC){ - puts("Too many link-later Source Address (accept) filters."); - exit(EXIT_FAILURE); - } - - if(ether_pton(optarg, &(filters.acceptlinksrc[filters.nacceptlinksrc]), sizeof(struct ether_addr)) == 0){ - printf("Error in link-layer Source Address (accept) filter number %u.\n", \ - filters.nacceptlinksrc+1); - exit(EXIT_FAILURE); - } - - (filters.nacceptlinksrc)++; - filters.acceptfilters_f=1; - break; - - case 'G': /* Link Destination Address (accept) filter */ - if(filters.nacceptlinkdst > MAX_ACCEPT_LINK_DST){ - puts("Too many link-layer Destination Address (accept) filters."); - exit(EXIT_FAILURE); - } - - if(ether_pton(optarg, &(filters.acceptlinkdst[filters.nacceptlinkdst]), sizeof(struct ether_addr)) == 0){ - printf("Error in link-layer Destination Address (accept) filter number %u.\n",\ - filters.nacceptlinkdst+1); - exit(EXIT_FAILURE); - } - - (filters.nacceptlinkdst)++; - filters.acceptfilters_f=1; - break; - - case 'r': - rand_src_f=1; - break; - - case 'R': - forgeether_f=1; - break; - - case 'l': /* "Loop mode */ - loop_f = 1; - break; - - case 'z': /* Sleep option */ - nsleep=atoi(optarg); - if(nsleep==0){ - puts("Invalid number of seconds in '-z' option"); - exit(EXIT_FAILURE); - } - - sleep_f=1; - break; - - case 'L': /* "Listen mode */ - listen_f = 1; - break; - - case 'v': /* Be verbose */ - idata.verbose_f++; - break; - - case 'h': /* Help */ - print_help(); - - exit(EXIT_FAILURE); - break; - - default: - usage(); - exit(EXIT_FAILURE); - break; - - } /* switch */ - } /* while(getopt) */ - - if(geteuid()) { - puts("ni6 needs root privileges to run."); - exit(EXIT_FAILURE); - } - - if(listen_f && !iface_f){ - puts("Must specify the network interface with the -i option when 'listening' mode is set"); - exit(EXIT_FAILURE); - } - - if(listen_f && loop_f){ - puts("'Error: 'listen' mode and 'loop' mode are incompatible"); - exit(EXIT_FAILURE); - } - - if(!(idata.dstaddr_f) && !listen_f){ /* Must specify IPv6 Destination Address if listening mode not used */ - puts("IPv6 Destination Address not specified (and listening mode not selected)"); - exit(EXIT_FAILURE); - } - - - if(load_dst_and_pcap(&idata, LOAD_SRC_NXT_HOP) == FAILURE){ - puts("Error while learning Source Address and Next Hop"); - exit(EXIT_FAILURE); - } - - release_privileges(); - - if(!sleep_f) - nsleep=2; - - if(!maxlabel_f){ - maxlabel=63; - } - - if(!flags_f){ - switch(qtype){ - case NI_QTYPE_NODEADDR: - flags= NI_NODEADDR_FLAG_GLOBAL | NI_NODEADDR_FLAG_SITELOCAL | NI_NODEADDR_FLAG_LINKLOCAL |\ - NI_NODEADDR_FLAG_COMPAT | NI_NODEADDR_FLAG_ALL; - break; - - default: - flags= 0; - break; - } - } - - if( !idata.fragh_f && dstoptuhdr_f){ - puts("Dst. Options Header (Unfragmentable Part) set, but Fragmentation not specified"); - exit(EXIT_FAILURE); - } - - if(sloopattack_f){ - if(code_f && code != 1){ - puts("Error: NI code must be '1' for performing name-loop attacks"); - exit(EXIT_FAILURE); - } - else{ - code=1; - } - } - - if(sloopattack_f){ - switch(slvariant){ - case 0: - slpointer= (unsigned char *)dnsloopq0; - slsize= sizeof(dnsloopq0); - break; - - case 1: - slpointer= (unsigned char *)dnsloopq1; - slsize= sizeof(dnsloopq1); - break; - - default: - puts("Error: invalid name loop variant (valid values are 0-1)"); - exit(EXIT_FAILURE); - break; - } - } - - if(dloopattack_f){ - switch(dlvariant){ - case 0: - dlpointer= (unsigned char *)dnsloopr0; - dlsize= sizeof(dnsloopr0); - break; - - case 1: - dlpointer= (unsigned char *)dnsloopr1; - dlsize= sizeof(dnsloopr1); - break; - - case 2: - dlpointer= (unsigned char *)dnsloopr2; - dlsize= sizeof(dnsloopr2); - break; - - default: - puts("Error: invalid name loop variant (valid values are 0-2)"); - exit(EXIT_FAILURE); - break; - } - } - - /* Set initial contents of the attack packet */ - init_packet_data(&idata); - - FD_ZERO(&sset); - FD_SET(idata.fd, &sset); - - start= time(NULL); - - /* Fire an ICMPv6 Redirect if an IPv6 Destination Address was specified */ - if(idata.dstaddr_f){ - if(!code_f){ - if(ipv6addr_f){ - code=0; - } - else if(name_f || fname_f || exceedp_f || sloopattack_f){ - code=1; - } - else if(ipv4addr_f){ - code=2; - } - else{ - code=0; - } - } - - if(!qtype_f){ - switch(code){ - case 0: - qtype= NI_QTYPE_NODEADDR; - break; - - case 1: - qtype= NI_QTYPE_NODEADDR; - break; - - case 2: - qtype= NI_QTYPE_NODEADDR; - break; - - default: - qtype= NI_QTYPE_NOOP; - break; - } - } - - if(pcap_compile(idata.pfd, &pcap_filter, PCAP_ICMPV6_NI_REPLY, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1){ - printf("pcap_compile(): %s", pcap_geterr(idata.pfd)); - exit(EXIT_FAILURE); - } - - if(pcap_setfilter(idata.pfd, &pcap_filter) == -1){ - printf("pcap_setfilter(): %s", pcap_geterr(idata.pfd)); - exit(EXIT_FAILURE); - } - - pcap_freecode(&pcap_filter); - - type= ICMP6_NI_QUERY; - - if(idata.verbose_f){ - print_attack_info(&idata); - } - - while(1){ - curtime=time(NULL); - - if(!loop_f && (curtime - start) >= QUERY_TIMEOUT){ - break; - } - - if((curtime - lastni) >= nsleep){ - lastni=curtime; - - puts("Sending ICMPv6 Node Information Query....\n"); - - if(send_packet(&idata, NULL, NULL) == -1){ - puts("Error sending packet"); - exit(EXIT_FAILURE); - } - } - - rset= sset; +struct in_addr ipv4addr, ipv4addrd; +struct in6_addr ipv6addr, ipv6addrd; +unsigned int maxlabel, slvariant, slsize, dlvariant, dlsize; +char *name, *named; +unsigned int fnamelen, exceedp, fnamedlen, exceedpd, payloadsize; +int namelen, namedlen; +uint8_t qtype, type; +uint8_t code = 0; +uint16_t flags = 0; +unsigned char *slpointer, *dlpointer; + +struct filters filters; + +int main(int argc, char **argv) { + extern char *optarg; + int r, sel; + fd_set sset, rset; + time_t curtime, lastni = 0, start = 0; + struct timeval timeout; + struct target_ipv6 targetipv6; + + /* For queries only: loops to the beginning of the same label (shouldn't work) */ + unsigned char dnsloopq0[] = {0x04, 0x61, 0x61, 0x61, 0x61, 0x0c, 0x00}; + /* For queries only: loops on a single byte label (shouldn't work) */ + unsigned char dnsloopq1[] = {0x04, 0x61, 0x61, 0x61, 0x61, 0x0c, 0x05}; + + /* Loops to the beginning of the same label */ + unsigned char dnsloopr0[] = {0x04, 0x61, 0x61, 0x61, 0x61, 0x0c, 0x04}; + /* Loops on a single byte */ + unsigned char dnsloopr1[] = {0x04, 0x61, 0x61, 0x61, 0x61, 0x0c, 0x09}; + /* Loops to the beginning of a previous label */ + unsigned char dnsloopr2[] = {0x04, 0x61, 0x61, 0x61, 0x61, 0x00, 0x03, 0x61, 0x61, 0x61, 0x0c, 0x04}; + + static struct option longopts[] = {{"interface", required_argument, 0, 'i'}, + {"src-addr", required_argument, 0, 's'}, + {"dst-addr", required_argument, 0, 'd'}, + {"hop-limit", required_argument, 0, 'c'}, + {"dst-opt-hdr", required_argument, 0, 'u'}, + {"dst-opt-u-hdr", required_argument, 0, 'U'}, + {"hbh-opt-hdr", required_argument, 0, 'H'}, + {"frag-hdr", required_argument, 0, 'y'}, + {"link-src-addr", required_argument, 0, 'S'}, + {"link-dst-addr", required_argument, 0, 'D'}, + {"payload-size", required_argument, 0, 'P'}, + {"subject-ipv4", required_argument, 0, '4'}, + {"subject-ipv6", required_argument, 0, '6'}, + {"subject-name", required_argument, 0, 'n'}, + {"subject-fname", required_argument, 0, 'N'}, + {"subject-ename", required_argument, 0, 'x'}, + {"subject-nloop", required_argument, 0, 'o'}, + {"max-label-size", required_argument, 0, 'Z'}, + {"sname-slabel", no_argument, 0, 'e'}, + {"code", required_argument, 0, 'C'}, + {"qtype", required_argument, 0, 'q'}, + {"flags", required_argument, 0, 'X'}, + {"data-ipv6", required_argument, 0, 'w'}, + {"data-ipv4", required_argument, 0, 'W'}, + {"data-name", required_argument, 0, 'a'}, + {"data-fname", required_argument, 0, 'A'}, + {"data-ename", required_argument, 0, 'Q'}, + {"data-nloop", required_argument, 0, 'O'}, + {"dname-slabel", no_argument, 0, 'E'}, + {"block-src-addr", required_argument, 0, 'j'}, + {"block-dst-addr", required_argument, 0, 'k'}, + {"block-link-src-addr", required_argument, 0, 'J'}, + {"block-link-dst-addr", required_argument, 0, 'K'}, + {"accept-src-addr", required_argument, 0, 'b'}, + {"accept-dst-addr", required_argument, 0, 'g'}, + {"accept-link-src-addr", required_argument, 0, 'B'}, + {"accept-link-dst-addr", required_argument, 0, 'G'}, + {"forge-src-addr", no_argument, 0, 'r'}, + {"forge-link-src-addr", no_argument, 0, 'R'}, + {"loop", no_argument, 0, 'l'}, + {"sleep", required_argument, 0, 'z'}, + {"listen", no_argument, 0, 'L'}, + {"verbose", no_argument, 0, 'v'}, + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0}}; + + char shortopts[] = "i:s:d:c:u:U:H:y:S:D:P:4:6:n:N:x:o:Z:eC:q:X:w:W:a:A:Q:O:Ej:k:J:K:b:g:B:G:lz:Lvh"; + + char option; + + if (argc <= 1) { + usage(); + exit(EXIT_FAILURE); + } + + srandom(time(NULL)); + hoplimit = 64 + random() % 180; + + /* Initialize filters structure */ + if (init_filters(&filters) == -1) { + puts("Error initializing internal data structure"); + exit(EXIT_FAILURE); + } + + if (init_iface_data(&idata) == FAILURE) { + puts("Error initializing internal data structure"); + exit(EXIT_FAILURE); + } + + while ((r = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { + option = r; + + switch (option) { + case 'i': /* Interface */ + strncpy(idata.iface, optarg, IFACE_LENGTH - 1); + idata.iface[IFACE_LENGTH - 1] = 0; + idata.ifindex = if_nametoindex(idata.iface); + idata.iface_f = TRUE; + break; + + case 's': /* IPv6 Source Address */ + if ((charptr = strtok_r(optarg, "/", &lasts)) == NULL) { + puts("Error in Source Address"); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, charptr, &(idata.srcaddr)) <= 0) { + puts("inet_pton(): Source Address not valid"); + exit(EXIT_FAILURE); + } + + idata.srcaddr_f = 1; + + if ((charptr = strtok_r(NULL, " ", &lasts)) != NULL) { + srcpreflen = atoi(charptr); + + if (srcpreflen > 128) { + puts("Prefix length error in IPv6 Source Address"); + exit(EXIT_FAILURE); + } + + sanitize_ipv6_prefix(&(idata.srcaddr), srcpreflen); + srcprefix_f = 1; + } + + break; + + case 'd': /* IPv6 Destination Address */ + strncpy(targetipv6.name, optarg, NI_MAXHOST); + targetipv6.name[NI_MAXHOST - 1] = 0; + targetipv6.flags = AI_CANONNAME; + + if ((r = get_ipv6_target(&targetipv6)) != 0) { + + if (r < 0) { + printf("Unknown Destination: %s\n", gai_strerror(targetipv6.res)); + } + else { + puts("Unknown Destination: No IPv6 address found for specified destination"); + } + + exit(EXIT_FAILURE); + } + + idata.dstaddr = targetipv6.ip6; + idata.dstaddr_f = TRUE; + type = ICMP6_NI_QUERY; + break; + + case 'c': /* Hop Limit */ + hoplimit = atoi(optarg); + hoplimit_f = 1; + break; + + case 'u': /* Destinations Options Header */ + if (ndstopthdr >= MAX_DST_OPT_HDR) { + puts("Too many Destination Options Headers"); + exit(EXIT_FAILURE); + } + + hdrlen = atoi(optarg); + + if (hdrlen < 8) { + puts("Bad length in Destination Options Header"); + exit(EXIT_FAILURE); + } + + hdrlen = ((hdrlen + 7) / 8) * 8; + dstopthdrlen[ndstopthdr] = hdrlen; + + if ((dstopthdr[ndstopthdr] = malloc(hdrlen)) == NULL) { + puts("Not enough memory for Destination Options Header"); + exit(EXIT_FAILURE); + } + + ptrhdr = dstopthdr[ndstopthdr] + 2; + ptrhdrend = dstopthdr[ndstopthdr] + hdrlen; + + while (ptrhdr < ptrhdrend) { + + if ((ptrhdrend - ptrhdr) > 257) + pad = 257; + else + pad = ptrhdrend - ptrhdr; + + if (!insert_pad_opt(ptrhdr, ptrhdrend, pad)) { + puts("Destination Options Header Too Big"); + exit(EXIT_FAILURE); + } + + ptrhdr = ptrhdr + pad; + } + + *(dstopthdr[ndstopthdr] + 1) = (hdrlen / 8) - 1; + ndstopthdr++; + dstopthdr_f = 1; + break; + + case 'U': /* Destination Options Header (Unfragmentable Part) */ + if (ndstoptuhdr >= MAX_DST_OPT_U_HDR) { + puts("Too many Destination Options Headers (Unfragmentable Part)"); + exit(EXIT_FAILURE); + } + + hdrlen = atoi(optarg); + + if (hdrlen < 8) { + puts("Bad length in Destination Options Header (Unfragmentable Part)"); + exit(EXIT_FAILURE); + } + + hdrlen = ((hdrlen + 7) / 8) * 8; + dstoptuhdrlen[ndstoptuhdr] = hdrlen; + + if ((dstoptuhdr[ndstoptuhdr] = malloc(hdrlen)) == NULL) { + puts("Not enough memory for Destination Options Header (Unfragmentable Part)"); + exit(EXIT_FAILURE); + } + + ptrhdr = dstoptuhdr[ndstoptuhdr] + 2; + ptrhdrend = dstoptuhdr[ndstoptuhdr] + hdrlen; + + while (ptrhdr < ptrhdrend) { + + if ((ptrhdrend - ptrhdr) > 257) + pad = 257; + else + pad = ptrhdrend - ptrhdr; + + if (!insert_pad_opt(ptrhdr, ptrhdrend, pad)) { + puts("Destination Options Header (Unfragmentable Part) Too Big"); + exit(EXIT_FAILURE); + } + + ptrhdr = ptrhdr + pad; + } + + *(dstoptuhdr[ndstoptuhdr] + 1) = (hdrlen / 8) - 1; + ndstoptuhdr++; + dstoptuhdr_f = 1; + break; + + case 'H': /* Hop-by-Hop Options Header */ + if (nhbhopthdr >= MAX_HBH_OPT_HDR) { + puts("Too many Hop-by-Hop Options Headers"); + exit(EXIT_FAILURE); + } + + hdrlen = atoi(optarg); + + if (hdrlen < 8) { + puts("Bad length in Hop-by-Hop Options Header"); + exit(EXIT_FAILURE); + } + + hdrlen = ((hdrlen + 7) / 8) * 8; + hbhopthdrlen[nhbhopthdr] = hdrlen; + + if ((hbhopthdr[nhbhopthdr] = malloc(hdrlen)) == NULL) { + puts("Not enough memory for Hop-by-Hop Options Header"); + exit(EXIT_FAILURE); + } + + ptrhdr = hbhopthdr[nhbhopthdr] + 2; + ptrhdrend = hbhopthdr[nhbhopthdr] + hdrlen; + + while (ptrhdr < ptrhdrend) { + if ((ptrhdrend - ptrhdr) > 257) + pad = 257; + else + pad = ptrhdrend - ptrhdr; + + if (!insert_pad_opt(ptrhdr, ptrhdrend, pad)) { + puts("Hop-by-Hop Options Header Too Big"); + exit(EXIT_FAILURE); + } + + ptrhdr = ptrhdr + pad; + } + + *(hbhopthdr[nhbhopthdr] + 1) = (hdrlen / 8) - 1; + nhbhopthdr++; + hbhopthdr_f = 1; + break; + + case 'y': /* Fragment header */ + nfrags = atoi(optarg); + if (nfrags < 8) { + puts("Error in Fragmentation option: Fragment Size must be at least 8 bytes"); + exit(EXIT_FAILURE); + } + + idata.fragh_f = 1; + break; + + case 'S': /* Source Ethernet address */ + if (ether_pton(optarg, &(idata.hsrcaddr), sizeof(idata.hsrcaddr)) == 0) { + puts("Error in Source link-layer address."); + exit(EXIT_FAILURE); + } + + idata.hsrcaddr_f = 1; + break; + + case 'D': /* Destination Ethernet Address */ + if (ether_pton(optarg, &(idata.hdstaddr), sizeof(idata.hdstaddr)) == 0) { + puts("Error in Source link-layer address."); + exit(EXIT_FAILURE); + } + + idata.hdstaddr_f = 1; + break; + + case '6': /* Subject: IPv6 address */ + strncpy(targetipv6.name, optarg, NI_MAXHOST); + targetipv6.name[NI_MAXHOST - 1] = 0; + targetipv6.flags = AI_CANONNAME; + + if ((r = get_ipv6_target(&targetipv6)) != 0) { + + if (r < 0) { + printf("Unknown Destination: %s\n", gai_strerror(targetipv6.res)); + } + else { + puts("Unknown Destination: No IPv6 address found for specified destination"); + } + + exit(EXIT_FAILURE); + } + + ipv6addr = targetipv6.ip6; + ipv6addr_f = 1; + break; + + case '4': /* Subject: IPv4 address */ + + if (inet_pton(AF_INET, optarg, &ipv4addr) <= 0) { + puts("inet_pton(): Subject Address not valid"); + exit(EXIT_FAILURE); + } + + ipv4addr_f = 1; + break; + + case 'n': /* Subject: Name */ + printname = optarg; + namelen = strlen(optarg) + 1; + + if ((name = malloc(namelen + 1)) == NULL) { + puts("Error allocating memory"); + exit(EXIT_FAILURE); + } + + if ((namelen = dns_str2wire(optarg, namelen, name, namelen + 1)) == -1) { + puts("inet_pton(): Error while converting name to DNS wire format"); + exit(EXIT_FAILURE); + } + + name_f = 1; + break; + + case 'N': /* Subject: Name of an arbitrary length */ + fnamelen = atoi(optarg); + fname_f = 1; + break; + + case 'x': /* Subject: DNS wire label that exceeeds packet size */ + exceedp = atoi(optarg); + exceedp_f = 1; + break; + + case 'o': + slvariant = atoi(optarg); + sloopattack_f = 1; + break; + + case 'P': /* Payload Size */ + payloadsize = atoi(optarg); + payloadsize_f = 1; + break; + + case 'w': /* Data: IPv6 address */ + strncpy(targetipv6.name, optarg, NI_MAXHOST); + targetipv6.name[NI_MAXHOST - 1] = 0; + targetipv6.flags = AI_CANONNAME; + + if ((r = get_ipv6_target(&targetipv6)) != 0) { + + if (r < 0) { + printf("Unknown Destination: %s\n", gai_strerror(targetipv6.res)); + } + else { + puts("Unknown Destination: No IPv6 address found for specified destination"); + } + + exit(EXIT_FAILURE); + } + + ipv6addrd = targetipv6.ip6; + ipv6addrd_f = 1; + break; + + case 'W': /* Data: IPv4 address */ + + if (inet_pton(AF_INET, optarg, &ipv4addrd) <= 0) { + puts("inet_pton(): Redirected Address not valid"); + exit(EXIT_FAILURE); + } + + ipv4addrd_f = 1; + break; + + case 'a': /* Data: Name */ + printnamed = optarg; + namedlen = strlen(optarg) + 1; + + if ((named = malloc(namedlen + 1)) == NULL) { + puts("Error allocating memory"); + exit(EXIT_FAILURE); + } + + if ((namedlen = dns_str2wire(optarg, namedlen, named, namedlen + 1)) == -1) { + puts("inet_pton(): Error while converting name to DNS wire format"); + exit(EXIT_FAILURE); + } + + named_f = 1; + break; + + case 'A': /* Data: Name of an arbitrary length */ + fnamedlen = atoi(optarg); + fnamed_f = 1; + break; + + case 'Q': /* Data: DNS wire label that exceeeds packet size */ + exceedpd = atoi(optarg); + exceedpd_f = 1; + break; + + case 'O': + dlvariant = atoi(optarg); + dloopattack_f = 1; + break; + + case 'E': /* Data is a Single label name */ + snamedslabel_f = 1; + break; + + case 'Z': /* Max DNS label size (defaults to 63) */ + maxlabel = atoi(optarg); + + if (maxlabel < 1) { + puts("Error: max-label-size too small"); + exit(EXIT_FAILURE); + } + + maxlabel_f = 1; + break; + + case 'e': /* Subject is a Single label name */ + snameslabel_f = 1; + break; + + case 'C': /* ICMPv6 code */ + code = atoi(optarg); + code_f = 1; + break; + + case 'q': /* Qtype */ + qtype = atoi(optarg); + qtype_f = 1; + break; + + case 'X': + charptr = optarg; + while (*charptr) { + switch (*charptr) { + case 'G': + flags = flags | NI_NODEADDR_FLAG_GLOBAL; + break; + + case 'S': + flags = flags | NI_NODEADDR_FLAG_SITELOCAL; + break; + + case 'L': + flags = flags | NI_NODEADDR_FLAG_LINKLOCAL; + break; + + case 'C': + flags = flags | NI_NODEADDR_FLAG_COMPAT; + break; + + case 'A': + flags = flags | NI_NODEADDR_FLAG_ALL; + break; + + case 'T': + flags = flags | NI_NODEADDR_FLAG_TRUNCATE; + break; + + case 'X': /* No flags */ + break; + + default: + printf("Unknown TCP flag '%c'\n", *charptr); + exit(EXIT_FAILURE); + break; + } + + if (*charptr == 'X') + break; + + charptr++; + } + + flags_f = 1; + break; + + case 'j': /* IPv6 Source Address (block) filter */ + if (filters.nblocksrc >= MAX_BLOCK_SRC) { + puts("Too many IPv6 Source Address (block) filters."); + exit(EXIT_FAILURE); + } + + if ((pref = strtok_r(optarg, "/", &lasts)) == NULL) { + printf("Error in IPv6 Source Address (block) filter number %u.\n", filters.nblocksrc + 1); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, pref, &(filters.blocksrc[filters.nblocksrc])) <= 0) { + printf("Error in IPv6 Source Address (block) filter number %u.", filters.nblocksrc + 1); + exit(EXIT_FAILURE); + } + + if ((charptr = strtok_r(NULL, " ", &lasts)) == NULL) { + filters.blocksrclen[filters.nblocksrc] = 128; + } + else { + filters.blocksrclen[filters.nblocksrc] = atoi(charptr); + + if (filters.blocksrclen[filters.nblocksrc] > 128) { + printf("Length error in IPv6 Source Address (block) filter number %u.\n", filters.nblocksrc + 1); + exit(EXIT_FAILURE); + } + } + + sanitize_ipv6_prefix(&(filters.blocksrc[filters.nblocksrc]), filters.blocksrclen[filters.nblocksrc]); + (filters.nblocksrc)++; + break; + + case 'k': /* IPv6 Destination Address (block) filter */ + if (filters.nblockdst >= MAX_BLOCK_DST) { + puts("Too many IPv6 Destination Address (block) filters."); + exit(EXIT_FAILURE); + } + + if ((pref = strtok_r(optarg, "/", &lasts)) == NULL) { + printf("Error in IPv6 Destination Address (block) filter number %u.\n", filters.nblockdst + 1); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, pref, &(filters.blockdst[filters.nblockdst])) <= 0) { + printf("Error in IPv6 Source Address (block) filter number %u.", filters.nblockdst + 1); + exit(EXIT_FAILURE); + } + + if ((charptr = strtok_r(NULL, " ", &lasts)) == NULL) { + filters.blockdstlen[filters.nblockdst] = 128; + } + else { + filters.blockdstlen[filters.nblockdst] = atoi(charptr); + + if (filters.blockdstlen[filters.nblockdst] > 128) { + printf("Length error in IPv6 Source Address (block) filter number %u.\n", filters.nblockdst + 1); + exit(EXIT_FAILURE); + } + } + + sanitize_ipv6_prefix(&(filters.blockdst[filters.nblockdst]), filters.blockdstlen[filters.nblockdst]); + filters.nblockdst++; + break; + + case 'J': /* Link Source Address (block) filter */ + if (filters.nblocklinksrc > MAX_BLOCK_LINK_SRC) { + puts("Too many link-layer Source Address (accept) filters."); + exit(EXIT_FAILURE); + } + + if (ether_pton(optarg, &(filters.blocklinksrc[filters.nblocklinksrc]), sizeof(struct ether_addr)) == 0) { + printf("Error in link-layer Source Address (blick) filter number %u.\n", filters.nblocklinksrc + 1); + exit(EXIT_FAILURE); + } + + (filters.nblocklinksrc)++; + break; + + case 'K': /* Link Destination Address (block) filter */ + if (filters.nblocklinkdst > MAX_BLOCK_LINK_DST) { + puts("Too many link-layer Destination Address (block) filters."); + exit(EXIT_FAILURE); + } + + if (ether_pton(optarg, &(filters.blocklinkdst[filters.nblocklinkdst]), sizeof(struct ether_addr)) == 0) { + printf("Error in link-layer Destination Address (blick) filter number %u.\n", + filters.nblocklinkdst + 1); + exit(EXIT_FAILURE); + } + + filters.nblocklinkdst++; + break; + + case 'b': /* IPv6 Source Address (accept) filter */ + if (filters.nacceptsrc > MAX_ACCEPT_SRC) { + puts("Too many IPv6 Source Address (accept) filters."); + exit(EXIT_FAILURE); + } + + if ((pref = strtok_r(optarg, "/", &lasts)) == NULL) { + printf("Error in IPv6 Source Address (accept) filter number %u.\n", filters.nacceptsrc + 1); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, pref, &(filters.acceptsrc[filters.nacceptsrc])) <= 0) { + printf("Error in IPv6 Source Address (accept) filter number %u.\n", filters.nacceptsrc + 1); + exit(EXIT_FAILURE); + } + + if ((charptr = strtok_r(NULL, " ", &lasts)) == NULL) { + filters.acceptsrclen[filters.nacceptsrc] = 128; + } + else { + filters.acceptsrclen[filters.nacceptsrc] = atoi(charptr); + + if (filters.acceptsrclen[filters.nacceptsrc] > 128) { + printf("Length error in IPv6 Source Address (accept) filter number %u.\n", filters.nacceptsrc + 1); + exit(EXIT_FAILURE); + } + } + + sanitize_ipv6_prefix(&(filters.acceptsrc[filters.nacceptsrc]), filters.acceptsrclen[filters.nacceptsrc]); + (filters.nacceptsrc)++; + filters.acceptfilters_f = 1; + break; + + case 'g': /* IPv6 Destination Address (accept) filter */ + if (filters.nacceptdst > MAX_ACCEPT_DST) { + puts("Too many IPv6 Destination Address (accept) filters."); + exit(EXIT_FAILURE); + } + + if ((pref = strtok_r(optarg, "/", &lasts)) == NULL) { + printf("Error in IPv6 Destination Address (accept) filter number %u.\n", filters.nacceptdst + 1); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, pref, &(filters.acceptdst[filters.nacceptdst])) <= 0) { + printf("Error in IPv6 Source Address (accept) filter number %u.\n", filters.nacceptdst + 1); + exit(EXIT_FAILURE); + } + + if ((charptr = strtok_r(NULL, " ", &lasts)) == NULL) { + filters.acceptdstlen[filters.nacceptdst] = 128; + } + else { + filters.acceptdstlen[filters.nacceptdst] = atoi(charptr); + + if (filters.acceptdstlen[filters.nacceptdst] > 128) { + printf("Length error in IPv6 Source Address (accept) filter number %u.\n", filters.nacceptdst + 1); + exit(EXIT_FAILURE); + } + } + + sanitize_ipv6_prefix(&(filters.acceptdst[filters.nacceptdst]), filters.acceptdstlen[filters.nacceptdst]); + (filters.nacceptdst)++; + filters.acceptfilters_f = 1; + break; + + case 'B': /* Link-layer Source Address (accept) filter */ + if (filters.nacceptlinksrc > MAX_ACCEPT_LINK_SRC) { + puts("Too many link-later Source Address (accept) filters."); + exit(EXIT_FAILURE); + } + + if (ether_pton(optarg, &(filters.acceptlinksrc[filters.nacceptlinksrc]), sizeof(struct ether_addr)) == 0) { + printf("Error in link-layer Source Address (accept) filter number %u.\n", filters.nacceptlinksrc + 1); + exit(EXIT_FAILURE); + } + + (filters.nacceptlinksrc)++; + filters.acceptfilters_f = 1; + break; + + case 'G': /* Link Destination Address (accept) filter */ + if (filters.nacceptlinkdst > MAX_ACCEPT_LINK_DST) { + puts("Too many link-layer Destination Address (accept) filters."); + exit(EXIT_FAILURE); + } + + if (ether_pton(optarg, &(filters.acceptlinkdst[filters.nacceptlinkdst]), sizeof(struct ether_addr)) == 0) { + printf("Error in link-layer Destination Address (accept) filter number %u.\n", + filters.nacceptlinkdst + 1); + exit(EXIT_FAILURE); + } + + (filters.nacceptlinkdst)++; + filters.acceptfilters_f = 1; + break; + + case 'r': + rand_src_f = 1; + break; + + case 'R': + forgeether_f = 1; + break; + + case 'l': /* "Loop mode */ + loop_f = 1; + break; + + case 'z': /* Sleep option */ + nsleep = atoi(optarg); + if (nsleep == 0) { + puts("Invalid number of seconds in '-z' option"); + exit(EXIT_FAILURE); + } + + sleep_f = 1; + break; + + case 'L': /* "Listen mode */ + listen_f = 1; + break; + + case 'v': /* Be verbose */ + idata.verbose_f++; + break; + + case 'h': /* Help */ + print_help(); + + exit(EXIT_FAILURE); + break; + + default: + usage(); + exit(EXIT_FAILURE); + break; + + } /* switch */ + } /* while(getopt) */ + + if (geteuid()) { + puts("ni6 needs root privileges to run."); + exit(EXIT_FAILURE); + } + + if (listen_f && !iface_f) { + puts("Must specify the network interface with the -i option when 'listening' mode is set"); + exit(EXIT_FAILURE); + } + + if (listen_f && loop_f) { + puts("'Error: 'listen' mode and 'loop' mode are incompatible"); + exit(EXIT_FAILURE); + } + + if (!(idata.dstaddr_f) && !listen_f) { /* Must specify IPv6 Destination Address if listening mode not used */ + puts("IPv6 Destination Address not specified (and listening mode not selected)"); + exit(EXIT_FAILURE); + } + + if (load_dst_and_pcap(&idata, LOAD_SRC_NXT_HOP) == FAILURE) { + puts("Error while learning Source Address and Next Hop"); + exit(EXIT_FAILURE); + } + + release_privileges(); + + if (!sleep_f) + nsleep = 2; + + if (!maxlabel_f) { + maxlabel = 63; + } + + if (!flags_f) { + switch (qtype) { + case NI_QTYPE_NODEADDR: + flags = NI_NODEADDR_FLAG_GLOBAL | NI_NODEADDR_FLAG_SITELOCAL | NI_NODEADDR_FLAG_LINKLOCAL | + NI_NODEADDR_FLAG_COMPAT | NI_NODEADDR_FLAG_ALL; + break; + + default: + flags = 0; + break; + } + } + + if (!idata.fragh_f && dstoptuhdr_f) { + puts("Dst. Options Header (Unfragmentable Part) set, but Fragmentation not specified"); + exit(EXIT_FAILURE); + } + + if (sloopattack_f) { + if (code_f && code != 1) { + puts("Error: NI code must be '1' for performing name-loop attacks"); + exit(EXIT_FAILURE); + } + else { + code = 1; + } + } + + if (sloopattack_f) { + switch (slvariant) { + case 0: + slpointer = (unsigned char *)dnsloopq0; + slsize = sizeof(dnsloopq0); + break; + + case 1: + slpointer = (unsigned char *)dnsloopq1; + slsize = sizeof(dnsloopq1); + break; + + default: + puts("Error: invalid name loop variant (valid values are 0-1)"); + exit(EXIT_FAILURE); + break; + } + } + + if (dloopattack_f) { + switch (dlvariant) { + case 0: + dlpointer = (unsigned char *)dnsloopr0; + dlsize = sizeof(dnsloopr0); + break; + + case 1: + dlpointer = (unsigned char *)dnsloopr1; + dlsize = sizeof(dnsloopr1); + break; + + case 2: + dlpointer = (unsigned char *)dnsloopr2; + dlsize = sizeof(dnsloopr2); + break; + + default: + puts("Error: invalid name loop variant (valid values are 0-2)"); + exit(EXIT_FAILURE); + break; + } + } + + /* Set initial contents of the attack packet */ + init_packet_data(&idata); + + FD_ZERO(&sset); + FD_SET(idata.fd, &sset); + + start = time(NULL); + + /* Fire an ICMPv6 Redirect if an IPv6 Destination Address was specified */ + if (idata.dstaddr_f) { + if (!code_f) { + if (ipv6addr_f) { + code = 0; + } + else if (name_f || fname_f || exceedp_f || sloopattack_f) { + code = 1; + } + else if (ipv4addr_f) { + code = 2; + } + else { + code = 0; + } + } + + if (!qtype_f) { + switch (code) { + case 0: + qtype = NI_QTYPE_NODEADDR; + break; + + case 1: + qtype = NI_QTYPE_NODEADDR; + break; + + case 2: + qtype = NI_QTYPE_NODEADDR; + break; + + default: + qtype = NI_QTYPE_NOOP; + break; + } + } + + if (pcap_compile(idata.pfd, &pcap_filter, PCAP_ICMPV6_NI_REPLY, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1) { + printf("pcap_compile(): %s", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } + + if (pcap_setfilter(idata.pfd, &pcap_filter) == -1) { + printf("pcap_setfilter(): %s", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } + + pcap_freecode(&pcap_filter); + + type = ICMP6_NI_QUERY; + + if (idata.verbose_f) { + print_attack_info(&idata); + } + + while (1) { + curtime = time(NULL); + + if (!loop_f && (curtime - start) >= QUERY_TIMEOUT) { + break; + } + + if ((curtime - lastni) >= nsleep) { + lastni = curtime; + + puts("Sending ICMPv6 Node Information Query....\n"); + + if (send_packet(&idata, NULL, NULL) == -1) { + puts("Error sending packet"); + exit(EXIT_FAILURE); + } + } + + rset = sset; #if defined(sun) || defined(__sun) || defined(__linux__) - timeout.tv_usec=10000; - timeout.tv_sec= 0; + timeout.tv_usec = 10000; + timeout.tv_sec = 0; #else - timeout.tv_usec=0; - timeout.tv_sec= nsleep; + timeout.tv_usec = 0; + timeout.tv_sec = nsleep; #endif - if((sel=select(idata.fd+1, &rset, NULL, NULL, &timeout)) == -1){ - if(errno == EINTR){ - continue; - } - else{ - puts("Error in select()"); - exit(EXIT_FAILURE); - } - } - - /* Read a NI Reply packet */ + if ((sel = select(idata.fd + 1, &rset, NULL, NULL, &timeout)) == -1) { + if (errno == EINTR) { + continue; + } + else { + puts("Error in select()"); + exit(EXIT_FAILURE); + } + } + + /* Read a NI Reply packet */ #if defined(sun) || defined(__sun) || defined(__linux__) - if(TRUE){ + if (TRUE) { #else - if(sel && FD_ISSET(idata.fd, &rset)){ + if (sel && FD_ISSET(idata.fd, &rset)) { #endif - if((r=pcap_next_ex(idata.pfd, &pkthdr, &pktdata)) == -1){ - printf("pcap_next_ex(): %s", pcap_geterr(idata.pfd)); - exit(EXIT_FAILURE); - } - else if(r == 1 && pktdata != NULL){ - if(print_ni_data(&idata, pktdata, pkthdr) == -1){ - puts("Error while printing NI data"); - exit(EXIT_FAILURE); - } - } - } - } - - exit(EXIT_SUCCESS); - } - - if(listen_f){ - if(named_f || fnamed_f || exceedpd_f || dloopattack_f){ - qtype= NI_QTYPE_DNSNAME; - } - else if(ipv4addrd_f){ - qtype= NI_QTYPE_IPV4ADDR; - } - else if(ipv6addrd_f){ - qtype= NI_QTYPE_NODEADDR; - } - else if(!qtype_f){ - qtype= NI_QTYPE_NOOP; - } - - if(pcap_compile(idata.pfd, &pcap_filter, PCAP_ICMPV6_NI_QUERY, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1){ - printf("pcap_compile(): %s", pcap_geterr(idata.pfd)); - exit(EXIT_FAILURE); - } - - - if(pcap_setfilter(idata.pfd, &pcap_filter) == -1){ - printf("pcap_setfilter(): %s", pcap_geterr(idata.pfd)); - exit(EXIT_FAILURE); - } - - pcap_freecode(&pcap_filter); - - type= ICMP6_NI_REPLY; - - if(idata.verbose_f){ - print_attack_info(&idata); - } - - if(idata.verbose_f){ - print_filters(&idata, &filters); - puts("Listening to incoming IPv6 packets..."); - } - - while(listen_f){ - rset= sset; + if ((r = pcap_next_ex(idata.pfd, &pkthdr, &pktdata)) == -1) { + printf("pcap_next_ex(): %s", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } + else if (r == 1 && pktdata != NULL) { + if (print_ni_data(&idata, pktdata, pkthdr) == -1) { + puts("Error while printing NI data"); + exit(EXIT_FAILURE); + } + } + } + } + + exit(EXIT_SUCCESS); + } + + if (listen_f) { + if (named_f || fnamed_f || exceedpd_f || dloopattack_f) { + qtype = NI_QTYPE_DNSNAME; + } + else if (ipv4addrd_f) { + qtype = NI_QTYPE_IPV4ADDR; + } + else if (ipv6addrd_f) { + qtype = NI_QTYPE_NODEADDR; + } + else if (!qtype_f) { + qtype = NI_QTYPE_NOOP; + } + + if (pcap_compile(idata.pfd, &pcap_filter, PCAP_ICMPV6_NI_QUERY, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1) { + printf("pcap_compile(): %s", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } + + if (pcap_setfilter(idata.pfd, &pcap_filter) == -1) { + printf("pcap_setfilter(): %s", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } + + pcap_freecode(&pcap_filter); + + type = ICMP6_NI_REPLY; + + if (idata.verbose_f) { + print_attack_info(&idata); + } + + if (idata.verbose_f) { + print_filters(&idata, &filters); + puts("Listening to incoming IPv6 packets..."); + } + + while (listen_f) { + rset = sset; #if defined(sun) || defined(__sun) || defined(__linux__) - timeout.tv_usec=10000; - timeout.tv_sec= 0; - if((sel=select(idata.fd+1, &rset, NULL, NULL, &timeout)) == -1){ + timeout.tv_usec = 10000; + timeout.tv_sec = 0; + if ((sel = select(idata.fd + 1, &rset, NULL, NULL, &timeout)) == -1) { #else - if((sel=select(idata.fd+1, &rset, NULL, NULL, NULL)) == -1){ + if ((sel = select(idata.fd + 1, &rset, NULL, NULL, NULL)) == -1) { #endif - if(errno == EINTR){ - continue; - } - else{ - puts("Error in select()"); - exit(EXIT_FAILURE); - } - } + if (errno == EINTR) { + continue; + } + else { + puts("Error in select()"); + exit(EXIT_FAILURE); + } + } #if defined(sun) || defined(__sun) || defined(__linux__) - if(TRUE){ + if (TRUE) { #else - if(sel && FD_ISSET(idata.fd, &rset)){ + if (sel && FD_ISSET(idata.fd, &rset)) { #endif - /* Read a Neighbor Solicitation message */ - if((r=pcap_next_ex(idata.pfd, &pkthdr, &pktdata)) == -1){ - printf("pcap_next_ex(): %s", pcap_geterr(idata.pfd)); - exit(EXIT_FAILURE); - } - else if(r == 1 && pktdata != NULL){ - pkt_ether = (struct ether_header *) pktdata; - pkt_ipv6 = (struct ip6_hdr *)((char *) pkt_ether + idata.linkhsize); - pkt_ni= (struct icmp6_nodeinfo *) ( (unsigned char *) pkt_ipv6 + sizeof(struct ip6_hdr)); - - accepted_f=0; - - if(pkt_ni->ni_type != ICMP6_NI_QUERY){ - continue; - } - - if(pkt_ni->ni_qtype != htons(qtype)){ - continue; - } - - if(!rand_src_f){ - if(!IN6_IS_ADDR_MC_LINKLOCAL(&(pkt_ipv6->ip6_dst)) && \ - !is_ip6_in_address_list(&(idata.ip6_global), &(pkt_ipv6->ip6_dst)) && \ - !is_eq_in6_addr(&(pkt_ipv6->ip6_dst), &(idata.ip6_local))) - continue; - } - - if(filters.nblocklinksrc){ - if(match_ether(filters.blocklinksrc, filters.nblocklinksrc, &(pkt_ether->src))){ - if(idata.verbose_f > 1) - print_filter_result(&idata, pktdata, BLOCKED); - - continue; - } - } - - if(filters.nblocklinkdst){ - if(match_ether(filters.blocklinkdst, filters.nblocklinkdst, &(pkt_ether->dst))){ - if(idata.verbose_f > 1) - print_filter_result(&idata, pktdata, BLOCKED); - - continue; - } - } - - if(filters.nblocksrc){ - if(match_ipv6(filters.blocksrc, filters.blocksrclen, filters.nblocksrc, &(pkt_ipv6->ip6_src))){ - if(idata.verbose_f > 1) - print_filter_result(&idata, pktdata, BLOCKED); - - continue; - } - } - - if(filters.nblockdst){ - if(match_ipv6(filters.blockdst, filters.blockdstlen, filters.nblockdst, &(pkt_ipv6->ip6_dst))){ - if(idata.verbose_f > 1) - print_filter_result(&idata, pktdata, BLOCKED); - - continue; - } - } - - if(filters.nacceptlinksrc){ - if(match_ether(filters.acceptlinksrc, filters.nacceptlinksrc, &(pkt_ether->src))) - accepted_f=1; - } - - if(filters.nacceptlinkdst && !accepted_f){ - if(match_ether(filters.acceptlinkdst, filters.nacceptlinkdst, &(pkt_ether->dst))) - accepted_f= 1; - } - - if(filters.nacceptsrc && !accepted_f){ - if(match_ipv6(filters.acceptsrc, filters.acceptsrclen, filters.nacceptsrc, &(pkt_ipv6->ip6_src))) - accepted_f= 1; - } - - if(filters.nacceptdst && !accepted_f){ - if(match_ipv6(filters.acceptdst, filters.acceptdstlen, filters.nacceptdst, &(pkt_ipv6->ip6_dst))) - accepted_f=1; - } - - if(filters.acceptfilters_f && !accepted_f){ - if(idata.verbose_f > 1) - print_filter_result(&idata, pktdata, BLOCKED); - - continue; - } - - if(idata.verbose_f) - print_filter_result(&idata, pktdata, ACCEPTED); - - /* Send a Node Information packet */ - if(send_packet(&idata, pktdata, pkthdr) == -1){ - puts("Error sending packet"); - exit(EXIT_FAILURE); - } - } - } - } - - exit(EXIT_SUCCESS); - } - - - if(!idata.dstaddr_f && !listen_f){ - puts("Error: Nothing to send! (key parameters left unspecified, and not using listening mode)"); - exit(EXIT_FAILURE); - } - - exit(EXIT_SUCCESS); + /* Read a Neighbor Solicitation message */ + if ((r = pcap_next_ex(idata.pfd, &pkthdr, &pktdata)) == -1) { + printf("pcap_next_ex(): %s", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } + else if (r == 1 && pktdata != NULL) { + pkt_ether = (struct ether_header *)pktdata; + pkt_ipv6 = (struct ip6_hdr *)((char *)pkt_ether + idata.linkhsize); + pkt_ni = (struct icmp6_nodeinfo *)((unsigned char *)pkt_ipv6 + sizeof(struct ip6_hdr)); + + accepted_f = 0; + + if (pkt_ni->ni_type != ICMP6_NI_QUERY) { + continue; + } + + if (pkt_ni->ni_qtype != htons(qtype)) { + continue; + } + + if (!rand_src_f) { + if (!IN6_IS_ADDR_MC_LINKLOCAL(&(pkt_ipv6->ip6_dst)) && + !is_ip6_in_address_list(&(idata.ip6_global), &(pkt_ipv6->ip6_dst)) && + !is_eq_in6_addr(&(pkt_ipv6->ip6_dst), &(idata.ip6_local))) + continue; + } + + if (filters.nblocklinksrc) { + if (match_ether(filters.blocklinksrc, filters.nblocklinksrc, &(pkt_ether->src))) { + if (idata.verbose_f > 1) + print_filter_result(&idata, pktdata, BLOCKED); + + continue; + } + } + + if (filters.nblocklinkdst) { + if (match_ether(filters.blocklinkdst, filters.nblocklinkdst, &(pkt_ether->dst))) { + if (idata.verbose_f > 1) + print_filter_result(&idata, pktdata, BLOCKED); + + continue; + } + } + + if (filters.nblocksrc) { + if (match_ipv6(filters.blocksrc, filters.blocksrclen, filters.nblocksrc, + &(pkt_ipv6->ip6_src))) { + if (idata.verbose_f > 1) + print_filter_result(&idata, pktdata, BLOCKED); + + continue; + } + } + + if (filters.nblockdst) { + if (match_ipv6(filters.blockdst, filters.blockdstlen, filters.nblockdst, + &(pkt_ipv6->ip6_dst))) { + if (idata.verbose_f > 1) + print_filter_result(&idata, pktdata, BLOCKED); + + continue; + } + } + + if (filters.nacceptlinksrc) { + if (match_ether(filters.acceptlinksrc, filters.nacceptlinksrc, &(pkt_ether->src))) + accepted_f = 1; + } + + if (filters.nacceptlinkdst && !accepted_f) { + if (match_ether(filters.acceptlinkdst, filters.nacceptlinkdst, &(pkt_ether->dst))) + accepted_f = 1; + } + + if (filters.nacceptsrc && !accepted_f) { + if (match_ipv6(filters.acceptsrc, filters.acceptsrclen, filters.nacceptsrc, + &(pkt_ipv6->ip6_src))) + accepted_f = 1; + } + + if (filters.nacceptdst && !accepted_f) { + if (match_ipv6(filters.acceptdst, filters.acceptdstlen, filters.nacceptdst, + &(pkt_ipv6->ip6_dst))) + accepted_f = 1; + } + + if (filters.acceptfilters_f && !accepted_f) { + if (idata.verbose_f > 1) + print_filter_result(&idata, pktdata, BLOCKED); + + continue; + } + + if (idata.verbose_f) + print_filter_result(&idata, pktdata, ACCEPTED); + + /* Send a Node Information packet */ + if (send_packet(&idata, pktdata, pkthdr) == -1) { + puts("Error sending packet"); + exit(EXIT_FAILURE); + } + } + } + } + + exit(EXIT_SUCCESS); + } + + if (!idata.dstaddr_f && !listen_f) { + puts("Error: Nothing to send! (key parameters left unspecified, and not using listening mode)"); + exit(EXIT_FAILURE); + } + + exit(EXIT_SUCCESS); } /* @@ -1338,137 +1315,132 @@ int main(int argc, char **argv){ * Wrapper to call the different functions that print the contents of NI replies */ -int print_ni_data(struct iface_data *idata, const u_char *pktdata, struct pcap_pkthdr * pkthdr){ - struct icmp6_nodeinfo *pkt_ni; - - pkt_ni= (struct icmp6_nodeinfo *) ((char *)pktdata + idata->linkhsize + sizeof(struct ip6_hdr)); - - switch(ntohs(pkt_ni->ni_qtype)){ - case NI_QTYPE_NOOP: - if(print_ni_noop(idata, pktdata, pkthdr) == -1){ - return(-1); - } - break; - - case NI_QTYPE_SUPTYPES: - if(print_ni_noop(idata, pktdata, pkthdr) == -1){ - return(-1); - } - break; - - case NI_QTYPE_DNSNAME: - if(print_ni_name(idata, pktdata, pkthdr) == -1){ - return(-1); - } - break; - - case NI_QTYPE_NODEADDR: - if(print_ni_addr6(idata, pktdata, pkthdr) == -1){ - return(-1); - } - break; - - case NI_QTYPE_IPV4ADDR: - if(print_ni_addr6(idata, pktdata, pkthdr) == -1){ - return(-1); - } - break; - - default: - break; - } - - return(0); +int print_ni_data(struct iface_data *idata, const u_char *pktdata, struct pcap_pkthdr *pkthdr) { + struct icmp6_nodeinfo *pkt_ni; + + pkt_ni = (struct icmp6_nodeinfo *)((char *)pktdata + idata->linkhsize + sizeof(struct ip6_hdr)); + + switch (ntohs(pkt_ni->ni_qtype)) { + case NI_QTYPE_NOOP: + if (print_ni_noop(idata, pktdata, pkthdr) == -1) { + return (-1); + } + break; + + case NI_QTYPE_SUPTYPES: + if (print_ni_noop(idata, pktdata, pkthdr) == -1) { + return (-1); + } + break; + + case NI_QTYPE_DNSNAME: + if (print_ni_name(idata, pktdata, pkthdr) == -1) { + return (-1); + } + break; + + case NI_QTYPE_NODEADDR: + if (print_ni_addr6(idata, pktdata, pkthdr) == -1) { + return (-1); + } + break; + + case NI_QTYPE_IPV4ADDR: + if (print_ni_addr6(idata, pktdata, pkthdr) == -1) { + return (-1); + } + break; + + default: + break; + } + + return (0); } - /* * Function: print_ni_addr() * * Print responses to ICMPv6 NI queries for IPv4 addresses */ -int print_ni_addr(struct iface_data *idata, const u_char *pktdata, struct pcap_pkthdr * pkthdr){ - struct ether_header *pkt_ether; - struct ip6_hdr *pkt_ipv6; - struct icmp6_nodeinfo *pkt_ni; - unsigned char *pkt_end; - uint16_t flags; - struct ni_reply_ip *pkt_nidata; - - pkt_ether = (struct ether_header *) pktdata; - pkt_ipv6 = (struct ip6_hdr *)((char *) pkt_ether + idata->linkhsize); - pkt_ni= (struct icmp6_nodeinfo *) ((char *) pkt_ipv6 + sizeof(struct ip6_hdr)); - pkt_end = (unsigned char *) pktdata + pkthdr->caplen; - - if( pkt_end > ((unsigned char *)pkt_ni + ntohs(pkt_ipv6->ip6_plen)) ) - pkt_end = (unsigned char *)pkt_ni + ntohs(pkt_ipv6->ip6_plen); - - if(!is_eq_in6_addr(&(pkt_ipv6->ip6_dst), &(idata->srcaddr))) - return 0; - - if(inet_ntop(AF_INET6, &(pkt_ipv6->ip6_src), pv6addr, sizeof(pv6addr)) == NULL){ - if(idata->verbose_f) - puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); - - return(-1); - } - - printf("Response from: %s\n", pv6addr); - - switch(pkt_ni->ni_code){ - case 0: - printf("\tCode: 0 (Successful reply)"); - break; - - case 1: - printf("\tCode: 1 (Node refuses to supply the answer)"); - break; - - case 2: - printf("\tCode: 2 (Qtype unknown to the responder)"); - break; - - default: - printf("\tCode: %u (Qtype unknown)", pkt_ni->ni_code); - break; - } - - flags= ntohs(pkt_ni->ni_flags); - printf("\tFlags: %s%s%s%s%s%s%s\n", ((flags & NI_NODEADDR_FLAG_GLOBAL)?"G":""), \ - ((flags & NI_NODEADDR_FLAG_SITELOCAL)?"S":""), \ - ((flags & NI_NODEADDR_FLAG_LINKLOCAL)?"L":""), \ - ((flags & NI_NODEADDR_FLAG_COMPAT)?"C":""),\ - ((flags & NI_NODEADDR_FLAG_ALL)?"A":""), \ - ((flags & NI_NODEADDR_FLAG_TRUNCATE)?"T":""),\ - ((!flags)?"none":"")); - - pkt_nidata= (struct ni_reply_ip *) ((char *)pkt_ni + sizeof(struct icmp6_nodeinfo)); - - while( (pkt_end - (unsigned char *) pkt_nidata) >= sizeof(struct ni_reply_ip)){ - if(inet_ntop(AF_INET, &(pkt_nidata->ip), pv6addr, sizeof(pv6addr)) == NULL){ - if(idata->verbose_f) - puts("inet_ntop(): Error converting IPv4 Address to presentation format"); - - return(-1); - } - - printf("\t%s (TTL: %lu%s)\n", pv6addr, (LUI) pkt_nidata->ni_ip_ttl,\ - (pkt_nidata->ni_ip_ttl==0xffffffff)?" (infinity)":""); - - pkt_nidata++; - } - - if( (unsigned char *)pkt_nidata != pkt_end){ - puts("Incomplete data in received NI Reply\n"); - } - else{ - puts(""); - } - - return(0); -} +int print_ni_addr(struct iface_data *idata, const u_char *pktdata, struct pcap_pkthdr *pkthdr) { + struct ether_header *pkt_ether; + struct ip6_hdr *pkt_ipv6; + struct icmp6_nodeinfo *pkt_ni; + unsigned char *pkt_end; + uint16_t flags; + struct ni_reply_ip *pkt_nidata; + + pkt_ether = (struct ether_header *)pktdata; + pkt_ipv6 = (struct ip6_hdr *)((char *)pkt_ether + idata->linkhsize); + pkt_ni = (struct icmp6_nodeinfo *)((char *)pkt_ipv6 + sizeof(struct ip6_hdr)); + pkt_end = (unsigned char *)pktdata + pkthdr->caplen; + + if (pkt_end > ((unsigned char *)pkt_ni + ntohs(pkt_ipv6->ip6_plen))) + pkt_end = (unsigned char *)pkt_ni + ntohs(pkt_ipv6->ip6_plen); + + if (!is_eq_in6_addr(&(pkt_ipv6->ip6_dst), &(idata->srcaddr))) + return 0; + + if (inet_ntop(AF_INET6, &(pkt_ipv6->ip6_src), pv6addr, sizeof(pv6addr)) == NULL) { + if (idata->verbose_f) + puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); + + return (-1); + } + + printf("Response from: %s\n", pv6addr); + + switch (pkt_ni->ni_code) { + case 0: + printf("\tCode: 0 (Successful reply)"); + break; + + case 1: + printf("\tCode: 1 (Node refuses to supply the answer)"); + break; + + case 2: + printf("\tCode: 2 (Qtype unknown to the responder)"); + break; + + default: + printf("\tCode: %u (Qtype unknown)", pkt_ni->ni_code); + break; + } + flags = ntohs(pkt_ni->ni_flags); + printf("\tFlags: %s%s%s%s%s%s%s\n", ((flags & NI_NODEADDR_FLAG_GLOBAL) ? "G" : ""), + ((flags & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : ""), ((flags & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : ""), + ((flags & NI_NODEADDR_FLAG_COMPAT) ? "C" : ""), ((flags & NI_NODEADDR_FLAG_ALL) ? "A" : ""), + ((flags & NI_NODEADDR_FLAG_TRUNCATE) ? "T" : ""), ((!flags) ? "none" : "")); + + pkt_nidata = (struct ni_reply_ip *)((char *)pkt_ni + sizeof(struct icmp6_nodeinfo)); + + while ((pkt_end - (unsigned char *)pkt_nidata) >= sizeof(struct ni_reply_ip)) { + if (inet_ntop(AF_INET, &(pkt_nidata->ip), pv6addr, sizeof(pv6addr)) == NULL) { + if (idata->verbose_f) + puts("inet_ntop(): Error converting IPv4 Address to presentation format"); + + return (-1); + } + + printf("\t%s (TTL: %lu%s)\n", pv6addr, (LUI)pkt_nidata->ni_ip_ttl, + (pkt_nidata->ni_ip_ttl == 0xffffffff) ? " (infinity)" : ""); + + pkt_nidata++; + } + + if ((unsigned char *)pkt_nidata != pkt_end) { + puts("Incomplete data in received NI Reply\n"); + } + else { + puts(""); + } + + return (0); +} /* * Function: print_ni_noop() @@ -1476,142 +1448,136 @@ int print_ni_addr(struct iface_data *idata, const u_char *pktdata, struct pcap_p * Print responses to NOOP ICMPv6 NI queries */ -int print_ni_noop(struct iface_data *idata, const u_char *pktdata, struct pcap_pkthdr * pkthdr){ - struct ether_header *pkt_ether; - struct ip6_hdr *pkt_ipv6; - struct icmp6_nodeinfo *pkt_ni; - unsigned char *pkt_end; +int print_ni_noop(struct iface_data *idata, const u_char *pktdata, struct pcap_pkthdr *pkthdr) { + struct ether_header *pkt_ether; + struct ip6_hdr *pkt_ipv6; + struct icmp6_nodeinfo *pkt_ni; + unsigned char *pkt_end; - pkt_ether = (struct ether_header *) pktdata; - pkt_ipv6 = (struct ip6_hdr *)((char *) pkt_ether + idata->linkhsize); - pkt_ni= (struct icmp6_nodeinfo *) ((char *) pkt_ipv6 + sizeof(struct ip6_hdr)); - pkt_end = (unsigned char *) pktdata + pkthdr->caplen; + pkt_ether = (struct ether_header *)pktdata; + pkt_ipv6 = (struct ip6_hdr *)((char *)pkt_ether + idata->linkhsize); + pkt_ni = (struct icmp6_nodeinfo *)((char *)pkt_ipv6 + sizeof(struct ip6_hdr)); + pkt_end = (unsigned char *)pktdata + pkthdr->caplen; - if( pkt_end > ((unsigned char *)pkt_ni + ntohs(pkt_ipv6->ip6_plen)) ) - pkt_end = (unsigned char *)pkt_ni + ntohs(pkt_ipv6->ip6_plen); + if (pkt_end > ((unsigned char *)pkt_ni + ntohs(pkt_ipv6->ip6_plen))) + pkt_end = (unsigned char *)pkt_ni + ntohs(pkt_ipv6->ip6_plen); - if(!is_eq_in6_addr(&(pkt_ipv6->ip6_dst), &(idata->srcaddr))) - return 0; + if (!is_eq_in6_addr(&(pkt_ipv6->ip6_dst), &(idata->srcaddr))) + return 0; - if(inet_ntop(AF_INET6, &(pkt_ipv6->ip6_src), pv6addr, sizeof(pv6addr)) == NULL){ - if(idata->verbose_f) - puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); + if (inet_ntop(AF_INET6, &(pkt_ipv6->ip6_src), pv6addr, sizeof(pv6addr)) == NULL) { + if (idata->verbose_f) + puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); - return(-1); - } + return (-1); + } - printf("Response from: %s\n", pv6addr); + printf("Response from: %s\n", pv6addr); - switch(pkt_ni->ni_code){ - case 0: - puts("\tCode: 0 (Successful reply)\n"); - break; + switch (pkt_ni->ni_code) { + case 0: + puts("\tCode: 0 (Successful reply)\n"); + break; - case 1: - puts("\tCode: 1 (Node refuses to supply the answer)\n"); - break; + case 1: + puts("\tCode: 1 (Node refuses to supply the answer)\n"); + break; - case 2: - puts("\tCode: 2 (Qtype unknown to the responder)\n"); - break; + case 2: + puts("\tCode: 2 (Qtype unknown to the responder)\n"); + break; - default: - printf("\tCode: %u (Qtype unknown)\n\n", pkt_ni->ni_code); - break; - } + default: + printf("\tCode: %u (Qtype unknown)\n\n", pkt_ni->ni_code); + break; + } - return(0); + return (0); } - /* * Function: print_ni_addr6() * * Print responses to ICMPv6 NI queries for IPv6 addresses */ -int print_ni_addr6(struct iface_data *idata, const u_char *pktdata, struct pcap_pkthdr * pkthdr){ - struct ether_header *pkt_ether; - struct ip6_hdr *pkt_ipv6; - struct icmp6_nodeinfo *pkt_ni; - unsigned char *pkt_end; - uint16_t flags; - struct ni_reply_ip6 *pkt_nidata; - - pkt_ether = (struct ether_header *) pktdata; - pkt_ipv6 = (struct ip6_hdr *)((char *) pkt_ether + idata->linkhsize); - pkt_ni= (struct icmp6_nodeinfo *) ((char *) pkt_ipv6 + sizeof(struct ip6_hdr)); - pkt_end = (unsigned char *) pktdata + pkthdr->caplen; - - if( pkt_end > ((unsigned char *)pkt_ni + ntohs(pkt_ipv6->ip6_plen)) ) - pkt_end = (unsigned char *)pkt_ni + ntohs(pkt_ipv6->ip6_plen); - - if(!is_eq_in6_addr(&(pkt_ipv6->ip6_dst), &(idata->srcaddr))) - return 0; - - if(inet_ntop(AF_INET6, &(pkt_ipv6->ip6_src), pv6addr, sizeof(pv6addr)) == NULL){ - if(idata->verbose_f) - puts("inet_ntop(): Error converting IPv6 Address to presentation format"); - - return(-1); - } - - printf("Response from: %s\n", pv6addr); - - switch(pkt_ni->ni_code){ - case 0: - printf("\tCode: 0 (Successful reply)"); - break; - - case 1: - printf("\tCode: 1 (Node refuses to supply the answer)"); - break; - - case 2: - printf("\tCode: 2 (Qtype unknown to the responder)"); - break; - - default: - printf("\tCode: %u (Qtype unknown)", pkt_ni->ni_code); - break; - } - - flags= ntohs(pkt_ni->ni_flags); - printf("\tFlags: %s%s%s%s%s%s%s\n", ((flags & NI_NODEADDR_FLAG_GLOBAL)?"G":""), \ - ((flags & NI_NODEADDR_FLAG_SITELOCAL)?"S":""), \ - ((flags & NI_NODEADDR_FLAG_LINKLOCAL)?"L":""), \ - ((flags & NI_NODEADDR_FLAG_COMPAT)?"C":""),\ - ((flags & NI_NODEADDR_FLAG_ALL)?"A":""), \ - ((flags & NI_NODEADDR_FLAG_TRUNCATE)?"T":""),\ - ((!flags)?"none":"")); - - pkt_nidata= (struct ni_reply_ip6 *) ((char *)pkt_ni + sizeof(struct icmp6_nodeinfo)); - - while( (pkt_end - (unsigned char *) pkt_nidata) >= sizeof(struct ni_reply_ip6)){ - if(inet_ntop(AF_INET6, &(pkt_nidata->ip6), pv6addr, sizeof(pv6addr)) == NULL){ - if(idata->verbose_f) - puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); - - return(-1); - } - - printf("\t%s (TTL: %lu%s)\n", pv6addr, (LUI) pkt_nidata->ni_ip6_ttl,\ - (pkt_nidata->ni_ip6_ttl==0xffffffff)?" (infinity)":""); - - pkt_nidata++; - } - - if( (unsigned char *)pkt_nidata != pkt_end){ - puts("Incomplete data in received NI Reply\n"); - } - else{ - puts(""); - } - - return(0); -} +int print_ni_addr6(struct iface_data *idata, const u_char *pktdata, struct pcap_pkthdr *pkthdr) { + struct ether_header *pkt_ether; + struct ip6_hdr *pkt_ipv6; + struct icmp6_nodeinfo *pkt_ni; + unsigned char *pkt_end; + uint16_t flags; + struct ni_reply_ip6 *pkt_nidata; + + pkt_ether = (struct ether_header *)pktdata; + pkt_ipv6 = (struct ip6_hdr *)((char *)pkt_ether + idata->linkhsize); + pkt_ni = (struct icmp6_nodeinfo *)((char *)pkt_ipv6 + sizeof(struct ip6_hdr)); + pkt_end = (unsigned char *)pktdata + pkthdr->caplen; + + if (pkt_end > ((unsigned char *)pkt_ni + ntohs(pkt_ipv6->ip6_plen))) + pkt_end = (unsigned char *)pkt_ni + ntohs(pkt_ipv6->ip6_plen); + + if (!is_eq_in6_addr(&(pkt_ipv6->ip6_dst), &(idata->srcaddr))) + return 0; + + if (inet_ntop(AF_INET6, &(pkt_ipv6->ip6_src), pv6addr, sizeof(pv6addr)) == NULL) { + if (idata->verbose_f) + puts("inet_ntop(): Error converting IPv6 Address to presentation format"); + + return (-1); + } + + printf("Response from: %s\n", pv6addr); + + switch (pkt_ni->ni_code) { + case 0: + printf("\tCode: 0 (Successful reply)"); + break; + + case 1: + printf("\tCode: 1 (Node refuses to supply the answer)"); + break; + + case 2: + printf("\tCode: 2 (Qtype unknown to the responder)"); + break; + + default: + printf("\tCode: %u (Qtype unknown)", pkt_ni->ni_code); + break; + } + flags = ntohs(pkt_ni->ni_flags); + printf("\tFlags: %s%s%s%s%s%s%s\n", ((flags & NI_NODEADDR_FLAG_GLOBAL) ? "G" : ""), + ((flags & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : ""), ((flags & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : ""), + ((flags & NI_NODEADDR_FLAG_COMPAT) ? "C" : ""), ((flags & NI_NODEADDR_FLAG_ALL) ? "A" : ""), + ((flags & NI_NODEADDR_FLAG_TRUNCATE) ? "T" : ""), ((!flags) ? "none" : "")); + pkt_nidata = (struct ni_reply_ip6 *)((char *)pkt_ni + sizeof(struct icmp6_nodeinfo)); + + while ((pkt_end - (unsigned char *)pkt_nidata) >= sizeof(struct ni_reply_ip6)) { + if (inet_ntop(AF_INET6, &(pkt_nidata->ip6), pv6addr, sizeof(pv6addr)) == NULL) { + if (idata->verbose_f) + puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); + + return (-1); + } + + printf("\t%s (TTL: %lu%s)\n", pv6addr, (LUI)pkt_nidata->ni_ip6_ttl, + (pkt_nidata->ni_ip6_ttl == 0xffffffff) ? " (infinity)" : ""); + + pkt_nidata++; + } + + if ((unsigned char *)pkt_nidata != pkt_end) { + puts("Incomplete data in received NI Reply\n"); + } + else { + puts(""); + } + + return (0); +} /* * Function: print_ni_name() @@ -1619,67 +1585,66 @@ int print_ni_addr6(struct iface_data *idata, const u_char *pktdata, struct pcap_ * Print responses to ICMPv6 NI queries for names */ -int print_ni_name(struct iface_data *idata, const u_char *pktdata, struct pcap_pkthdr * pkthdr){ - struct ether_header *pkt_ether; - struct ip6_hdr *pkt_ipv6; - struct icmp6_nodeinfo *pkt_ni; - unsigned char *pkt_end; - struct ni_reply_name *pkt_nidata; - unsigned char *start, *next; +int print_ni_name(struct iface_data *idata, const u_char *pktdata, struct pcap_pkthdr *pkthdr) { + struct ether_header *pkt_ether; + struct ip6_hdr *pkt_ipv6; + struct icmp6_nodeinfo *pkt_ni; + unsigned char *pkt_end; + struct ni_reply_name *pkt_nidata; + unsigned char *start, *next; - pkt_ether = (struct ether_header *) pktdata; - pkt_ipv6 = (struct ip6_hdr *)((char *) pkt_ether + idata->linkhsize); - pkt_ni= (struct icmp6_nodeinfo *) ((char *) pkt_ipv6 + sizeof(struct ip6_hdr)); - pkt_end = (unsigned char *) pktdata + pkthdr->caplen; + pkt_ether = (struct ether_header *)pktdata; + pkt_ipv6 = (struct ip6_hdr *)((char *)pkt_ether + idata->linkhsize); + pkt_ni = (struct icmp6_nodeinfo *)((char *)pkt_ipv6 + sizeof(struct ip6_hdr)); + pkt_end = (unsigned char *)pktdata + pkthdr->caplen; - if( pkt_end > ((unsigned char *)pkt_ni + ntohs(pkt_ipv6->ip6_plen)) ) - pkt_end = (unsigned char *)pkt_ni + ntohs(pkt_ipv6->ip6_plen); + if (pkt_end > ((unsigned char *)pkt_ni + ntohs(pkt_ipv6->ip6_plen))) + pkt_end = (unsigned char *)pkt_ni + ntohs(pkt_ipv6->ip6_plen); - if(!is_eq_in6_addr(&(pkt_ipv6->ip6_dst), &(idata->srcaddr))) - return 0; + if (!is_eq_in6_addr(&(pkt_ipv6->ip6_dst), &(idata->srcaddr))) + return 0; - if(inet_ntop(AF_INET6, &(pkt_ipv6->ip6_src), pv6addr, sizeof(pv6addr)) == NULL){ - if(idata->verbose_f) - puts("inet_ntop(): Error converting IPv6 Address to presentation format"); + if (inet_ntop(AF_INET6, &(pkt_ipv6->ip6_src), pv6addr, sizeof(pv6addr)) == NULL) { + if (idata->verbose_f) + puts("inet_ntop(): Error converting IPv6 Address to presentation format"); - return(-1); - } + return (-1); + } - printf("Response from: %s\n", pv6addr); + printf("Response from: %s\n", pv6addr); - switch(pkt_ni->ni_code){ - case 0: - puts("\tCode: 0 (Successful reply)"); - break; + switch (pkt_ni->ni_code) { + case 0: + puts("\tCode: 0 (Successful reply)"); + break; - case 1: - puts("\tCode: 1 (Node refuses to supply the answer)"); - break; + case 1: + puts("\tCode: 1 (Node refuses to supply the answer)"); + break; - case 2: - puts("\tCode: 2 (Qtype unknown to the responder)"); - break; + case 2: + puts("\tCode: 2 (Qtype unknown to the responder)"); + break; - default: - printf("\tCode: %u (Qtype unknown)\n", pkt_ni->ni_code); - break; - } + default: + printf("\tCode: %u (Qtype unknown)\n", pkt_ni->ni_code); + break; + } - pkt_nidata= (struct ni_reply_name *) ((char *)pkt_ni + sizeof(struct icmp6_nodeinfo)); - start= (unsigned char *) pkt_nidata; - next= (unsigned char *) &(pkt_nidata->ni_name_name); + pkt_nidata = (struct ni_reply_name *)((char *)pkt_ni + sizeof(struct icmp6_nodeinfo)); + start = (unsigned char *)pkt_nidata; + next = (unsigned char *)&(pkt_nidata->ni_name_name); - while(next != NULL && dns_decode(start, pkt_end-start, next, domain, sizeof(domain), &next) == 0){ - printf("\t%s (TTL: %lu%s)\n", domain, (LUI) pkt_nidata->ni_name_ttl,\ - (pkt_nidata->ni_name_ttl==0xffffffff)?" (infinity)":""); - } + while (next != NULL && dns_decode(start, pkt_end - start, next, domain, sizeof(domain), &next) == 0) { + printf("\t%s (TTL: %lu%s)\n", domain, (LUI)pkt_nidata->ni_name_ttl, + (pkt_nidata->ni_name_ttl == 0xffffffff) ? " (infinity)" : ""); + } - puts(""); + puts(""); - return(0); + return (0); } - /* * Function: init_packet_data() * @@ -1687,928 +1652,914 @@ int print_ni_name(struct iface_data *idata, const u_char *pktdata, struct pcap_p * that are expected to remain constant for the specified attack. */ -void init_packet_data(struct iface_data *idata){ - struct dlt_null *dlt_null; - ethernet= (struct ether_header *) buffer; - dlt_null= (struct dlt_null *) buffer; - v6buffer = buffer + idata->linkhsize; - ipv6 = (struct ip6_hdr *) v6buffer; - - if(idata->type == DLT_EN10MB){ - ethernet->ether_type = htons(ETHERTYPE_IPV6); - - if(!(idata->flags & IFACE_LOOPBACK)){ - ethernet->src = idata->hsrcaddr; - ethernet->dst = idata->hdstaddr; - } - } - else if(idata->type == DLT_NULL){ - dlt_null->family= PF_INET6; - } -#if defined (__OpenBSD__) - else if(idata->type == DLT_LOOP){ - dlt_null->family= htonl(PF_INET6); - } +void init_packet_data(struct iface_data *idata) { + struct dlt_null *dlt_null; + ethernet = (struct ether_header *)buffer; + dlt_null = (struct dlt_null *)buffer; + v6buffer = buffer + idata->linkhsize; + ipv6 = (struct ip6_hdr *)v6buffer; + + if (idata->type == DLT_EN10MB) { + ethernet->ether_type = htons(ETHERTYPE_IPV6); + + if (!(idata->flags & IFACE_LOOPBACK)) { + ethernet->src = idata->hsrcaddr; + ethernet->dst = idata->hdstaddr; + } + } + else if (idata->type == DLT_NULL) { + dlt_null->family = PF_INET6; + } +#if defined(__OpenBSD__) + else if (idata->type == DLT_LOOP) { + dlt_null->family = htonl(PF_INET6); + } #endif - ipv6->ip6_flow=0; - ipv6->ip6_vfc= 0x60; - ipv6->ip6_hlim= hoplimit; - ipv6->ip6_src= idata->srcaddr; - - ipv6->ip6_dst= idata->dstaddr; - prev_nh = (unsigned char *) &(ipv6->ip6_nxt); - ptr = (unsigned char *) v6buffer + MIN_IPV6_HLEN; - - if(hbhopthdr_f){ - hbhopthdrs=0; - - while(hbhopthdrs < nhbhopthdr){ - if((ptr+ hbhopthdrlen[hbhopthdrs]) > (v6buffer+ idata->mtu)){ - puts("Packet too large while processing HBH Opt. Header"); - exit(EXIT_FAILURE); - } - - *prev_nh = IPPROTO_HOPOPTS; - prev_nh = ptr; - memcpy(ptr, hbhopthdr[hbhopthdrs], hbhopthdrlen[hbhopthdrs]); - ptr = ptr + hbhopthdrlen[hbhopthdrs]; - hbhopthdrs++; - } - } - - if(dstoptuhdr_f){ - dstoptuhdrs=0; - - while(dstoptuhdrs < ndstoptuhdr){ - if((ptr+ dstoptuhdrlen[dstoptuhdrs]) > (v6buffer+ idata->mtu)){ - puts("Packet too large while processing Dest. Opt. Header (Unfrag. Part)"); - exit(EXIT_FAILURE); - } - - *prev_nh = IPPROTO_DSTOPTS; - prev_nh = ptr; - memcpy(ptr, dstoptuhdr[dstoptuhdrs], dstoptuhdrlen[dstoptuhdrs]); - ptr = ptr + dstoptuhdrlen[dstoptuhdrs]; - dstoptuhdrs++; - } - } - - /* Everything that follows is the Fragmentable Part of the packet */ - fragpart = ptr; - - if(idata->fragh_f){ - /* Check that we are able to send the Unfragmentable Part, together with a - Fragment Header and a chunk data over our link layer - */ - if( (fragpart+sizeof(fraghdr)+nfrags) > (v6buffer+idata->mtu)){ - printf("Unfragmentable part too large for current MTU (%u bytes)\n", idata->mtu); - exit(EXIT_FAILURE); - } - - /* We prepare a separate Fragment Header, but we do not include it in the packet to be sent. - This Fragment Header will be used (an assembled with the rest of the packet by the - send_packet() function. - */ - memset(&fraghdr, 0, FRAG_HDR_SIZE); - *prev_nh = IPPROTO_FRAGMENT; - prev_nh = (unsigned char *) &fraghdr; - } - - if(dstopthdr_f){ - dstopthdrs=0; - - while(dstopthdrs < ndstopthdr){ - if((ptr+ dstopthdrlen[dstopthdrs]) > (v6buffer+ idata->max_packet_size)){ - puts("Packet too large while processing Dest. Opt. Header (should be using the Frag. option?)"); - exit(EXIT_FAILURE); - } - - *prev_nh = IPPROTO_DSTOPTS; - prev_nh = ptr; - memcpy(ptr, dstopthdr[dstopthdrs], dstopthdrlen[dstopthdrs]); - ptr = ptr + dstopthdrlen[dstopthdrs]; - dstopthdrs++; - } - } - - - *prev_nh = IPPROTO_ICMPV6; - startofprefixes=ptr; + ipv6->ip6_flow = 0; + ipv6->ip6_vfc = 0x60; + ipv6->ip6_hlim = hoplimit; + ipv6->ip6_src = idata->srcaddr; + + ipv6->ip6_dst = idata->dstaddr; + prev_nh = (unsigned char *)&(ipv6->ip6_nxt); + ptr = (unsigned char *)v6buffer + MIN_IPV6_HLEN; + + if (hbhopthdr_f) { + hbhopthdrs = 0; + + while (hbhopthdrs < nhbhopthdr) { + if ((ptr + hbhopthdrlen[hbhopthdrs]) > (v6buffer + idata->mtu)) { + puts("Packet too large while processing HBH Opt. Header"); + exit(EXIT_FAILURE); + } + + *prev_nh = IPPROTO_HOPOPTS; + prev_nh = ptr; + memcpy(ptr, hbhopthdr[hbhopthdrs], hbhopthdrlen[hbhopthdrs]); + ptr = ptr + hbhopthdrlen[hbhopthdrs]; + hbhopthdrs++; + } + } + + if (dstoptuhdr_f) { + dstoptuhdrs = 0; + + while (dstoptuhdrs < ndstoptuhdr) { + if ((ptr + dstoptuhdrlen[dstoptuhdrs]) > (v6buffer + idata->mtu)) { + puts("Packet too large while processing Dest. Opt. Header (Unfrag. Part)"); + exit(EXIT_FAILURE); + } + + *prev_nh = IPPROTO_DSTOPTS; + prev_nh = ptr; + memcpy(ptr, dstoptuhdr[dstoptuhdrs], dstoptuhdrlen[dstoptuhdrs]); + ptr = ptr + dstoptuhdrlen[dstoptuhdrs]; + dstoptuhdrs++; + } + } + + /* Everything that follows is the Fragmentable Part of the packet */ + fragpart = ptr; + + if (idata->fragh_f) { + /* Check that we are able to send the Unfragmentable Part, together with a + Fragment Header and a chunk data over our link layer + */ + if ((fragpart + sizeof(fraghdr) + nfrags) > (v6buffer + idata->mtu)) { + printf("Unfragmentable part too large for current MTU (%u bytes)\n", idata->mtu); + exit(EXIT_FAILURE); + } + + /* We prepare a separate Fragment Header, but we do not include it in the packet to be sent. + This Fragment Header will be used (an assembled with the rest of the packet by the + send_packet() function. + */ + memset(&fraghdr, 0, FRAG_HDR_SIZE); + *prev_nh = IPPROTO_FRAGMENT; + prev_nh = (unsigned char *)&fraghdr; + } + + if (dstopthdr_f) { + dstopthdrs = 0; + + while (dstopthdrs < ndstopthdr) { + if ((ptr + dstopthdrlen[dstopthdrs]) > (v6buffer + idata->max_packet_size)) { + puts("Packet too large while processing Dest. Opt. Header (should be using the Frag. option?)"); + exit(EXIT_FAILURE); + } + + *prev_nh = IPPROTO_DSTOPTS; + prev_nh = ptr; + memcpy(ptr, dstopthdr[dstopthdrs], dstopthdrlen[dstopthdrs]); + ptr = ptr + dstopthdrlen[dstopthdrs]; + dstopthdrs++; + } + } + + *prev_nh = IPPROTO_ICMPV6; + startofprefixes = ptr; } - - /* * Function: send_packet() * * Initialize the remaining fields of the Neighbor Advertisement Message, and * send the attack packet(s). */ -int send_packet(struct iface_data *idata, const u_char *pktdata, struct pcap_pkthdr * pkthdr){ - ptr=startofprefixes; - - if(pktdata != NULL){ /* Sending a NI Reply in response to a received query */ - pkt_ether = (struct ether_header *) pktdata; - pkt_ipv6 = (struct ip6_hdr *)((char *) pkt_ether + idata->linkhsize); - pkt_ni= (struct icmp6_nodeinfo *) ( (unsigned char *)pkt_ipv6 + sizeof (struct ip6_hdr)); - - /* If the IPv6 Source Address of the incoming Neighbor Solicitation is the unspecified - address (::), the Neighbor Advertisement must be directed to the IPv6 all-nodes - multicast address (and the Ethernet Destination address should be 33:33:33:00:00:01). - Otherwise, the Neighbor Advertisement is sent to the IPv6 Source Address (and - Ethernet Source Address) of the incoming Neighbor Solicitation message - */ - pkt_ipv6addr = &(pkt_ipv6->ip6_src); - - /* - We don't send any packets if the Source Address of the captured packet is the unspecified - address. - */ - if(IN6_IS_ADDR_UNSPECIFIED(pkt_ipv6addr)){ - return 0; - } - else{ - ipv6->ip6_dst = pkt_ipv6->ip6_src; - ethernet->dst = pkt_ether->src; - } - - pkt_ipv6addr = &(pkt_ipv6->ip6_dst); - - /* - If the query was sent to a multicast address, we respond with a forged link-local address. - Otherwise we respond to the unicast address that elicited our response - - XXX: [fgont] Changed - */ - if(IN6_IS_ADDR_MULTICAST(pkt_ipv6addr)){ - ipv6->ip6_src= idata->srcaddr; - ethernet->src= idata->hsrcaddr; - } - else{ - ipv6->ip6_src= pkt_ipv6->ip6_dst; - ethernet->src= pkt_ether->dst; - } - - ni= (struct icmp6_nodeinfo *) ptr; - ni->ni_type= ICMP6_NI_REPLY; - ni->ni_code= 0; - ni->ni_qtype= pkt_ni->ni_qtype; - ni->ni_flags= pkt_ni->ni_flags; - - for(i=0; i<8; i++) - ni->icmp6_ni_nonce[i]= pkt_ni->icmp6_ni_nonce[i]; - - ptr= ptr + sizeof(struct icmp6_nodeinfo); - - switch(ntohs(pkt_ni->ni_qtype)){ - case NI_QTYPE_NOOP: - break; - - case NI_QTYPE_SUPTYPES: - break; - - case NI_QTYPE_DNSNAME: - if(dloopattack_f){ - if((ptr+(dlsize+4)) > (v6buffer + idata->max_packet_size)){ - if(idata->verbose_f) - puts("Packet too large while inserting name payload"); - - return(-1); - } - - memset(ptr, 0, 4); - ptr+=4; - memcpy(ptr, dlpointer, dlsize); - ptr+= dlsize; - } - else if(named_f){ - if((ptr+ (namedlen+4)) > (v6buffer + idata->max_packet_size)){ - if(idata->verbose_f) - puts("Packet too large while inserting name"); - - return(-1); - } - - /* The response contains a TTL, and it is set to 0 */ - memset(ptr, 0, 4); - ptr+= 4; - - memcpy(ptr, named, namedlen); - ptr+= namedlen; - - if(snamedslabel_f){ - if((ptr+1) > (v6buffer + idata->max_packet_size)){ - if(idata->verbose_f) - puts("Error while inserting last label"); - - return(-1); - } - else{ - *ptr=0; - ptr++; - } - } - } - else if(fnamed_f && fnamedlen>0){ - - if((ptr+ (fnamedlen+4)) > (v6buffer + idata->max_packet_size)){ - if(idata->verbose_f) - puts("Packet too large when inserting forged name"); - - return(-1); - } - - /* The response contains a TTL, and it is set to 0 */ - memset(ptr, 0, 4); - ptr+= 4; - - i=fnamedlen-1; /* There is a zero-length label at the end */ - - if(snamedslabel_f && i>0) - i=i-1; - - while(i>0){ - if(i<= (maxlabel+1)){ - /* This accounts for the length byte */ - i=i-1; - *ptr=i; - ptr++; - - for(j=0; j1){ - if((ptr+1) > (v6buffer + idata->max_packet_size)){ - return(-1); - } - else{ - *ptr=0; - ptr++; - } - } - } - else if(exceedpd_f){ - if( (ptr+5) > (v6buffer + idata->max_packet_size)){ - if(idata->verbose_f) - puts("Packet too large whil inserting 'exceeding' name"); - - return(-1); - } - - /* The response contains a TTL, and it is set to 0 */ - memset(ptr, 0, 4); - ptr+= 4; - - *ptr= exceedpd; - ptr++; - } - else if(payloadsize_f){ - if(payloadsize>=4) - payloadsize-=4; - - if((ptr+(payloadsize+4)) > (v6buffer + idata->max_packet_size)){ - if(idata->verbose_f) - puts("Packet too large while inserting randomized payload"); - - return(-1); - } - - /* The response contains a TTL, and it is set to 0 */ - memset(ptr, 0, 4); - ptr+= 4; - - for(i=0; i (v6buffer + idata->max_packet_size)){ - if(idata->verbose_f) - puts("Packet too large when inserting IPv6 address"); - - return(-1); - } - - *(struct in6_addr *)ptr= ipv6addrd; - ptr= ptr+ sizeof(struct in6_addr); - } - else if(payloadsize_f){ - if((ptr+payloadsize) > (v6buffer + idata->max_packet_size)){ - if(idata->verbose_f) - puts("Packet too large while inserting randomized payload"); - - return(-1); - } - - for(i=0; i (v6buffer + idata->max_packet_size)){ - if(idata->verbose_f) - puts("Packet too large while inserting IPv4 address"); - - return(-1); - } - - *(struct in_addr *)ptr= ipv4addrd; - ptr= ptr+ sizeof(struct in_addr); - } - else if(payloadsize_f){ - if((ptr+payloadsize) > (v6buffer + idata->max_packet_size)){ - if(idata->verbose_f) - puts("Packet too large while inserting randomized payload"); - - return(-1); - } - - for(i=0; ini_type= ICMP6_NI_QUERY; - ni->ni_code= code; - ni->ni_qtype= htons(qtype); - ni->ni_flags= htons(flags); - - for(i=0; i<8; i++) - ni->icmp6_ni_nonce[i]= random(); - - ptr= ptr + sizeof(struct icmp6_nodeinfo); - - if(ipv4addr_f){ - if( (ptr+sizeof(struct in_addr)) > (v6buffer + idata->max_packet_size)){ - if(idata->verbose_f) - puts("Packet too large while inserting IPv4 address"); - - return(-1); - } - - *(struct in_addr *)ptr= ipv4addr; - ptr= ptr+ sizeof(struct in_addr); - } - else if(ipv6addr_f){ - if( (ptr+sizeof(struct in6_addr)) > (v6buffer + idata->max_packet_size)){ - if(idata->verbose_f) - puts("Packet too large while inserting IPv6 address"); - - return(-1); - } - - *(struct in6_addr *)ptr= ipv6addr; - ptr= ptr+ sizeof(struct in6_addr); - } - else if(name_f){ - if((ptr+namelen) > (v6buffer + idata->max_packet_size)){ - if(idata->verbose_f) - puts("Packet too large while inserting name"); - - return(-1); - } - - memcpy(ptr, name, namelen); - ptr+= namelen; - - if(snameslabel_f){ - if((ptr+1) > (v6buffer + idata->max_packet_size)){ - if(idata->verbose_f) - puts("Error while inserting last label"); - - return(-1); - } - else{ - *ptr=0; - ptr++; - } - } - } - else if(fname_f && fnamelen>0){ - - if((ptr+fnamelen) > (v6buffer + idata->max_packet_size)){ - if(idata->verbose_f) - puts("Packet too large when inserting forged name"); - - return(-1); - } - - i=fnamelen-1; /* There is a zero-length label at the end */ - - if(snameslabel_f && i>0) - i=i-1; - - while(i>0){ - if(i<= (maxlabel+1)){ - /* This accounts for the length byte */ - i=i-1; - *ptr=i; - ptr++; - - for(j=0; j1){ - if((ptr+1) > (v6buffer + idata->max_packet_size)){ - return(-1); - } - else{ - *ptr=0; - ptr++; - } - } - } - else if(exceedp_f){ - if( (ptr+1) > (v6buffer + idata->max_packet_size)){ - if(idata->verbose_f) - puts("Packet too large when 'exceeding' name"); - - return(-1); - } - - *ptr= exceedp; - ptr++; - } - else if(payloadsize_f){ - if((ptr+payloadsize) > (v6buffer + idata->max_packet_size)){ - if(idata->verbose_f) - puts("Packet too large while inserting randomized payload"); - - return(-1); - } - - for(i=0; i (v6buffer + idata->max_packet_size)){ - if(idata->verbose_f) - puts("Packet too large while inserting name payload"); - - return(-1); - } - - memset(ptr, 0, 4); - ptr+=4; - memcpy(ptr, slpointer, slsize); - ptr+= slsize; - } - } - - ni->ni_cksum = 0; - ni->ni_cksum = in_chksum(v6buffer, ni, ptr-(unsigned char *)ni, IPPROTO_ICMPV6); - - if(!idata->fragh_f){ - ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); - - if((nw=pcap_inject(idata->pfd, buffer, ptr - buffer)) == -1){ - if(idata->verbose_f) - printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); - - return(-1); - } - - if(nw != (ptr-buffer)){ - if(idata->verbose_f) - printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, (LUI) (ptr-buffer)); - - return(-1); - } - } - else{ - ptrend= ptr; - ptr= fragpart; - fptr = fragbuffer; - fipv6 = (struct ip6_hdr *) (fragbuffer + idata->linkhsize); - fptrend = fptr + idata->linkhsize+MIN_IPV6_HLEN+MAX_IPV6_PAYLOAD; - memcpy(fptr, buffer, fragpart-buffer); - fptr = fptr + (fragpart-buffer); - - if( (fptr+FRAG_HDR_SIZE)> fptrend){ - if(idata->verbose_f) - puts("Unfragmentable Part is Too Large"); - - return(-1); - } - - memcpy(fptr, (char *) &fraghdr, FRAG_HDR_SIZE); - fh= (struct ip6_frag *) fptr; - fh->ip6f_ident=random(); - startoffragment = fptr + FRAG_HDR_SIZE; - - /* - * Check that the selected fragment size is not larger than the largest - * fragment size that can be sent - */ - if(nfrags > (fptrend - fptr)) - nfrags= (fptrend-fptr); - - m=IP6F_MORE_FRAG; - - while((ptr< ptrend) && m==IP6F_MORE_FRAG){ - fptr= startoffragment; - - if( (ptrend-ptr) <= nfrags){ - fragsize= ptrend-ptr; - m=0; - } - else{ - fragsize = (nfrags + 7) & ntohs(IP6F_OFF_MASK); - } - - memcpy(fptr, ptr, fragsize); - fh->ip6f_offlg = (htons(ptr-fragpart) & IP6F_OFF_MASK) | m; - ptr+=fragsize; - fptr+=fragsize; - - fipv6->ip6_plen = htons((fptr - fragbuffer) - MIN_IPV6_HLEN - idata->linkhsize); - - if((nw=pcap_inject(idata->pfd, fragbuffer, fptr - fragbuffer)) == -1){ - if(idata->verbose_f) - printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); - - return(-1); - } - - if(nw != (fptr- fragbuffer)){ - if(idata->verbose_f) - printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, (LUI) (ptr-buffer)); - - return(-1); - } - } /* Sending fragments */ - } /* Sending fragmented datagram */ - - return 0; +int send_packet(struct iface_data *idata, const u_char *pktdata, struct pcap_pkthdr *pkthdr) { + ptr = startofprefixes; + + if (pktdata != NULL) { /* Sending a NI Reply in response to a received query */ + pkt_ether = (struct ether_header *)pktdata; + pkt_ipv6 = (struct ip6_hdr *)((char *)pkt_ether + idata->linkhsize); + pkt_ni = (struct icmp6_nodeinfo *)((unsigned char *)pkt_ipv6 + sizeof(struct ip6_hdr)); + + /* If the IPv6 Source Address of the incoming Neighbor Solicitation is the unspecified + address (::), the Neighbor Advertisement must be directed to the IPv6 all-nodes + multicast address (and the Ethernet Destination address should be 33:33:33:00:00:01). + Otherwise, the Neighbor Advertisement is sent to the IPv6 Source Address (and + Ethernet Source Address) of the incoming Neighbor Solicitation message + */ + pkt_ipv6addr = &(pkt_ipv6->ip6_src); + + /* + We don't send any packets if the Source Address of the captured packet is the unspecified + address. + */ + if (IN6_IS_ADDR_UNSPECIFIED(pkt_ipv6addr)) { + return 0; + } + else { + ipv6->ip6_dst = pkt_ipv6->ip6_src; + ethernet->dst = pkt_ether->src; + } + + pkt_ipv6addr = &(pkt_ipv6->ip6_dst); + + /* + If the query was sent to a multicast address, we respond with a forged link-local address. + Otherwise we respond to the unicast address that elicited our response + + XXX: [fgont] Changed + */ + if (IN6_IS_ADDR_MULTICAST(pkt_ipv6addr)) { + ipv6->ip6_src = idata->srcaddr; + ethernet->src = idata->hsrcaddr; + } + else { + ipv6->ip6_src = pkt_ipv6->ip6_dst; + ethernet->src = pkt_ether->dst; + } + + ni = (struct icmp6_nodeinfo *)ptr; + ni->ni_type = ICMP6_NI_REPLY; + ni->ni_code = 0; + ni->ni_qtype = pkt_ni->ni_qtype; + ni->ni_flags = pkt_ni->ni_flags; + + for (i = 0; i < 8; i++) + ni->icmp6_ni_nonce[i] = pkt_ni->icmp6_ni_nonce[i]; + + ptr = ptr + sizeof(struct icmp6_nodeinfo); + + switch (ntohs(pkt_ni->ni_qtype)) { + case NI_QTYPE_NOOP: + break; + + case NI_QTYPE_SUPTYPES: + break; + + case NI_QTYPE_DNSNAME: + if (dloopattack_f) { + if ((ptr + (dlsize + 4)) > (v6buffer + idata->max_packet_size)) { + if (idata->verbose_f) + puts("Packet too large while inserting name payload"); + + return (-1); + } + + memset(ptr, 0, 4); + ptr += 4; + memcpy(ptr, dlpointer, dlsize); + ptr += dlsize; + } + else if (named_f) { + if ((ptr + (namedlen + 4)) > (v6buffer + idata->max_packet_size)) { + if (idata->verbose_f) + puts("Packet too large while inserting name"); + + return (-1); + } + + /* The response contains a TTL, and it is set to 0 */ + memset(ptr, 0, 4); + ptr += 4; + + memcpy(ptr, named, namedlen); + ptr += namedlen; + + if (snamedslabel_f) { + if ((ptr + 1) > (v6buffer + idata->max_packet_size)) { + if (idata->verbose_f) + puts("Error while inserting last label"); + + return (-1); + } + else { + *ptr = 0; + ptr++; + } + } + } + else if (fnamed_f && fnamedlen > 0) { + + if ((ptr + (fnamedlen + 4)) > (v6buffer + idata->max_packet_size)) { + if (idata->verbose_f) + puts("Packet too large when inserting forged name"); + + return (-1); + } + + /* The response contains a TTL, and it is set to 0 */ + memset(ptr, 0, 4); + ptr += 4; + + i = fnamedlen - 1; /* There is a zero-length label at the end */ + + if (snamedslabel_f && i > 0) + i = i - 1; + + while (i > 0) { + if (i <= (maxlabel + 1)) { + /* This accounts for the length byte */ + i = i - 1; + *ptr = i; + ptr++; + + for (j = 0; j < i; j++) { + *ptr = 'a'; + ptr++; + } + + i = 0; + } + else { + *ptr = maxlabel; + ptr++; + + for (j = 0; j < maxlabel; j++) { + *ptr = 'a'; + ptr++; + } + + /* This accounts for the 'lenght' byte, too */ + i = i - (maxlabel + 1); + } + } + + *ptr = 0; + ptr++; + + if (snamedslabel_f && fnamedlen > 1) { + if ((ptr + 1) > (v6buffer + idata->max_packet_size)) { + return (-1); + } + else { + *ptr = 0; + ptr++; + } + } + } + else if (exceedpd_f) { + if ((ptr + 5) > (v6buffer + idata->max_packet_size)) { + if (idata->verbose_f) + puts("Packet too large whil inserting 'exceeding' name"); + + return (-1); + } + + /* The response contains a TTL, and it is set to 0 */ + memset(ptr, 0, 4); + ptr += 4; + + *ptr = exceedpd; + ptr++; + } + else if (payloadsize_f) { + if (payloadsize >= 4) + payloadsize -= 4; + + if ((ptr + (payloadsize + 4)) > (v6buffer + idata->max_packet_size)) { + if (idata->verbose_f) + puts("Packet too large while inserting randomized payload"); + + return (-1); + } + + /* The response contains a TTL, and it is set to 0 */ + memset(ptr, 0, 4); + ptr += 4; + + for (i = 0; i < payloadsize; i++) { + *ptr = (unsigned char)random(); + ptr++; + } + } + + break; + + case NI_QTYPE_NODEADDR: + if (ipv6addrd_f) { + if ((ptr + sizeof(struct in6_addr)) > (v6buffer + idata->max_packet_size)) { + if (idata->verbose_f) + puts("Packet too large when inserting IPv6 address"); + + return (-1); + } + + *(struct in6_addr *)ptr = ipv6addrd; + ptr = ptr + sizeof(struct in6_addr); + } + else if (payloadsize_f) { + if ((ptr + payloadsize) > (v6buffer + idata->max_packet_size)) { + if (idata->verbose_f) + puts("Packet too large while inserting randomized payload"); + + return (-1); + } + + for (i = 0; i < payloadsize; i++) { + *ptr = (unsigned char)random(); + ptr++; + } + } + break; + + case NI_QTYPE_IPV4ADDR: + if (ipv4addrd_f) { + if ((ptr + sizeof(struct in_addr)) > (v6buffer + idata->max_packet_size)) { + if (idata->verbose_f) + puts("Packet too large while inserting IPv4 address"); + + return (-1); + } + + *(struct in_addr *)ptr = ipv4addrd; + ptr = ptr + sizeof(struct in_addr); + } + else if (payloadsize_f) { + if ((ptr + payloadsize) > (v6buffer + idata->max_packet_size)) { + if (idata->verbose_f) + puts("Packet too large while inserting randomized payload"); + + return (-1); + } + + for (i = 0; i < payloadsize; i++) { + *ptr = (unsigned char)random(); + ptr++; + } + } + break; + + default: + break; + } + } + else { + /* Packet being sent to a pre-specified destination */ + + ni = (struct icmp6_nodeinfo *)ptr; + ni->ni_type = ICMP6_NI_QUERY; + ni->ni_code = code; + ni->ni_qtype = htons(qtype); + ni->ni_flags = htons(flags); + + for (i = 0; i < 8; i++) + ni->icmp6_ni_nonce[i] = random(); + + ptr = ptr + sizeof(struct icmp6_nodeinfo); + + if (ipv4addr_f) { + if ((ptr + sizeof(struct in_addr)) > (v6buffer + idata->max_packet_size)) { + if (idata->verbose_f) + puts("Packet too large while inserting IPv4 address"); + + return (-1); + } + + *(struct in_addr *)ptr = ipv4addr; + ptr = ptr + sizeof(struct in_addr); + } + else if (ipv6addr_f) { + if ((ptr + sizeof(struct in6_addr)) > (v6buffer + idata->max_packet_size)) { + if (idata->verbose_f) + puts("Packet too large while inserting IPv6 address"); + + return (-1); + } + + *(struct in6_addr *)ptr = ipv6addr; + ptr = ptr + sizeof(struct in6_addr); + } + else if (name_f) { + if ((ptr + namelen) > (v6buffer + idata->max_packet_size)) { + if (idata->verbose_f) + puts("Packet too large while inserting name"); + + return (-1); + } + + memcpy(ptr, name, namelen); + ptr += namelen; + + if (snameslabel_f) { + if ((ptr + 1) > (v6buffer + idata->max_packet_size)) { + if (idata->verbose_f) + puts("Error while inserting last label"); + + return (-1); + } + else { + *ptr = 0; + ptr++; + } + } + } + else if (fname_f && fnamelen > 0) { + + if ((ptr + fnamelen) > (v6buffer + idata->max_packet_size)) { + if (idata->verbose_f) + puts("Packet too large when inserting forged name"); + + return (-1); + } + + i = fnamelen - 1; /* There is a zero-length label at the end */ + + if (snameslabel_f && i > 0) + i = i - 1; + + while (i > 0) { + if (i <= (maxlabel + 1)) { + /* This accounts for the length byte */ + i = i - 1; + *ptr = i; + ptr++; + + for (j = 0; j < i; j++) { + *ptr = 'a'; + ptr++; + } + + i = 0; + } + else { + *ptr = maxlabel; + ptr++; + + for (j = 0; j < maxlabel; j++) { + *ptr = 'a'; + ptr++; + } + + /* This accounts for the 'lenght' byte, too */ + i = i - (maxlabel + 1); + } + } + + *ptr = 0; + ptr++; + + if (snameslabel_f && fnamelen > 1) { + if ((ptr + 1) > (v6buffer + idata->max_packet_size)) { + return (-1); + } + else { + *ptr = 0; + ptr++; + } + } + } + else if (exceedp_f) { + if ((ptr + 1) > (v6buffer + idata->max_packet_size)) { + if (idata->verbose_f) + puts("Packet too large when 'exceeding' name"); + + return (-1); + } + + *ptr = exceedp; + ptr++; + } + else if (payloadsize_f) { + if ((ptr + payloadsize) > (v6buffer + idata->max_packet_size)) { + if (idata->verbose_f) + puts("Packet too large while inserting randomized payload"); + + return (-1); + } + + for (i = 0; i < payloadsize; i++) { + *ptr = (unsigned char)random(); + ptr++; + } + } + else if (sloopattack_f) { + if ((ptr + (slsize + 4)) > (v6buffer + idata->max_packet_size)) { + if (idata->verbose_f) + puts("Packet too large while inserting name payload"); + + return (-1); + } + + memset(ptr, 0, 4); + ptr += 4; + memcpy(ptr, slpointer, slsize); + ptr += slsize; + } + } + + ni->ni_cksum = 0; + ni->ni_cksum = in_chksum(v6buffer, ni, ptr - (unsigned char *)ni, IPPROTO_ICMPV6); + + if (!idata->fragh_f) { + ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); + + if ((nw = pcap_inject(idata->pfd, buffer, ptr - buffer)) == -1) { + if (idata->verbose_f) + printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); + + return (-1); + } + + if (nw != (ptr - buffer)) { + if (idata->verbose_f) + printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, (LUI)(ptr - buffer)); + + return (-1); + } + } + else { + ptrend = ptr; + ptr = fragpart; + fptr = fragbuffer; + fipv6 = (struct ip6_hdr *)(fragbuffer + idata->linkhsize); + fptrend = fptr + idata->linkhsize + MIN_IPV6_HLEN + MAX_IPV6_PAYLOAD; + memcpy(fptr, buffer, fragpart - buffer); + fptr = fptr + (fragpart - buffer); + + if ((fptr + FRAG_HDR_SIZE) > fptrend) { + if (idata->verbose_f) + puts("Unfragmentable Part is Too Large"); + + return (-1); + } + + memcpy(fptr, (char *)&fraghdr, FRAG_HDR_SIZE); + fh = (struct ip6_frag *)fptr; + fh->ip6f_ident = random(); + startoffragment = fptr + FRAG_HDR_SIZE; + + /* + * Check that the selected fragment size is not larger than the largest + * fragment size that can be sent + */ + if (nfrags > (fptrend - fptr)) + nfrags = (fptrend - fptr); + + m = IP6F_MORE_FRAG; + + while ((ptr < ptrend) && m == IP6F_MORE_FRAG) { + fptr = startoffragment; + + if ((ptrend - ptr) <= nfrags) { + fragsize = ptrend - ptr; + m = 0; + } + else { + fragsize = (nfrags + 7) & ntohs(IP6F_OFF_MASK); + } + + memcpy(fptr, ptr, fragsize); + fh->ip6f_offlg = (htons(ptr - fragpart) & IP6F_OFF_MASK) | m; + ptr += fragsize; + fptr += fragsize; + + fipv6->ip6_plen = htons((fptr - fragbuffer) - MIN_IPV6_HLEN - idata->linkhsize); + + if ((nw = pcap_inject(idata->pfd, fragbuffer, fptr - fragbuffer)) == -1) { + if (idata->verbose_f) + printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); + + return (-1); + } + + if (nw != (fptr - fragbuffer)) { + if (idata->verbose_f) + printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, (LUI)(ptr - buffer)); + + return (-1); + } + } /* Sending fragments */ + } /* Sending fragmented datagram */ + + return 0; } - - /* * Function: usage() * * Prints the syntax of the ni6 tool */ -void usage(void){ +void usage(void) { puts("usage:\n" - " ni6 [-i INTERFACE] [-S LINK_SRC_ADDR | -R] [-D LINK-DST-ADDR] \n" - " [-s SRC_ADDR[/LEN] | -r] [-d DST_ADDR] [-c HOP_LIMIT] [-y FRAG_SIZE]\n" - " [-u DST_OPT_HDR_SIZE] [-U DST_OPT_U_HDR_SIZE] [-H HBH_OPT_HDR_SIZE] \n" - " [-P SIZE | -6 IPV6_ADDR | -4 IPV4_ADDR | -n NAME | -N LEN | -x LEN -o TYPE]\n" - " [-Z SIZE] [-e] [-C ICMP6_CODE] [-q NI_QTYPE] [-X NI_FLAGS]\n" - " [-P SIZE | -w IPV6_ADDR | -W IPV4_ADDR | -a NAME | -A LEN | -Q LEN -O TYPE]\n" - " [-E] [-j PREFIX[/LEN]] [-k PREFIX[/LEN]] [-J LINK_ADDR]\n" - " [-K LINK_ADDR] [-b PREFIX[/LEN]] [-g PREFIX[/LEN]] [-B LINK_ADDR]\n" - " [-G LINK_ADDR] [-L | -l] [-z] [-v] [-h]"); + " ni6 [-i INTERFACE] [-S LINK_SRC_ADDR | -R] [-D LINK-DST-ADDR] \n" + " [-s SRC_ADDR[/LEN] | -r] [-d DST_ADDR] [-c HOP_LIMIT] [-y FRAG_SIZE]\n" + " [-u DST_OPT_HDR_SIZE] [-U DST_OPT_U_HDR_SIZE] [-H HBH_OPT_HDR_SIZE] \n" + " [-P SIZE | -6 IPV6_ADDR | -4 IPV4_ADDR | -n NAME | -N LEN | -x LEN -o TYPE]\n" + " [-Z SIZE] [-e] [-C ICMP6_CODE] [-q NI_QTYPE] [-X NI_FLAGS]\n" + " [-P SIZE | -w IPV6_ADDR | -W IPV4_ADDR | -a NAME | -A LEN | -Q LEN -O TYPE]\n" + " [-E] [-j PREFIX[/LEN]] [-k PREFIX[/LEN]] [-J LINK_ADDR]\n" + " [-K LINK_ADDR] [-b PREFIX[/LEN]] [-g PREFIX[/LEN]] [-B LINK_ADDR]\n" + " [-G LINK_ADDR] [-L | -l] [-z] [-v] [-h]"); } - /* * Function: print_help() * * Prints help information for the ni6 tool */ -void print_help(void){ - puts(SI6_TOOLKIT); - puts("ni6: Security assessment tool for attack vectors based on ICMPv6 NI messages\n"); - usage(); - - puts("\nOPTIONS:\n" - " --interface, -i Network interface\n" - " --link-src-addr, -S Link-layer Destination Address\n" - " --link-dst-addr, -D Link-layer Source Address\n" - " --src-addr, -s IPv6 Source Address\n" - " --dst-addr, -d IPv6 Destination Address\n" - " --hop-limit, -c IPv6 Hop Limit\n" - " --frag-hdr. -y Fragment Header\n" - " --dst-opt-hdr, -u Destination Options Header (Fragmentable Part)\n" - " --dst-opt-u-hdr, -U Destination Options Header (Unfragmentable Part)\n" - " --hbh-opt-hdr, -H Hop by Hop Options Header\n" - " --payload-size, -P ICMPv6 NI payload size\n" - " --subject-ipv6. -6 Subject IPv6 Address\n" - " --subject-ipv4, -4 Subject IPv4 address\n" - " --subject-name, -n Subject Name\n" - " --subject-fname, -N Forge Subject Name of specific length\n" - " --subject-ename, -x For (malformed) Subject name of specified length\n" - " --subject-nloop, -o Subject is a Name with a DNS compression loop\n" - " --max-label-size, -Z Maximum DNS label size (defaults to 63)\n" - " --sname-slabel, -e Subject Name is a single-label name\n" - " --code, -C ICMPv6 code\n" - " --qtype, -q ICMPv6 NI Qtype\n" - " --flags, -X ICMPv6 NI flags\n" - " --data-ipv6, -w Data IPv6 Address\n" - " --data-ipv4, W Data IPv4 Address\n" - " --data-name, -a Data Name\n" - " --data-fname, -A Forge Data Name of specific length\n" - " --data-ename, -Q For (malformed) Data Name of specified length\n" - " --data-nloop, -O Data is a Name with a DNS compression loop\n" - " --dname-slabel, -E Subject Name is a single-label name\n" - " --block-src, -j Block IPv6 Source Address prefix\n" - " --block-dst, -k Block IPv6 Destination Address prefix\n" - " --block-link-src, -J Block Ethernet Source Address\n" - " --block-link-dst, -K Block Ethernet Destination Address\n" - " --accept-src, -b Accept IPv6 Source Address prefix\n" - " --accept-dst, -g Accept IPv6 Destination Address prefix\n" - " --accept-link-src, -B Accept Ethernet Source Address\n" - " --accept-link-dst, -G Accept Ethernet Destination Address\n" - " --forge-src-addr, -r Forge IPv6 Source Address\n" - " --forge-link-src-addr, -R Forge link-layer Source Address\n" - " --loop, -l Send periodic ICMPv6 error messages\n" - " --sleep, -z Pause between sending ICMPv6 messages\n" - " --listen, -L Listen to incoming traffic\n" - " --help, -h Print help for the ni6 tool\n" - " --verbose, -v Be verbose\n" - "\n" - " Programmed by Fernando Gont for SI6 Networks \n" - " Please send any bug reports to \n" - ); +void print_help(void) { + puts(SI6_TOOLKIT); + puts("ni6: Security assessment tool for attack vectors based on ICMPv6 NI messages\n"); + usage(); + + puts("\nOPTIONS:\n" + " --interface, -i Network interface\n" + " --link-src-addr, -S Link-layer Destination Address\n" + " --link-dst-addr, -D Link-layer Source Address\n" + " --src-addr, -s IPv6 Source Address\n" + " --dst-addr, -d IPv6 Destination Address\n" + " --hop-limit, -c IPv6 Hop Limit\n" + " --frag-hdr. -y Fragment Header\n" + " --dst-opt-hdr, -u Destination Options Header (Fragmentable Part)\n" + " --dst-opt-u-hdr, -U Destination Options Header (Unfragmentable Part)\n" + " --hbh-opt-hdr, -H Hop by Hop Options Header\n" + " --payload-size, -P ICMPv6 NI payload size\n" + " --subject-ipv6. -6 Subject IPv6 Address\n" + " --subject-ipv4, -4 Subject IPv4 address\n" + " --subject-name, -n Subject Name\n" + " --subject-fname, -N Forge Subject Name of specific length\n" + " --subject-ename, -x For (malformed) Subject name of specified length\n" + " --subject-nloop, -o Subject is a Name with a DNS compression loop\n" + " --max-label-size, -Z Maximum DNS label size (defaults to 63)\n" + " --sname-slabel, -e Subject Name is a single-label name\n" + " --code, -C ICMPv6 code\n" + " --qtype, -q ICMPv6 NI Qtype\n" + " --flags, -X ICMPv6 NI flags\n" + " --data-ipv6, -w Data IPv6 Address\n" + " --data-ipv4, W Data IPv4 Address\n" + " --data-name, -a Data Name\n" + " --data-fname, -A Forge Data Name of specific length\n" + " --data-ename, -Q For (malformed) Data Name of specified length\n" + " --data-nloop, -O Data is a Name with a DNS compression loop\n" + " --dname-slabel, -E Subject Name is a single-label name\n" + " --block-src, -j Block IPv6 Source Address prefix\n" + " --block-dst, -k Block IPv6 Destination Address prefix\n" + " --block-link-src, -J Block Ethernet Source Address\n" + " --block-link-dst, -K Block Ethernet Destination Address\n" + " --accept-src, -b Accept IPv6 Source Address prefix\n" + " --accept-dst, -g Accept IPv6 Destination Address prefix\n" + " --accept-link-src, -B Accept Ethernet Source Address\n" + " --accept-link-dst, -G Accept Ethernet Destination Address\n" + " --forge-src-addr, -r Forge IPv6 Source Address\n" + " --forge-link-src-addr, -R Forge link-layer Source Address\n" + " --loop, -l Send periodic ICMPv6 error messages\n" + " --sleep, -z Pause between sending ICMPv6 messages\n" + " --listen, -L Listen to incoming traffic\n" + " --help, -h Print help for the ni6 tool\n" + " --verbose, -v Be verbose\n" + "\n" + " Programmed by Fernando Gont for SI6 Networks \n" + " Please send any bug reports to \n"); } - - /* * Function: print_attack_info() * * Prints attack details (when the verbose ("-v") option is specified). */ - -void print_attack_info(struct iface_data *idata){ - - puts( "ni6: Assessment tool for attack vectors based on ICMPv6 NI messages\n"); - - if(ether_ntop(&(idata->hsrcaddr), plinkaddr, sizeof(plinkaddr)) == 0){ - puts("ether_ntop(): Error converting address"); - exit(EXIT_FAILURE); - } - - printf("Ethernet Source Address: %s%s\n", plinkaddr, ((!(idata->hsrcaddr_f))?" (randomized)":"")); - - /* - Ethernet Destination Address only used if a IPv6 Destination Address or an - Ethernet Destination Address were specified. - */ - if(idata->dstaddr_f){ - if(ether_ntop(&(idata->hdstaddr), plinkaddr, sizeof(plinkaddr)) == 0){ - puts("ether_ntop(): Error converting address"); - exit(EXIT_FAILURE); - } - - printf("Ethernet Destination Address: %s%s\n", plinkaddr, \ - ((!idata->hdstaddr_f)?" (automatically selected)":"")); - } - - if(idata->srcaddr_f){ - if(inet_ntop(AF_INET6, &(idata->srcaddr), psrcaddr, sizeof(psrcaddr)) == NULL){ - puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); - exit(EXIT_FAILURE); - } - - printf("IPv6 Source Address: %s%s\n", psrcaddr, ((srcprefix_f)?" (randomized)":"")); - } - else{ - if(idata->dstaddr_f){ - if(inet_ntop(AF_INET6, &(idata->srcaddr), psrcaddr, sizeof(psrcaddr)) == NULL){ - puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); - exit(EXIT_FAILURE); - } - - printf("IPv6 Source Address: %s (automatically selected)\n", psrcaddr); - } - else - puts("IPv6 Source Address: Automatically selected"); - } - - if(idata->dstaddr_f){ - if(inet_ntop(AF_INET6, &(idata->dstaddr), pdstaddr, sizeof(pdstaddr)) == NULL){ - puts("inet_ntop(): Error converting IPv6 Destination Address to presentation format"); - exit(EXIT_FAILURE); - } - - printf("IPv6 Destination Address: %s\n", pdstaddr); - } - - printf("IPv6 Hop Limit: %u%s\n", hoplimit, (hoplimit_f)?"":" (randomized)"); - - for(i=0; ifragh_f) - printf("Sending each packet in fragments of %u bytes (plus the Unfragmentable part)\n", nfrags); - - if(type==ICMP6_NI_QUERY){ - printf("ICMPv6 NI Query (Type 139)"); - - switch(code){ - case 0: - printf(", Subject is an IPv6 address (Code %u)\n", code); - - if(ipv6addr_f){ - if(inet_ntop(AF_INET6, &ipv6addr, pv6addr, sizeof(pv6addr)) == NULL){ - puts("inet_ntop(): Error converting Subject IPv6 Address to presentation format"); - exit(EXIT_FAILURE); - } - - printf("Subject IPv6 Address: %s\n", pv6addr); - } - break; - - case 1: - printf(", Subject is a Name (Code %u)\n", code); - - if(name_f){ - printf("Subject Name: %s%s\n", printname, (snameslabel_f)?" (single label name)":""); - } - else if(fname_f){ - printf("Subject Name: Forged Name of %u byte%s\n", fnamelen, (fnamelen>1)?"s":""); - } - else if(exceedp_f){ - printf("Subject Name: Malformed label of %u byte%s\n", exceedp, (exceedp>1)?"s":""); - } - - break; - - case 2: - printf(", Subject is an IPv4 Address (Code %u)\n", code); - - if(ipv4addr_f){ - if(inet_ntop(AF_INET, &ipv4addr, pv6addr, sizeof(pv6addr)) == NULL){ - puts("inet_ntop(): Error converting Subject IPv4 Address to presentation format"); - exit(EXIT_FAILURE); - } - - printf("Subject IPv4 Address: %s\n", pv6addr); - } - break; - - default: - printf(", Unknown ICMPv6 code (Code %u)\n", code); - break; - } - - switch(qtype){ - case NI_QTYPE_NOOP: - printf("Qtype: NOOP (Qtype %u)\n", qtype); - break; - case NI_QTYPE_SUPTYPES: - printf("Qtype: Subtypes (?) (Qtype %u)\n", qtype); - break; - - case NI_QTYPE_DNSNAME: - printf("Qtype: Node Name (Qtype %u)\n", qtype); - break; - - case NI_QTYPE_NODEADDR: - printf("Qtype: Node Addresses (Qtype %u)\n", qtype); - break; - - case NI_QTYPE_IPV4ADDR: - printf("Qtype: IPv4 Addresses (Qtype %u)\n", qtype); - break; - - default: - printf("Qtype: (Qtype %u)\n", qtype); - break; - } - } - else if(type == ICMP6_NI_REPLY){ - printf("ICMPv6 NI Reply (Type 140)"); - - switch(qtype){ - case 0: - puts(", NOOP (Qtype 0)"); - break; - - case 1: - puts(", Supported Qtypes (Qtype 1)"); - break; - - case 2: - printf(", Data is a Name (Qtype %u)\n", qtype); - - if(named_f){ - printf("Data Name: %s%s\n", printnamed, (snamedslabel_f)?" (single label name)":""); - } - else if(fnamed_f){ - printf("Data Name: Forged Name of %u byte%s\n", fnamedlen, (fnamedlen>1)?"s":""); - } - else if(exceedpd_f){ - printf("Data Name: Malformed label of %u byte%s\n", exceedp, (exceedp>1)?"s":""); - } - - break; - - case 3: - printf(", Data contains IPv6 address(es) (Qtype %u)\n", qtype); - - if(ipv6addrd_f){ - if(inet_ntop(AF_INET6, &ipv6addrd, pv6addr, sizeof(pv6addr)) == NULL){ - puts("inet_ntop(): Error converting Subject IPv6 Address to presentation format"); - exit(EXIT_FAILURE); - } - - printf("Data IPv6 Address: %s\n", pv6addr); - } - break; - - case 4: - printf(", Data contains IPv4 Address(es) (Qtype %u)\n", qtype); - - if(ipv4addrd_f){ - if(inet_ntop(AF_INET, &ipv4addrd, pv6addr, sizeof(pv6addr)) == NULL){ - puts("inet_ntop(): Error converting Data IPv4 Address to presentation format"); - exit(EXIT_FAILURE); - } - - printf("Data IPv4 Address: %s\n", pv6addr); - } - break; - - default: - printf(", Unknown ICMPv6 NI Query type (Qtype %u)\n", qtype); - break; - } - } - - if(flags_f || type== ICMP6_NI_QUERY){ - printf("Flags: %s%s%s%s%s%s%s%s\n\n", ((flags & NI_NODEADDR_FLAG_GLOBAL)?"G":""), \ - ((flags & NI_NODEADDR_FLAG_SITELOCAL)?"S":""), \ - ((flags & NI_NODEADDR_FLAG_LINKLOCAL)?"L":""), \ - ((flags & NI_NODEADDR_FLAG_COMPAT)?"C":""),\ - ((flags & NI_NODEADDR_FLAG_ALL)?"A":""), \ - ((flags & NI_NODEADDR_FLAG_TRUNCATE)?"T":""),\ - ((!flags)?"none":""), ((!flags_f)?" (default)":"")); - } -} - - +void print_attack_info(struct iface_data *idata) { + + puts("ni6: Assessment tool for attack vectors based on ICMPv6 NI messages\n"); + + if (ether_ntop(&(idata->hsrcaddr), plinkaddr, sizeof(plinkaddr)) == 0) { + puts("ether_ntop(): Error converting address"); + exit(EXIT_FAILURE); + } + + printf("Ethernet Source Address: %s%s\n", plinkaddr, ((!(idata->hsrcaddr_f)) ? " (randomized)" : "")); + + /* + Ethernet Destination Address only used if a IPv6 Destination Address or an + Ethernet Destination Address were specified. + */ + if (idata->dstaddr_f) { + if (ether_ntop(&(idata->hdstaddr), plinkaddr, sizeof(plinkaddr)) == 0) { + puts("ether_ntop(): Error converting address"); + exit(EXIT_FAILURE); + } + + printf("Ethernet Destination Address: %s%s\n", plinkaddr, + ((!idata->hdstaddr_f) ? " (automatically selected)" : "")); + } + + if (idata->srcaddr_f) { + if (inet_ntop(AF_INET6, &(idata->srcaddr), psrcaddr, sizeof(psrcaddr)) == NULL) { + puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); + exit(EXIT_FAILURE); + } + + printf("IPv6 Source Address: %s%s\n", psrcaddr, ((srcprefix_f) ? " (randomized)" : "")); + } + else { + if (idata->dstaddr_f) { + if (inet_ntop(AF_INET6, &(idata->srcaddr), psrcaddr, sizeof(psrcaddr)) == NULL) { + puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); + exit(EXIT_FAILURE); + } + + printf("IPv6 Source Address: %s (automatically selected)\n", psrcaddr); + } + else + puts("IPv6 Source Address: Automatically selected"); + } + + if (idata->dstaddr_f) { + if (inet_ntop(AF_INET6, &(idata->dstaddr), pdstaddr, sizeof(pdstaddr)) == NULL) { + puts("inet_ntop(): Error converting IPv6 Destination Address to presentation format"); + exit(EXIT_FAILURE); + } + + printf("IPv6 Destination Address: %s\n", pdstaddr); + } + + printf("IPv6 Hop Limit: %u%s\n", hoplimit, (hoplimit_f) ? "" : " (randomized)"); + + for (i = 0; i < ndstoptuhdr; i++) + printf("Destination Options Header (Unfragmentable part): %u bytes\n", dstoptuhdrlen[i]); + + for (i = 0; i < nhbhopthdr; i++) + printf("Hop by Hop Options Header: %u bytes\n", hbhopthdrlen[i]); + + for (i = 0; i < ndstopthdr; i++) + printf("Destination Options Header: %u bytes\n", dstopthdrlen[i]); + + if (idata->fragh_f) + printf("Sending each packet in fragments of %u bytes (plus the Unfragmentable part)\n", nfrags); + + if (type == ICMP6_NI_QUERY) { + printf("ICMPv6 NI Query (Type 139)"); + + switch (code) { + case 0: + printf(", Subject is an IPv6 address (Code %u)\n", code); + + if (ipv6addr_f) { + if (inet_ntop(AF_INET6, &ipv6addr, pv6addr, sizeof(pv6addr)) == NULL) { + puts("inet_ntop(): Error converting Subject IPv6 Address to presentation format"); + exit(EXIT_FAILURE); + } + + printf("Subject IPv6 Address: %s\n", pv6addr); + } + break; + + case 1: + printf(", Subject is a Name (Code %u)\n", code); + + if (name_f) { + printf("Subject Name: %s%s\n", printname, (snameslabel_f) ? " (single label name)" : ""); + } + else if (fname_f) { + printf("Subject Name: Forged Name of %u byte%s\n", fnamelen, (fnamelen > 1) ? "s" : ""); + } + else if (exceedp_f) { + printf("Subject Name: Malformed label of %u byte%s\n", exceedp, (exceedp > 1) ? "s" : ""); + } + + break; + + case 2: + printf(", Subject is an IPv4 Address (Code %u)\n", code); + + if (ipv4addr_f) { + if (inet_ntop(AF_INET, &ipv4addr, pv6addr, sizeof(pv6addr)) == NULL) { + puts("inet_ntop(): Error converting Subject IPv4 Address to presentation format"); + exit(EXIT_FAILURE); + } + + printf("Subject IPv4 Address: %s\n", pv6addr); + } + break; + + default: + printf(", Unknown ICMPv6 code (Code %u)\n", code); + break; + } + + switch (qtype) { + case NI_QTYPE_NOOP: + printf("Qtype: NOOP (Qtype %u)\n", qtype); + break; + case NI_QTYPE_SUPTYPES: + printf("Qtype: Subtypes (?) (Qtype %u)\n", qtype); + break; + + case NI_QTYPE_DNSNAME: + printf("Qtype: Node Name (Qtype %u)\n", qtype); + break; + + case NI_QTYPE_NODEADDR: + printf("Qtype: Node Addresses (Qtype %u)\n", qtype); + break; + + case NI_QTYPE_IPV4ADDR: + printf("Qtype: IPv4 Addresses (Qtype %u)\n", qtype); + break; + + default: + printf("Qtype: (Qtype %u)\n", qtype); + break; + } + } + else if (type == ICMP6_NI_REPLY) { + printf("ICMPv6 NI Reply (Type 140)"); + + switch (qtype) { + case 0: + puts(", NOOP (Qtype 0)"); + break; + + case 1: + puts(", Supported Qtypes (Qtype 1)"); + break; + + case 2: + printf(", Data is a Name (Qtype %u)\n", qtype); + + if (named_f) { + printf("Data Name: %s%s\n", printnamed, (snamedslabel_f) ? " (single label name)" : ""); + } + else if (fnamed_f) { + printf("Data Name: Forged Name of %u byte%s\n", fnamedlen, (fnamedlen > 1) ? "s" : ""); + } + else if (exceedpd_f) { + printf("Data Name: Malformed label of %u byte%s\n", exceedp, (exceedp > 1) ? "s" : ""); + } + + break; + + case 3: + printf(", Data contains IPv6 address(es) (Qtype %u)\n", qtype); + + if (ipv6addrd_f) { + if (inet_ntop(AF_INET6, &ipv6addrd, pv6addr, sizeof(pv6addr)) == NULL) { + puts("inet_ntop(): Error converting Subject IPv6 Address to presentation format"); + exit(EXIT_FAILURE); + } + + printf("Data IPv6 Address: %s\n", pv6addr); + } + break; + + case 4: + printf(", Data contains IPv4 Address(es) (Qtype %u)\n", qtype); + + if (ipv4addrd_f) { + if (inet_ntop(AF_INET, &ipv4addrd, pv6addr, sizeof(pv6addr)) == NULL) { + puts("inet_ntop(): Error converting Data IPv4 Address to presentation format"); + exit(EXIT_FAILURE); + } + + printf("Data IPv4 Address: %s\n", pv6addr); + } + break; + + default: + printf(", Unknown ICMPv6 NI Query type (Qtype %u)\n", qtype); + break; + } + } + + if (flags_f || type == ICMP6_NI_QUERY) { + printf("Flags: %s%s%s%s%s%s%s%s\n\n", ((flags & NI_NODEADDR_FLAG_GLOBAL) ? "G" : ""), + ((flags & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : ""), ((flags & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : ""), + ((flags & NI_NODEADDR_FLAG_COMPAT) ? "C" : ""), ((flags & NI_NODEADDR_FLAG_ALL) ? "A" : ""), + ((flags & NI_NODEADDR_FLAG_TRUNCATE) ? "T" : ""), ((!flags) ? "none" : ""), + ((!flags_f) ? " (default)" : "")); + } +} diff --git a/tools/ni6.h b/tools/ni6.h index 78d1c48..f538a95 100644 --- a/tools/ni6.h +++ b/tools/ni6.h @@ -3,9 +3,4 @@ * */ - -#define QUERY_TIMEOUT 2 - - - - +#define QUERY_TIMEOUT 2 diff --git a/tools/ns6.c b/tools/ns6.c index e623bb8..50730d7 100644 --- a/tools/ns6.c +++ b/tools/ns6.c @@ -18,1072 +18,1051 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . - * + * * Build with: make ns6 - * + * * The libpcap library must be previously installed on your system. * * Please send any bug reports to Fernando Gont */ -#include #include #include +#include -#include #include -#include #include +#include +#include +#include +#include #include #include -#include -#include -#include #include -#include #include +#include +#include -#include "ns6.h" -#include "libipv6.h" #include "ipv6toolkit.h" +#include "libipv6.h" +#include "ns6.h" + +void init_packet_data(struct iface_data *); +void send_packet(struct iface_data *); +int send_packet_to_ns(struct iface_data *, struct pcap_pkthdr *, const u_char *); +void print_attack_info(struct iface_data *); +void usage(void); +void print_help(void); + +struct pcap_pkthdr *pkthdr; +const u_char *pktdata; +bpf_u_int32 my_netmask; +bpf_u_int32 my_ip; +struct bpf_program pcap_filter; +char dev[64], errbuf[PCAP_ERRBUF_SIZE]; + +unsigned char buffer[65556]; +unsigned char *v6buffer, *ptr, *startofprefixes; + +struct nd_neighbor_solicit *pkt_ns; +struct ether_header *ethernet, *pkt_ether; +struct icmp6_hdr *pkt_icmp6; + +struct ip6_hdr *ipv6, *pkt_ipv6; +struct nd_neighbor_solicit *ns; +struct ether_header *ethernet, *pkt_ether; +struct nd_opt_slla *sllaopt; + +struct in6_addr targetaddr, *pkt_ipv6addr; +; +char *lasts, *endptr; + +int nw; +unsigned long ul_res, ul_val; + +unsigned int i, j, startrand, sources, nsources, targets, ntargets; -void init_packet_data(struct iface_data *); -void send_packet(struct iface_data *); -int send_packet_to_ns(struct iface_data *, struct pcap_pkthdr *, const u_char *); -void print_attack_info(struct iface_data *); -void usage(void); -void print_help(void); - -struct pcap_pkthdr *pkthdr; -const u_char *pktdata; -bpf_u_int32 my_netmask; -bpf_u_int32 my_ip; -struct bpf_program pcap_filter; -char dev[64], errbuf[PCAP_ERRBUF_SIZE]; - -unsigned char buffer[65556]; -unsigned char *v6buffer, *ptr, *startofprefixes; - - -struct nd_neighbor_solicit *pkt_ns; -struct ether_header *ethernet, *pkt_ether; -struct icmp6_hdr *pkt_icmp6; - - -struct ip6_hdr *ipv6, *pkt_ipv6; -struct nd_neighbor_solicit *ns; -struct ether_header *ethernet, *pkt_ether; -struct nd_opt_slla *sllaopt; - -struct in6_addr targetaddr, *pkt_ipv6addr; ; -char *lasts, *endptr; - -int nw; -unsigned long ul_res, ul_val; - -unsigned int i, j, startrand, sources, nsources, targets, ntargets; - -uint16_t mask; -uint8_t hoplimit; - -struct ether_addr linkaddr[MAX_SLLA_OPTION]; -unsigned int nlinkaddr=0, linkaddrs; -unsigned int nsleep; - -char *charptr, *pref; - -char plinkaddr[ETHER_ADDR_PLEN], phsrcaddr[ETHER_ADDR_PLEN], phdstaddr[ETHER_ADDR_PLEN]; -char psrcaddr[INET6_ADDRSTRLEN], pdstaddr[INET6_ADDRSTRLEN], pv6addr[INET6_ADDRSTRLEN]; -unsigned char sllopt_f=0, sllopta_f=0, targetprefix_f=0, targetaddr_f=0, listen_f=0, accepted_f=0; -unsigned char loop_f = 0, sleep_f=0, floods_f=0, floodt_f=0, newdata_f=0, hoplimit_f=0, multicastdst_f=0; -unsigned char targetpreflen; +uint16_t mask; +uint8_t hoplimit; + +struct ether_addr linkaddr[MAX_SLLA_OPTION]; +unsigned int nlinkaddr = 0, linkaddrs; +unsigned int nsleep; + +char *charptr, *pref; + +char plinkaddr[ETHER_ADDR_PLEN], phsrcaddr[ETHER_ADDR_PLEN], phdstaddr[ETHER_ADDR_PLEN]; +char psrcaddr[INET6_ADDRSTRLEN], pdstaddr[INET6_ADDRSTRLEN], pv6addr[INET6_ADDRSTRLEN]; +unsigned char sllopt_f = 0, sllopta_f = 0, targetprefix_f = 0, targetaddr_f = 0, listen_f = 0, accepted_f = 0; +unsigned char loop_f = 0, sleep_f = 0, floods_f = 0, floodt_f = 0, newdata_f = 0, hoplimit_f = 0, multicastdst_f = 0; +unsigned char targetpreflen; /* Support for Extension Headers */ -unsigned int dstopthdrs, dstoptuhdrs, hbhopthdrs; -unsigned char hbhopthdr_f=0, dstoptuhdr_f=0, dstopthdr_f=0; -unsigned char *dstopthdr[MAX_DST_OPT_HDR], *dstoptuhdr[MAX_DST_OPT_U_HDR]; -unsigned char *hbhopthdr[MAX_HBH_OPT_HDR]; -unsigned int dstopthdrlen[MAX_DST_OPT_HDR], dstoptuhdrlen[MAX_DST_OPT_U_HDR]; -unsigned int hbhopthdrlen[MAX_HBH_OPT_HDR], m, pad; - -struct ip6_frag fraghdr, *fh; -struct ip6_hdr *fipv6; -unsigned char fragbuffer[ETHER_HDR_LEN+MIN_IPV6_HLEN+MAX_IPV6_PAYLOAD]; -unsigned char *fragpart, *fptr, *fptrend, *ptrend, *ptrhdr, *ptrhdrend; -unsigned int hdrlen, ndstopthdr=0, nhbhopthdr=0, ndstoptuhdr=0; -unsigned int nfrags, fragsize; -unsigned char *prev_nh, *startoffragment; - -struct filters filters; - -struct iface_data idata; - -int main(int argc, char **argv){ - extern char *optarg; - int r, sel; - fd_set sset, rset; - -#if defined(sun) || defined(__sun) || defined (__linux__) - struct timeval timeout; +unsigned int dstopthdrs, dstoptuhdrs, hbhopthdrs; +unsigned char hbhopthdr_f = 0, dstoptuhdr_f = 0, dstopthdr_f = 0; +unsigned char *dstopthdr[MAX_DST_OPT_HDR], *dstoptuhdr[MAX_DST_OPT_U_HDR]; +unsigned char *hbhopthdr[MAX_HBH_OPT_HDR]; +unsigned int dstopthdrlen[MAX_DST_OPT_HDR], dstoptuhdrlen[MAX_DST_OPT_U_HDR]; +unsigned int hbhopthdrlen[MAX_HBH_OPT_HDR], m, pad; + +struct ip6_frag fraghdr, *fh; +struct ip6_hdr *fipv6; +unsigned char fragbuffer[ETHER_HDR_LEN + MIN_IPV6_HLEN + MAX_IPV6_PAYLOAD]; +unsigned char *fragpart, *fptr, *fptrend, *ptrend, *ptrhdr, *ptrhdrend; +unsigned int hdrlen, ndstopthdr = 0, nhbhopthdr = 0, ndstoptuhdr = 0; +unsigned int nfrags, fragsize; +unsigned char *prev_nh, *startoffragment; + +struct filters filters; + +struct iface_data idata; + +int main(int argc, char **argv) { + extern char *optarg; + int r, sel; + fd_set sset, rset; + +#if defined(sun) || defined(__sun) || defined(__linux__) + struct timeval timeout; #endif - struct target_ipv6 targetipv6; - - static struct option longopts[] = { - {"interface", required_argument, 0, 'i'}, - {"src-addr", required_argument, 0, 's'}, - {"dst-addr", required_argument, 0, 'd'}, - {"hop-limit", required_argument, 0, 'A'}, - {"dst-opt-hdr", required_argument, 0, 'u'}, - {"dst-opt-u-hdr", required_argument, 0, 'U'}, - {"hbh-opt-hdr", required_argument, 0, 'H'}, - {"frag-hdr", required_argument, 0, 'y'}, - {"link-src-addr", required_argument, 0, 'S'}, - {"link-dst-addr", required_argument, 0, 'D'}, - {"target-address", required_argument, 0, 't'}, - {"source-lla-opt", required_argument, 0, 'E'}, - {"add-slla-opt", no_argument, 0, 'e'}, - {"block-src-addr", required_argument, 0, 'j'}, - {"block-dst-addr", required_argument, 0, 'k'}, - {"block-link-src-addr", required_argument, 0, 'J'}, - {"block-link-dst-addr", required_argument, 0, 'K'}, - {"block-target-addr", required_argument, 0, 'w'}, - {"accept-src-addr", required_argument, 0, 'b'}, - {"accept-dst-addr", required_argument, 0, 'g'}, - {"accept-link-src-addr", required_argument, 0, 'B'}, - {"accept-link-dst-addr", required_argument, 0, 'G'}, - {"accept-target-addr", required_argument, 0, 'W'}, - {"flood-sources", required_argument, 0, 'F'}, - {"flood-targets", required_argument, 0, 'T'}, - {"loop", no_argument, 0, 'l'}, - {"sleep", no_argument, 0, 'z'}, - {"listen", no_argument, 0, 'L'}, - {"verbose", no_argument, 0, 'v'}, - {"help", no_argument, 0, 'h'}, - {0, 0, 0, 0 } - }; - - const char shortopts[]= "i:s:d:A:u:U:H:y:S:D:t:eE:j:k:J:K:w:b:g:B:G:W:F:T:lz:Lvh"; - char option; - - if(argc<=1){ - usage(); - exit(EXIT_FAILURE); - } - - hoplimit=255; - - if(init_iface_data(&idata) == FAILURE){ - puts("Error initializing internal data structure"); - exit(EXIT_FAILURE); - } - - while((r=getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { - option =r; - - switch(option) { - case 'i': /* Interface */ - strncpy(idata.iface, optarg, IFACE_LENGTH); - idata.iface[IFACE_LENGTH-1]=0; - idata.iface_f=1; - break; - - case 's': /* IPv6 Source Address */ - if((charptr = strtok_r(optarg, "/", &lasts)) == NULL){ - puts("inet_pton(): address not valid"); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, charptr, &(idata.srcaddr)) <= 0){ - puts("inet_pton(): address not valid"); - exit(EXIT_FAILURE); - } - - idata.srcaddr_f = 1; - - if((charptr = strtok_r(NULL, " ", &lasts)) != NULL){ - idata.srcpreflen = atoi(charptr); - - if(idata.srcpreflen>128){ - puts("Prefix length error in IPv6 Source Address"); - exit(EXIT_FAILURE); - } - - sanitize_ipv6_prefix(&(idata.srcaddr), idata.srcpreflen); - idata.srcprefix_f=1; - } - - break; - - case 'd': /* IPv6 Destination Address */ - strncpy( targetipv6.name, optarg, NI_MAXHOST); - targetipv6.name[NI_MAXHOST-1]= 0; - targetipv6.flags= AI_CANONNAME; - - if( (r=get_ipv6_target(&targetipv6)) != 0){ - - if(r < 0){ - printf("Unknown Destination: %s\n", gai_strerror(targetipv6.res)); - } - else{ - puts("Unknown Destination: No IPv6 address found for specified destination"); - } - - exit(EXIT_FAILURE); - } - - idata.dstaddr= targetipv6.ip6; - idata.dstaddr_f = 1; - break; - - case 'A': /* Hop Limit */ - hoplimit= atoi(optarg); - hoplimit_f=1; - break; - - case 'y': /* Fragment header */ - nfrags= atoi(optarg); - - if(nfrags < 8){ - puts("Error in Fragmentation option: Fragment Size must be at least 8 bytes"); - exit(EXIT_FAILURE); - } - - idata.fragh_f= 1; - break; - - case 'u': /* Destinations Options Header */ - if(ndstopthdr >= MAX_DST_OPT_HDR){ - puts("Too many Destination Options Headers"); - exit(EXIT_FAILURE); - } - - hdrlen= atoi(optarg); - - if(hdrlen < 8){ - puts("Bad length in Destination Options Header"); - exit(EXIT_FAILURE); - } - - hdrlen = ((hdrlen+7)/8) * 8; - dstopthdrlen[ndstopthdr]= hdrlen; - - if( (dstopthdr[ndstopthdr]= malloc(hdrlen)) == NULL){ - puts("Not enough memory for Destination Options Header"); - exit(EXIT_FAILURE); - } - - ptrhdr= dstopthdr[ndstopthdr] + 2; - ptrhdrend= dstopthdr[ndstopthdr] + hdrlen; - - while( ptrhdr < ptrhdrend){ - - if( (ptrhdrend-ptrhdr)>257) - pad= 257; - else - pad= ptrhdrend-ptrhdr; - - if(!insert_pad_opt(ptrhdr, ptrhdrend, pad)){ - puts("Destination Options Header Too Big"); - exit(EXIT_FAILURE); - } - - ptrhdr= ptrhdr + pad; - } - - *(dstopthdr[ndstopthdr]+1)= (hdrlen/8)-1; - ndstopthdr++; - dstopthdr_f=1; - break; - - - case 'U': /* Destination Options Header (Unfragmentable Part) */ - if(ndstoptuhdr >= MAX_DST_OPT_U_HDR){ - puts("Too many Destination Options Headers (Unfragmentable Part)"); - exit(EXIT_FAILURE); - } - - hdrlen= atoi(optarg); - - if(hdrlen < 8){ - puts("Bad length in Destination Options Header (Unfragmentable Part)"); - exit(EXIT_FAILURE); - } - - hdrlen = ((hdrlen+7)/8) * 8; - dstoptuhdrlen[ndstoptuhdr]= hdrlen; - - if( (dstoptuhdr[ndstoptuhdr]= malloc(hdrlen)) == NULL){ - puts("Not enough memory for Destination Options Header (Unfragmentable Part)"); - exit(EXIT_FAILURE); - } - - ptrhdr= dstoptuhdr[ndstoptuhdr]+2; - ptrhdrend= dstoptuhdr[ndstoptuhdr] + hdrlen; - - while( ptrhdr < ptrhdrend){ - - if( (ptrhdrend-ptrhdr)>257) - pad= 257; - else - pad= ptrhdrend-ptrhdr; - - if(!insert_pad_opt(ptrhdr, ptrhdrend, pad)){ - puts("Destination Options Header (Unfragmentable Part) Too Big"); - exit(EXIT_FAILURE); - } - - ptrhdr = ptrhdr + pad; - } - - *(dstoptuhdr[ndstoptuhdr]+1)= (hdrlen/8) - 1; - ndstoptuhdr++; - dstoptuhdr_f=1; - break; - - case 'H': /* Hop-by-Hop Options Header */ - if(nhbhopthdr >= MAX_HBH_OPT_HDR){ - puts("Too many Hop-by-Hop Options Headers"); - exit(EXIT_FAILURE); - } - - hdrlen= atoi(optarg); - - if(hdrlen < 8){ - puts("Bad length in Hop-by-Hop Options Header"); - exit(EXIT_FAILURE); - } - - hdrlen = ((hdrlen+7)/8) * 8; - hbhopthdrlen[nhbhopthdr]= hdrlen; - - if( (hbhopthdr[nhbhopthdr]= malloc(hdrlen)) == NULL){ - puts("Not enough memory for Hop-by-Hop Options Header"); - exit(EXIT_FAILURE); - } - - ptrhdr= hbhopthdr[nhbhopthdr] + 2; - ptrhdrend= hbhopthdr[nhbhopthdr] + hdrlen; - - - while( ptrhdr < ptrhdrend){ - - if( (ptrhdrend-ptrhdr)>257) - pad= 257; - else - pad= ptrhdrend-ptrhdr; - - if(!insert_pad_opt(ptrhdr, ptrhdrend, pad)){ - puts("Hop-by-Hop Options Header Too Big"); - exit(EXIT_FAILURE); - } - - ptrhdr = ptrhdr + pad; - } - - *(hbhopthdr[nhbhopthdr]+1)= (hdrlen/8) - 1; - nhbhopthdr++; - hbhopthdr_f=1; - break; - - case 'S': /* Source Ethernet address */ - if(ether_pton(optarg, &(idata.hsrcaddr), sizeof(idata.hsrcaddr)) == 0){ - puts("Error in Source link-layer address."); - exit(EXIT_FAILURE); - } - - idata.hsrcaddr_f = 1; - break; - - case 'D': /* Destination Ethernet Address */ - if(ether_pton(optarg, &(idata.hdstaddr), sizeof(idata.hdstaddr)) == 0){ - puts("Error in Source link-layer address."); - exit(EXIT_FAILURE); - } - - idata.hdstaddr_f = 1; - break; - - case 't': /* NA Target address */ - if((charptr = strtok_r(optarg, "/", &lasts)) == NULL){ - puts("Target Address not valid"); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, charptr, &targetaddr) <= 0){ - puts("inet_pton(): Target Address not valid"); - exit(EXIT_FAILURE); - } - - targetaddr_f = 1; - - if((charptr = strtok_r(NULL, " ", &lasts)) != NULL){ - targetpreflen = atoi(charptr); - - if(targetpreflen>128){ - puts("Prefix length error in Target Address"); - exit(EXIT_FAILURE); - } - - sanitize_ipv6_prefix(&targetaddr, targetpreflen); - targetprefix_f=1; - } - - break; - - - case 'E': /* Source link-layer option */ - sllopt_f = 1; - - if(ether_pton(optarg, &linkaddr[nlinkaddr], sizeof(struct ether_addr)) == 0){ - puts("Error in Source link-layer address option."); - exit(EXIT_FAILURE); - } - - sllopta_f=1; - nlinkaddr++; - break; - - case 'e': /* Add Source link-layer option */ - sllopt_f = 1; - break; - - case 'F': /* Flood sources */ - nsources= atoi(optarg); - if(nsources == 0){ - puts("Invalid number of sources in option -F"); - exit(EXIT_FAILURE); - } - - floods_f= 1; - break; - - case 'j': /* IPv6 Source Address (block) filter */ - if(filters.nblocksrc >= MAX_BLOCK_SRC){ - puts("Too many IPv6 Source Address (block) filters."); - exit(EXIT_FAILURE); - } - - if((pref = strtok_r(optarg, "/", &lasts)) == NULL){ - printf("Error in IPv6 Source Address (block) filter number %u.\n", \ - filters.nblocksrc+1); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, pref, &(filters.blocksrc[filters.nblocksrc])) <= 0){ - printf("Error in IPv6 Source Address (block) filter number %u.", \ - filters.nblocksrc+1); - exit(EXIT_FAILURE); - } - - if((charptr = strtok_r(NULL, " ", &lasts)) == NULL){ - filters.blocksrclen[filters.nblocksrc] = 128; - } - else{ - filters.blocksrclen[filters.nblocksrc] = atoi(charptr); - - if(filters.blocksrclen[filters.nblocksrc]>128){ - printf("Length error in IPv6 Source Address (block) filter number %u.\n", \ - filters.nblocksrc+1); - exit(EXIT_FAILURE); - } - } - - sanitize_ipv6_prefix(&(filters.blocksrc[filters.nblocksrc]), filters.blocksrclen[filters.nblocksrc]); - (filters.nblocksrc)++; - break; - - case 'k': /* IPv6 Destination Address (block) filter */ - if(filters.nblockdst >= MAX_BLOCK_DST){ - puts("Too many IPv6 Destination Address (block) filters."); - exit(EXIT_FAILURE); - } - - if((pref = strtok_r(optarg, "/", &lasts)) == NULL){ - printf("Error in IPv6 Destination Address (block) filter number %u.\n", \ - filters.nblockdst+1); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, pref, &(filters.blockdst[filters.nblockdst])) <= 0){ - printf("Error in IPv6 Source Address (block) filter number %u.", \ - filters.nblockdst+1); - exit(EXIT_FAILURE); - } - - if((charptr = strtok_r(NULL, " ", &lasts)) == NULL){ - filters.blockdstlen[filters.nblockdst] = 128; - } - else{ - filters.blockdstlen[filters.nblockdst] = atoi(charptr); - - if(filters.blockdstlen[filters.nblockdst]>128){ - printf("Length error in IPv6 Source Address (block) filter number %u.\n", \ - filters.nblockdst+1); - exit(EXIT_FAILURE); - } - } - - sanitize_ipv6_prefix(&(filters.blockdst[filters.nblockdst]), filters.blockdstlen[filters.nblockdst]); - (filters.nblockdst)++; - break; - - case 'J': /* Link Source Address (block) filter */ - if(filters.nblocklinksrc > MAX_BLOCK_LINK_SRC){ - puts("Too many link-layer Source Address (accept) filters."); - exit(EXIT_FAILURE); - } - - if(ether_pton(optarg, &(filters.blocklinksrc[filters.nblocklinksrc]), sizeof(struct ether_addr)) == 0){ - printf("Error in link-layer Source Address (blick) filter number %u.\n", \ - filters.nblocklinksrc+1); - exit(EXIT_FAILURE); - } - - (filters.nblocklinksrc)++; - break; - - case 'K': /* Link Destination Address (block) filter */ - if(filters.nblocklinkdst > MAX_BLOCK_LINK_DST){ - puts("Too many link-layer Destination Address (block) filters."); - exit(EXIT_FAILURE); - } - - if(ether_pton(optarg, &(filters.blocklinkdst[filters.nblocklinkdst]), sizeof(struct ether_addr)) == 0){ - printf("Error in link-layer Destination Address (blick) filter number %u.\n", \ - filters.nblocklinkdst+1); - exit(EXIT_FAILURE); - } - - filters.nblocklinkdst++; - break; - - case 'b': /* IPv6 Source Address (accept) filter */ - if(filters.nacceptsrc > MAX_ACCEPT_SRC){ - puts("Too many IPv6 Source Address (accept) filters."); - exit(EXIT_FAILURE); - } - - if((pref = strtok_r(optarg, "/", &lasts)) == NULL){ - printf("Error in IPv6 Source Address (accept) filter number %u.\n", \ - filters.nacceptsrc+1); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, pref, &(filters.acceptsrc[filters.nacceptsrc])) <= 0){ - printf("Error in IPv6 Source Address (accept) filter number %u.\n", \ - filters.nacceptsrc+1); - exit(EXIT_FAILURE); - } - - if((charptr = strtok_r(NULL, " ", &lasts)) == NULL){ - filters.acceptsrclen[filters.nacceptsrc] = 128; - } - else{ - filters.acceptsrclen[filters.nacceptsrc] = atoi(charptr); - - if(filters.acceptsrclen[filters.nacceptsrc]>128){ - printf("Length error in IPv6 Source Address (accept) filter number %u.\n", \ - filters.nacceptsrc+1); - exit(EXIT_FAILURE); - } - } - - sanitize_ipv6_prefix(&(filters.acceptsrc[filters.nacceptsrc]), filters.acceptsrclen[filters.nacceptsrc]); - (filters.nacceptsrc)++; - filters.acceptfilters_f=1; - break; - - - case 'g': /* IPv6 Destination Address (accept) filter */ - if(filters.nacceptdst > MAX_ACCEPT_DST){ - puts("Too many IPv6 Destination Address (accept) filters."); - exit(EXIT_FAILURE); - } - - if((pref = strtok_r(optarg, "/", &lasts)) == NULL){ - printf("Error in IPv6 Destination Address (accept) filter number %u.\n", \ - filters.nacceptdst+1); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, pref, &(filters.acceptdst[filters.nacceptdst])) <= 0){ - printf("Error in IPv6 Source Address (accept) filter number %u.\n", \ - filters.nacceptdst+1); - exit(EXIT_FAILURE); - } - - if((charptr = strtok_r(NULL, " ", &lasts)) == NULL){ - filters.acceptdstlen[filters.nacceptdst] = 128; - } - else{ - filters.acceptdstlen[filters.nacceptdst] = atoi(charptr); - - if(filters.acceptdstlen[filters.nacceptdst] > 128){ - printf("Length error in IPv6 Source Address (accept) filter number %u.\n", \ - filters.nacceptdst+1); - exit(EXIT_FAILURE); - } - } - - sanitize_ipv6_prefix(&(filters.acceptdst[filters.nacceptdst]), filters.acceptdstlen[filters.nacceptdst]); - (filters.nacceptdst)++; - filters.acceptfilters_f=1; - break; - - case 'B': /* Link-layer Source Address (accept) filter */ - if(filters.nacceptlinksrc > MAX_ACCEPT_LINK_SRC){ - puts("Too many link-later Source Address (accept) filters."); - exit(EXIT_FAILURE); - } - - if(ether_pton(optarg, &(filters.acceptlinksrc[filters.nacceptlinksrc]), sizeof(struct ether_addr)) == 0){ - printf("Error in link-layer Source Address (accept) filter number %u.\n", \ - filters.nacceptlinksrc+1); - exit(EXIT_FAILURE); - } - - (filters.nacceptlinksrc)++; - filters.acceptfilters_f=1; - break; - - case 'G': /* Link Destination Address (accept) filter */ - if(filters.nacceptlinkdst > MAX_ACCEPT_LINK_DST){ - puts("Too many link-layer Destination Address (accept) filters."); - exit(EXIT_FAILURE); - } - - if(ether_pton(optarg, &(filters.acceptlinkdst[filters.nacceptlinkdst]), sizeof(struct ether_addr)) == 0){ - printf("Error in link-layer Destination Address (accept) filter number %u.\n",\ - filters.nacceptlinkdst+1); - exit(EXIT_FAILURE); - } - - (filters.nacceptlinkdst)++; - filters.acceptfilters_f=1; - break; - - case 'w': /* ND Target Address (block) filter */ - if(filters.nblocktarget > MAX_BLOCK_TARGET){ - puts("Too many Target Address (block) filters."); - exit(EXIT_FAILURE); - } - - if((pref = strtok_r(optarg, "/", &lasts)) == NULL){ - printf("Error in Target Address (block) filter number %u.\n", filters.nblocktarget+1); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, pref, &(filters.blocktarget[filters.nblocktarget])) <= 0){ - printf("Error in Target Address (block) filter number %u.\n", filters.nblocktarget+1); - exit(EXIT_FAILURE); - } - - if((charptr = strtok_r(NULL, " ", &lasts)) == NULL){ - filters.blocktargetlen[filters.nblocktarget] = 128; - } - else{ - filters.blocktargetlen[filters.nblocktarget] = atoi(charptr); - - if(filters.blocktargetlen[filters.nblocktarget]>128){ - printf("Length error in Target Address (block) filter number %u.\n", filters.nblocktarget+1); - exit(EXIT_FAILURE); - } - } - - sanitize_ipv6_prefix(&(filters.blocktarget[filters.nblocktarget]), filters.blocktargetlen[filters.nblocktarget]); - filters.nblocktarget++; - break; - - case 'W': /* ND Target Address (accept) filter */ - if(filters.naccepttarget >= MAX_ACCEPT_TARGET){ - puts("Too many Target Address (accept) filters."); - exit(EXIT_FAILURE); - } - - if((pref = strtok_r(optarg, "/", &lasts)) == NULL){ - printf("Error in Target Address (accept) filter number %u.\n", filters.naccepttarget+1); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, pref, &(filters.accepttarget[filters.naccepttarget])) <= 0){ - printf("Error in Target Address (accept) filter number %u.\n", filters.naccepttarget+1); - exit(EXIT_FAILURE); - } - - if((charptr = strtok_r(NULL, " ", &lasts)) == NULL){ - filters.accepttargetlen[filters.naccepttarget] = 128; - } - else{ - filters.accepttargetlen[filters.naccepttarget] = atoi(charptr); - - if(filters.accepttargetlen[filters.naccepttarget]>128){ - printf("Length error in Target Address (accept) filter number %u.\n", \ - filters.naccepttarget+1); - exit(EXIT_FAILURE); - } - } - - sanitize_ipv6_prefix(&(filters.accepttarget[filters.naccepttarget]), filters.accepttargetlen[filters.naccepttarget]); - filters.naccepttarget++; - filters.acceptfilters_f=1; - break; - - case 'L': /* "Listen mode */ - listen_f = 1; - break; - - case 'T': /* Flood targets */ - ntargets= atoi(optarg); - if(ntargets == 0){ - puts("Invalid number of Target Addresses in option -T"); - exit(EXIT_FAILURE); - } - - floodt_f= 1; - break; - - case 'l': /* "Loop mode */ - loop_f = 1; - break; - - case 'z': /* Sleep option */ - nsleep=atoi(optarg); - if(nsleep==0){ - puts("Invalid number of seconds in '-z' option"); - exit(EXIT_FAILURE); - } - - sleep_f=1; - break; - - case 'v': /* Be verbose */ - idata.verbose_f=1; - break; - - case 'h': /* Help */ - print_help(); - - exit(EXIT_FAILURE); - break; - - default: - usage(); - exit(EXIT_FAILURE); - break; - - } /* switch */ + struct target_ipv6 targetipv6; + + static struct option longopts[] = {{"interface", required_argument, 0, 'i'}, + {"src-addr", required_argument, 0, 's'}, + {"dst-addr", required_argument, 0, 'd'}, + {"hop-limit", required_argument, 0, 'A'}, + {"dst-opt-hdr", required_argument, 0, 'u'}, + {"dst-opt-u-hdr", required_argument, 0, 'U'}, + {"hbh-opt-hdr", required_argument, 0, 'H'}, + {"frag-hdr", required_argument, 0, 'y'}, + {"link-src-addr", required_argument, 0, 'S'}, + {"link-dst-addr", required_argument, 0, 'D'}, + {"target-address", required_argument, 0, 't'}, + {"source-lla-opt", required_argument, 0, 'E'}, + {"add-slla-opt", no_argument, 0, 'e'}, + {"block-src-addr", required_argument, 0, 'j'}, + {"block-dst-addr", required_argument, 0, 'k'}, + {"block-link-src-addr", required_argument, 0, 'J'}, + {"block-link-dst-addr", required_argument, 0, 'K'}, + {"block-target-addr", required_argument, 0, 'w'}, + {"accept-src-addr", required_argument, 0, 'b'}, + {"accept-dst-addr", required_argument, 0, 'g'}, + {"accept-link-src-addr", required_argument, 0, 'B'}, + {"accept-link-dst-addr", required_argument, 0, 'G'}, + {"accept-target-addr", required_argument, 0, 'W'}, + {"flood-sources", required_argument, 0, 'F'}, + {"flood-targets", required_argument, 0, 'T'}, + {"loop", no_argument, 0, 'l'}, + {"sleep", no_argument, 0, 'z'}, + {"listen", no_argument, 0, 'L'}, + {"verbose", no_argument, 0, 'v'}, + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0}}; + + const char shortopts[] = "i:s:d:A:u:U:H:y:S:D:t:eE:j:k:J:K:w:b:g:B:G:W:F:T:lz:Lvh"; + char option; + + if (argc <= 1) { + usage(); + exit(EXIT_FAILURE); + } + + hoplimit = 255; + + if (init_iface_data(&idata) == FAILURE) { + puts("Error initializing internal data structure"); + exit(EXIT_FAILURE); + } + + while ((r = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { + option = r; + + switch (option) { + case 'i': /* Interface */ + strncpy(idata.iface, optarg, IFACE_LENGTH); + idata.iface[IFACE_LENGTH - 1] = 0; + idata.iface_f = 1; + break; + + case 's': /* IPv6 Source Address */ + if ((charptr = strtok_r(optarg, "/", &lasts)) == NULL) { + puts("inet_pton(): address not valid"); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, charptr, &(idata.srcaddr)) <= 0) { + puts("inet_pton(): address not valid"); + exit(EXIT_FAILURE); + } + + idata.srcaddr_f = 1; + + if ((charptr = strtok_r(NULL, " ", &lasts)) != NULL) { + idata.srcpreflen = atoi(charptr); + + if (idata.srcpreflen > 128) { + puts("Prefix length error in IPv6 Source Address"); + exit(EXIT_FAILURE); + } + + sanitize_ipv6_prefix(&(idata.srcaddr), idata.srcpreflen); + idata.srcprefix_f = 1; + } + + break; + + case 'd': /* IPv6 Destination Address */ + strncpy(targetipv6.name, optarg, NI_MAXHOST); + targetipv6.name[NI_MAXHOST - 1] = 0; + targetipv6.flags = AI_CANONNAME; + + if ((r = get_ipv6_target(&targetipv6)) != 0) { + + if (r < 0) { + printf("Unknown Destination: %s\n", gai_strerror(targetipv6.res)); + } + else { + puts("Unknown Destination: No IPv6 address found for specified destination"); + } + + exit(EXIT_FAILURE); + } + + idata.dstaddr = targetipv6.ip6; + idata.dstaddr_f = 1; + break; + + case 'A': /* Hop Limit */ + hoplimit = atoi(optarg); + hoplimit_f = 1; + break; + + case 'y': /* Fragment header */ + nfrags = atoi(optarg); + + if (nfrags < 8) { + puts("Error in Fragmentation option: Fragment Size must be at least 8 bytes"); + exit(EXIT_FAILURE); + } + + idata.fragh_f = 1; + break; + + case 'u': /* Destinations Options Header */ + if (ndstopthdr >= MAX_DST_OPT_HDR) { + puts("Too many Destination Options Headers"); + exit(EXIT_FAILURE); + } + + hdrlen = atoi(optarg); + + if (hdrlen < 8) { + puts("Bad length in Destination Options Header"); + exit(EXIT_FAILURE); + } + + hdrlen = ((hdrlen + 7) / 8) * 8; + dstopthdrlen[ndstopthdr] = hdrlen; + + if ((dstopthdr[ndstopthdr] = malloc(hdrlen)) == NULL) { + puts("Not enough memory for Destination Options Header"); + exit(EXIT_FAILURE); + } + + ptrhdr = dstopthdr[ndstopthdr] + 2; + ptrhdrend = dstopthdr[ndstopthdr] + hdrlen; + + while (ptrhdr < ptrhdrend) { + + if ((ptrhdrend - ptrhdr) > 257) + pad = 257; + else + pad = ptrhdrend - ptrhdr; + + if (!insert_pad_opt(ptrhdr, ptrhdrend, pad)) { + puts("Destination Options Header Too Big"); + exit(EXIT_FAILURE); + } + + ptrhdr = ptrhdr + pad; + } + + *(dstopthdr[ndstopthdr] + 1) = (hdrlen / 8) - 1; + ndstopthdr++; + dstopthdr_f = 1; + break; + + case 'U': /* Destination Options Header (Unfragmentable Part) */ + if (ndstoptuhdr >= MAX_DST_OPT_U_HDR) { + puts("Too many Destination Options Headers (Unfragmentable Part)"); + exit(EXIT_FAILURE); + } + + hdrlen = atoi(optarg); + + if (hdrlen < 8) { + puts("Bad length in Destination Options Header (Unfragmentable Part)"); + exit(EXIT_FAILURE); + } + + hdrlen = ((hdrlen + 7) / 8) * 8; + dstoptuhdrlen[ndstoptuhdr] = hdrlen; + + if ((dstoptuhdr[ndstoptuhdr] = malloc(hdrlen)) == NULL) { + puts("Not enough memory for Destination Options Header (Unfragmentable Part)"); + exit(EXIT_FAILURE); + } + + ptrhdr = dstoptuhdr[ndstoptuhdr] + 2; + ptrhdrend = dstoptuhdr[ndstoptuhdr] + hdrlen; + + while (ptrhdr < ptrhdrend) { + + if ((ptrhdrend - ptrhdr) > 257) + pad = 257; + else + pad = ptrhdrend - ptrhdr; + + if (!insert_pad_opt(ptrhdr, ptrhdrend, pad)) { + puts("Destination Options Header (Unfragmentable Part) Too Big"); + exit(EXIT_FAILURE); + } + + ptrhdr = ptrhdr + pad; + } + + *(dstoptuhdr[ndstoptuhdr] + 1) = (hdrlen / 8) - 1; + ndstoptuhdr++; + dstoptuhdr_f = 1; + break; + + case 'H': /* Hop-by-Hop Options Header */ + if (nhbhopthdr >= MAX_HBH_OPT_HDR) { + puts("Too many Hop-by-Hop Options Headers"); + exit(EXIT_FAILURE); + } + + hdrlen = atoi(optarg); + + if (hdrlen < 8) { + puts("Bad length in Hop-by-Hop Options Header"); + exit(EXIT_FAILURE); + } + + hdrlen = ((hdrlen + 7) / 8) * 8; + hbhopthdrlen[nhbhopthdr] = hdrlen; + + if ((hbhopthdr[nhbhopthdr] = malloc(hdrlen)) == NULL) { + puts("Not enough memory for Hop-by-Hop Options Header"); + exit(EXIT_FAILURE); + } + + ptrhdr = hbhopthdr[nhbhopthdr] + 2; + ptrhdrend = hbhopthdr[nhbhopthdr] + hdrlen; + + while (ptrhdr < ptrhdrend) { + + if ((ptrhdrend - ptrhdr) > 257) + pad = 257; + else + pad = ptrhdrend - ptrhdr; + + if (!insert_pad_opt(ptrhdr, ptrhdrend, pad)) { + puts("Hop-by-Hop Options Header Too Big"); + exit(EXIT_FAILURE); + } + + ptrhdr = ptrhdr + pad; + } + + *(hbhopthdr[nhbhopthdr] + 1) = (hdrlen / 8) - 1; + nhbhopthdr++; + hbhopthdr_f = 1; + break; + + case 'S': /* Source Ethernet address */ + if (ether_pton(optarg, &(idata.hsrcaddr), sizeof(idata.hsrcaddr)) == 0) { + puts("Error in Source link-layer address."); + exit(EXIT_FAILURE); + } + + idata.hsrcaddr_f = 1; + break; + + case 'D': /* Destination Ethernet Address */ + if (ether_pton(optarg, &(idata.hdstaddr), sizeof(idata.hdstaddr)) == 0) { + puts("Error in Source link-layer address."); + exit(EXIT_FAILURE); + } + + idata.hdstaddr_f = 1; + break; + + case 't': /* NA Target address */ + if ((charptr = strtok_r(optarg, "/", &lasts)) == NULL) { + puts("Target Address not valid"); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, charptr, &targetaddr) <= 0) { + puts("inet_pton(): Target Address not valid"); + exit(EXIT_FAILURE); + } + + targetaddr_f = 1; + + if ((charptr = strtok_r(NULL, " ", &lasts)) != NULL) { + targetpreflen = atoi(charptr); + + if (targetpreflen > 128) { + puts("Prefix length error in Target Address"); + exit(EXIT_FAILURE); + } + + sanitize_ipv6_prefix(&targetaddr, targetpreflen); + targetprefix_f = 1; + } + + break; + + case 'E': /* Source link-layer option */ + sllopt_f = 1; + + if (ether_pton(optarg, &linkaddr[nlinkaddr], sizeof(struct ether_addr)) == 0) { + puts("Error in Source link-layer address option."); + exit(EXIT_FAILURE); + } + + sllopta_f = 1; + nlinkaddr++; + break; + + case 'e': /* Add Source link-layer option */ + sllopt_f = 1; + break; + + case 'F': /* Flood sources */ + nsources = atoi(optarg); + if (nsources == 0) { + puts("Invalid number of sources in option -F"); + exit(EXIT_FAILURE); + } + + floods_f = 1; + break; + + case 'j': /* IPv6 Source Address (block) filter */ + if (filters.nblocksrc >= MAX_BLOCK_SRC) { + puts("Too many IPv6 Source Address (block) filters."); + exit(EXIT_FAILURE); + } + + if ((pref = strtok_r(optarg, "/", &lasts)) == NULL) { + printf("Error in IPv6 Source Address (block) filter number %u.\n", filters.nblocksrc + 1); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, pref, &(filters.blocksrc[filters.nblocksrc])) <= 0) { + printf("Error in IPv6 Source Address (block) filter number %u.", filters.nblocksrc + 1); + exit(EXIT_FAILURE); + } + + if ((charptr = strtok_r(NULL, " ", &lasts)) == NULL) { + filters.blocksrclen[filters.nblocksrc] = 128; + } + else { + filters.blocksrclen[filters.nblocksrc] = atoi(charptr); + + if (filters.blocksrclen[filters.nblocksrc] > 128) { + printf("Length error in IPv6 Source Address (block) filter number %u.\n", filters.nblocksrc + 1); + exit(EXIT_FAILURE); + } + } + + sanitize_ipv6_prefix(&(filters.blocksrc[filters.nblocksrc]), filters.blocksrclen[filters.nblocksrc]); + (filters.nblocksrc)++; + break; + + case 'k': /* IPv6 Destination Address (block) filter */ + if (filters.nblockdst >= MAX_BLOCK_DST) { + puts("Too many IPv6 Destination Address (block) filters."); + exit(EXIT_FAILURE); + } + + if ((pref = strtok_r(optarg, "/", &lasts)) == NULL) { + printf("Error in IPv6 Destination Address (block) filter number %u.\n", filters.nblockdst + 1); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, pref, &(filters.blockdst[filters.nblockdst])) <= 0) { + printf("Error in IPv6 Source Address (block) filter number %u.", filters.nblockdst + 1); + exit(EXIT_FAILURE); + } + + if ((charptr = strtok_r(NULL, " ", &lasts)) == NULL) { + filters.blockdstlen[filters.nblockdst] = 128; + } + else { + filters.blockdstlen[filters.nblockdst] = atoi(charptr); + + if (filters.blockdstlen[filters.nblockdst] > 128) { + printf("Length error in IPv6 Source Address (block) filter number %u.\n", filters.nblockdst + 1); + exit(EXIT_FAILURE); + } + } + + sanitize_ipv6_prefix(&(filters.blockdst[filters.nblockdst]), filters.blockdstlen[filters.nblockdst]); + (filters.nblockdst)++; + break; + + case 'J': /* Link Source Address (block) filter */ + if (filters.nblocklinksrc > MAX_BLOCK_LINK_SRC) { + puts("Too many link-layer Source Address (accept) filters."); + exit(EXIT_FAILURE); + } + + if (ether_pton(optarg, &(filters.blocklinksrc[filters.nblocklinksrc]), sizeof(struct ether_addr)) == 0) { + printf("Error in link-layer Source Address (blick) filter number %u.\n", filters.nblocklinksrc + 1); + exit(EXIT_FAILURE); + } + + (filters.nblocklinksrc)++; + break; + + case 'K': /* Link Destination Address (block) filter */ + if (filters.nblocklinkdst > MAX_BLOCK_LINK_DST) { + puts("Too many link-layer Destination Address (block) filters."); + exit(EXIT_FAILURE); + } + + if (ether_pton(optarg, &(filters.blocklinkdst[filters.nblocklinkdst]), sizeof(struct ether_addr)) == 0) { + printf("Error in link-layer Destination Address (blick) filter number %u.\n", + filters.nblocklinkdst + 1); + exit(EXIT_FAILURE); + } + + filters.nblocklinkdst++; + break; + + case 'b': /* IPv6 Source Address (accept) filter */ + if (filters.nacceptsrc > MAX_ACCEPT_SRC) { + puts("Too many IPv6 Source Address (accept) filters."); + exit(EXIT_FAILURE); + } + + if ((pref = strtok_r(optarg, "/", &lasts)) == NULL) { + printf("Error in IPv6 Source Address (accept) filter number %u.\n", filters.nacceptsrc + 1); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, pref, &(filters.acceptsrc[filters.nacceptsrc])) <= 0) { + printf("Error in IPv6 Source Address (accept) filter number %u.\n", filters.nacceptsrc + 1); + exit(EXIT_FAILURE); + } + + if ((charptr = strtok_r(NULL, " ", &lasts)) == NULL) { + filters.acceptsrclen[filters.nacceptsrc] = 128; + } + else { + filters.acceptsrclen[filters.nacceptsrc] = atoi(charptr); + + if (filters.acceptsrclen[filters.nacceptsrc] > 128) { + printf("Length error in IPv6 Source Address (accept) filter number %u.\n", filters.nacceptsrc + 1); + exit(EXIT_FAILURE); + } + } + + sanitize_ipv6_prefix(&(filters.acceptsrc[filters.nacceptsrc]), filters.acceptsrclen[filters.nacceptsrc]); + (filters.nacceptsrc)++; + filters.acceptfilters_f = 1; + break; + + case 'g': /* IPv6 Destination Address (accept) filter */ + if (filters.nacceptdst > MAX_ACCEPT_DST) { + puts("Too many IPv6 Destination Address (accept) filters."); + exit(EXIT_FAILURE); + } + + if ((pref = strtok_r(optarg, "/", &lasts)) == NULL) { + printf("Error in IPv6 Destination Address (accept) filter number %u.\n", filters.nacceptdst + 1); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, pref, &(filters.acceptdst[filters.nacceptdst])) <= 0) { + printf("Error in IPv6 Source Address (accept) filter number %u.\n", filters.nacceptdst + 1); + exit(EXIT_FAILURE); + } + + if ((charptr = strtok_r(NULL, " ", &lasts)) == NULL) { + filters.acceptdstlen[filters.nacceptdst] = 128; + } + else { + filters.acceptdstlen[filters.nacceptdst] = atoi(charptr); + + if (filters.acceptdstlen[filters.nacceptdst] > 128) { + printf("Length error in IPv6 Source Address (accept) filter number %u.\n", filters.nacceptdst + 1); + exit(EXIT_FAILURE); + } + } + + sanitize_ipv6_prefix(&(filters.acceptdst[filters.nacceptdst]), filters.acceptdstlen[filters.nacceptdst]); + (filters.nacceptdst)++; + filters.acceptfilters_f = 1; + break; + + case 'B': /* Link-layer Source Address (accept) filter */ + if (filters.nacceptlinksrc > MAX_ACCEPT_LINK_SRC) { + puts("Too many link-later Source Address (accept) filters."); + exit(EXIT_FAILURE); + } + + if (ether_pton(optarg, &(filters.acceptlinksrc[filters.nacceptlinksrc]), sizeof(struct ether_addr)) == 0) { + printf("Error in link-layer Source Address (accept) filter number %u.\n", filters.nacceptlinksrc + 1); + exit(EXIT_FAILURE); + } + + (filters.nacceptlinksrc)++; + filters.acceptfilters_f = 1; + break; + + case 'G': /* Link Destination Address (accept) filter */ + if (filters.nacceptlinkdst > MAX_ACCEPT_LINK_DST) { + puts("Too many link-layer Destination Address (accept) filters."); + exit(EXIT_FAILURE); + } + + if (ether_pton(optarg, &(filters.acceptlinkdst[filters.nacceptlinkdst]), sizeof(struct ether_addr)) == 0) { + printf("Error in link-layer Destination Address (accept) filter number %u.\n", + filters.nacceptlinkdst + 1); + exit(EXIT_FAILURE); + } + + (filters.nacceptlinkdst)++; + filters.acceptfilters_f = 1; + break; + + case 'w': /* ND Target Address (block) filter */ + if (filters.nblocktarget > MAX_BLOCK_TARGET) { + puts("Too many Target Address (block) filters."); + exit(EXIT_FAILURE); + } + + if ((pref = strtok_r(optarg, "/", &lasts)) == NULL) { + printf("Error in Target Address (block) filter number %u.\n", filters.nblocktarget + 1); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, pref, &(filters.blocktarget[filters.nblocktarget])) <= 0) { + printf("Error in Target Address (block) filter number %u.\n", filters.nblocktarget + 1); + exit(EXIT_FAILURE); + } + + if ((charptr = strtok_r(NULL, " ", &lasts)) == NULL) { + filters.blocktargetlen[filters.nblocktarget] = 128; + } + else { + filters.blocktargetlen[filters.nblocktarget] = atoi(charptr); + + if (filters.blocktargetlen[filters.nblocktarget] > 128) { + printf("Length error in Target Address (block) filter number %u.\n", filters.nblocktarget + 1); + exit(EXIT_FAILURE); + } + } + + sanitize_ipv6_prefix(&(filters.blocktarget[filters.nblocktarget]), + filters.blocktargetlen[filters.nblocktarget]); + filters.nblocktarget++; + break; + + case 'W': /* ND Target Address (accept) filter */ + if (filters.naccepttarget >= MAX_ACCEPT_TARGET) { + puts("Too many Target Address (accept) filters."); + exit(EXIT_FAILURE); + } + + if ((pref = strtok_r(optarg, "/", &lasts)) == NULL) { + printf("Error in Target Address (accept) filter number %u.\n", filters.naccepttarget + 1); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, pref, &(filters.accepttarget[filters.naccepttarget])) <= 0) { + printf("Error in Target Address (accept) filter number %u.\n", filters.naccepttarget + 1); + exit(EXIT_FAILURE); + } + + if ((charptr = strtok_r(NULL, " ", &lasts)) == NULL) { + filters.accepttargetlen[filters.naccepttarget] = 128; + } + else { + filters.accepttargetlen[filters.naccepttarget] = atoi(charptr); + + if (filters.accepttargetlen[filters.naccepttarget] > 128) { + printf("Length error in Target Address (accept) filter number %u.\n", filters.naccepttarget + 1); + exit(EXIT_FAILURE); + } + } + + sanitize_ipv6_prefix(&(filters.accepttarget[filters.naccepttarget]), + filters.accepttargetlen[filters.naccepttarget]); + filters.naccepttarget++; + filters.acceptfilters_f = 1; + break; + + case 'L': /* "Listen mode */ + listen_f = 1; + break; + + case 'T': /* Flood targets */ + ntargets = atoi(optarg); + if (ntargets == 0) { + puts("Invalid number of Target Addresses in option -T"); + exit(EXIT_FAILURE); + } + + floodt_f = 1; + break; + + case 'l': /* "Loop mode */ + loop_f = 1; + break; + + case 'z': /* Sleep option */ + nsleep = atoi(optarg); + if (nsleep == 0) { + puts("Invalid number of seconds in '-z' option"); + exit(EXIT_FAILURE); + } + + sleep_f = 1; + break; + + case 'v': /* Be verbose */ + idata.verbose_f = 1; + break; + + case 'h': /* Help */ + print_help(); + + exit(EXIT_FAILURE); + break; + + default: + usage(); + exit(EXIT_FAILURE); + break; + + } /* switch */ } /* while(getopt) */ - if(geteuid()) { - puts("ns6 needs root privileges to run."); - exit(EXIT_FAILURE); - } + if (geteuid()) { + puts("ns6 needs root privileges to run."); + exit(EXIT_FAILURE); + } - if(!idata.iface_f){ - puts("Must specify the network interface with the -i option"); - exit(EXIT_FAILURE); - } - + if (!idata.iface_f) { + puts("Must specify the network interface with the -i option"); + exit(EXIT_FAILURE); + } - if(listen_f){ + if (listen_f) { - /* Initialize filters structure */ - if(init_filters(&filters) == -1){ - puts("Error initializing internal data structure"); - exit(EXIT_FAILURE); - } + /* Initialize filters structure */ + if (init_filters(&filters) == -1) { + puts("Error initializing internal data structure"); + exit(EXIT_FAILURE); + } - FD_ZERO(&sset); - FD_SET(idata.fd, &sset); + FD_ZERO(&sset); + FD_SET(idata.fd, &sset); - if(idata.verbose_f){ - print_filters(&idata, &filters); - puts("Listening to incoming ICMPv6 Neighbor Solicitation messages..."); - } + if (idata.verbose_f) { + print_filters(&idata, &filters); + puts("Listening to incoming ICMPv6 Neighbor Solicitation messages..."); + } - /* Set initial contents of the attack packet */ - init_packet_data(&idata); + /* Set initial contents of the attack packet */ + init_packet_data(&idata); - while(listen_f){ - rset= sset; + while (listen_f) { + rset = sset; #if defined(sun) || defined(__sun) || defined(__linux__) - timeout.tv_usec=1000; - timeout.tv_sec= 0; - if((sel=select(idata.fd+1, &rset, NULL, NULL, &timeout)) == -1){ + timeout.tv_usec = 1000; + timeout.tv_sec = 0; + if ((sel = select(idata.fd + 1, &rset, NULL, NULL, &timeout)) == -1) { #else - if((sel=select(idata.fd+1, &rset, NULL, NULL, NULL)) == -1){ + if ((sel = select(idata.fd + 1, &rset, NULL, NULL, NULL)) == -1) { #endif - if(errno == EINTR){ - continue; - } - else{ - puts("Error in select()"); - exit(EXIT_FAILURE); - } - } + if (errno == EINTR) { + continue; + } + else { + puts("Error in select()"); + exit(EXIT_FAILURE); + } + } #if defined(sun) || defined(__sun) || defined(__linux__) - if(TRUE){ + if (TRUE) { #else - if(sel && FD_ISSET(idata.fd, &rset)){ + if (sel && FD_ISSET(idata.fd, &rset)) { #endif - /* Read a Neighbor Solicitation message */ - if((r=pcap_next_ex(idata.pfd, &pkthdr, &pktdata)) == -1){ - printf("pcap_next_ex(): %s", pcap_geterr(idata.pfd)); - exit(EXIT_FAILURE); - } - else if(r == 1 && pktdata != NULL){ - /* XXX Code assumes no IPv6 Extension Headers */ - pkt_ether = (struct ether_header *) pktdata; - pkt_ipv6 = (struct ip6_hdr *)((char *) pkt_ether + idata.linkhsize); - pkt_ns = (struct nd_neighbor_solicit *) ((char *) pkt_ipv6 + MIN_IPV6_HLEN); - pkt_icmp6= (struct icmp6_hdr *) pkt_ns; - - /* XXX This should probably be removed when pcap filter problem is solved */ - if(pkt_ipv6->ip6_nxt != IPPROTO_ICMPV6 || pkt_icmp6->icmp6_type != ND_NEIGHBOR_SOLICIT || \ - pkt_icmp6->icmp6_code != 0) - continue; - - accepted_f=0; - - if(idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK)){ - if(filters.nblocklinksrc){ - if(match_ether(filters.blocklinksrc, filters.nblocklinksrc, &(pkt_ether->src))){ - if(idata.verbose_f>1) - print_filter_result(&idata, pktdata, BLOCKED); - - continue; - } - } - - if(filters.nblocklinkdst){ - if(match_ether(filters.blocklinkdst, filters.nblocklinkdst, &(pkt_ether->dst))){ - if(idata.verbose_f>1) - print_filter_result(&idata, pktdata, BLOCKED); - - continue; - } - } - } - - if(filters.nblocksrc){ - if(match_ipv6(filters.blocksrc, filters.blocksrclen, filters.nblocksrc, &(pkt_ipv6->ip6_src))){ - if(idata.verbose_f>1) - print_filter_result(&idata, pktdata, BLOCKED); - - continue; - } - } - - if(filters.nblockdst){ - if(match_ipv6(filters.blockdst, filters.blockdstlen, filters.nblockdst, &(pkt_ipv6->ip6_dst))){ - if(idata.verbose_f>1) - print_filter_result(&idata, pktdata, BLOCKED); - - continue; - } - } - - if(filters.nblocktarget){ - if(match_ipv6(filters.blocktarget, filters.blocktargetlen, filters.nblocktarget, &(pkt_ns->nd_ns_target))){ - if(idata.verbose_f>1) - print_filter_result(&idata, pktdata, BLOCKED); - - continue; - } - } - - if(idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK)){ - if(filters.nacceptlinksrc){ - if(match_ether(filters.acceptlinksrc, filters.nacceptlinksrc, &(pkt_ether->src))) - accepted_f=1; - } - - if(filters.nacceptlinkdst && !accepted_f){ - if(match_ether(filters.acceptlinkdst, filters.nacceptlinkdst, &(pkt_ether->dst))) - accepted_f= 1; - } - } - - if(filters.nacceptsrc && !accepted_f){ - if(match_ipv6(filters.acceptsrc, filters.acceptsrclen, filters.nacceptsrc, &(pkt_ipv6->ip6_src))) - accepted_f= 1; - } - - if(filters.nacceptdst && !accepted_f){ - if(match_ipv6(filters.acceptdst, filters.acceptdstlen, filters.nacceptdst, &(pkt_ipv6->ip6_dst))) - accepted_f=1; - } - - if(filters.naccepttarget && !accepted_f){ - if(match_ipv6(filters.accepttarget, filters.accepttargetlen, filters.naccepttarget, &(pkt_ns->nd_ns_target))) - accepted_f=1; - } - - if(filters.acceptfilters_f && !accepted_f){ - if(idata.verbose_f>1) - print_filter_result(&idata, pktdata, BLOCKED); - - continue; - } - - if(idata.verbose_f) - print_filter_result(&idata, pktdata, ACCEPTED); - - /* Send a Neighbor Advertisement */ - if(send_packet_to_ns(&idata, pkthdr, pktdata) == FAILURE){ - puts("Error while sending packet"); - exit(EXIT_FAILURE); - } - } - } - } - - exit(EXIT_SUCCESS); - } - else{ - - - if(!targetaddr_f){ - puts("Must specify a ND target address with the '-t' option"); - exit(EXIT_FAILURE); - } - - if(load_dst_and_pcap(&idata, LOAD_PCAP_ONLY) == FAILURE){ - puts("Error while learning Source Address and Next Hop"); - exit(EXIT_FAILURE); - } - - release_privileges(); - - if(pcap_compile(idata.pfd, &pcap_filter, PCAP_NOPACKETS_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1){ - printf("pcap_compile(): %s", pcap_geterr(idata.pfd)); - exit(EXIT_FAILURE); - } - - if(pcap_setfilter(idata.pfd, &pcap_filter) == -1){ - printf("pcap_setfilter(): %s", pcap_geterr(idata.pfd)); - exit(EXIT_FAILURE); - } - - pcap_freecode(&pcap_filter); - - srandom(time(NULL)); - - /* - If the IPv6 Source Address has not been specified, and the "-F" (flood) option has - not been specified, select a random link-local unicast address. - */ - if(!idata.srcaddr_f && !floods_f){ - /* - When randomizing a link-local IPv6 address, select addresses that belong to the - prefix fe80::/64 (that's what a link-local address looks-like in legitimate cases). - The KAME implementation discards addresses in which the second highe-order 16 bits - (srcaddr.s6_addr16[1] in our case) are not zero. - */ - if ( inet_pton(AF_INET6, "fe80::", &(idata.srcaddr)) <= 0){ - puts("inet_pton(): Error when converting address"); - exit(EXIT_FAILURE); - } - - randomize_ipv6_addr(&(idata.srcaddr), &(idata.srcaddr), 64); - } - - - /* - If the flood option ("-F") has been specified, but no prefix has been specified, - select the random Source Addresses from the link-local unicast prefix (fe80::/64). - */ - if(floods_f && !idata.srcprefix_f){ - if ( inet_pton(AF_INET6, "fe80::", &(idata.srcaddr)) <= 0){ - puts("inet_pton(): Error when converting address"); - exit(EXIT_FAILURE); - } - - randomize_ipv6_addr(&(idata.srcaddr), &(idata.srcaddr), 64); - idata.srcpreflen=64; - } - - /* - If the flood target option ("-T") was specified, but no prefix was specified, - select the random Target Addresses from the link-local unicast prefix (fe80::/64). - */ - if(floodt_f && !targetprefix_f){ - if ( inet_pton(AF_INET6, "fe80::", &(targetaddr)) <= 0){ - puts("inet_pton(): Error when converting address"); - exit(EXIT_FAILURE); - } - - randomize_ipv6_addr(&(targetaddr), &(targetaddr), 64); - targetpreflen=64; - } - - if(!floodt_f) - ntargets=1; - - if(!idata.dstaddr_f){ /* Destination Address defaults to all-nodes (ff02::1) */ - if( inet_pton(AF_INET6, ALL_NODES_MULTICAST_ADDR, &(idata.dstaddr)) <= 0){ - puts("inet_pton(): address not valid"); - exit(EXIT_FAILURE); - } - } - - if(!idata.hsrcaddr_f && !floods_f) /* Source link-layer address is randomized by default */ - randomize_ether_addr(&(idata.hsrcaddr)); - - if(sllopt_f && !sllopta_f){ /* The value of the source link-layer address option */ - linkaddr[0]= idata.hsrcaddr; /* defaults to the source Ethernet address */ - nlinkaddr++; - } - - if(!idata.hdstaddr_f) /* Destination link-layer address defaults to all-nodes */ - if(ether_pton(ETHER_ALLNODES_LINK_ADDR, &(idata.hdstaddr), sizeof(idata.hdstaddr)) == 0){ - puts("ether_pton(): Error converting all-nodes multicast address"); - exit(EXIT_FAILURE); - } - - if(!floods_f) - nsources=1; - - if(!sleep_f) - nsleep=1; - - if( !idata.fragh_f && dstoptuhdr_f){ - puts("Dst. Options Header (Unfragmentable Part) set, but Fragmentation not specified"); - exit(EXIT_FAILURE); - } - - if(idata.verbose_f){ - print_attack_info(&idata); - } - - /* Set initial contents of the attack packet */ - init_packet_data(&idata); - - /* Fire a Neighbor Solicitarion message */ - send_packet(&idata); - - if(idata.verbose_f) - puts("Initial attack packet(s) sent successfully."); - - if(loop_f && idata.verbose_f) - printf("Now sending Neighbor Solicitations every %u second%s...\n", nsleep, \ - ((nsleep>1)?"s":"")); - - while(loop_f){ - sleep(nsleep); - send_packet(&idata); - } - - } - - - exit(EXIT_SUCCESS); -} + /* Read a Neighbor Solicitation message */ + if ((r = pcap_next_ex(idata.pfd, &pkthdr, &pktdata)) == -1) { + printf("pcap_next_ex(): %s", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } + else if (r == 1 && pktdata != NULL) { + /* XXX Code assumes no IPv6 Extension Headers */ + pkt_ether = (struct ether_header *)pktdata; + pkt_ipv6 = (struct ip6_hdr *)((char *)pkt_ether + idata.linkhsize); + pkt_ns = (struct nd_neighbor_solicit *)((char *)pkt_ipv6 + MIN_IPV6_HLEN); + pkt_icmp6 = (struct icmp6_hdr *)pkt_ns; + + /* XXX This should probably be removed when pcap filter problem is solved */ + if (pkt_ipv6->ip6_nxt != IPPROTO_ICMPV6 || pkt_icmp6->icmp6_type != ND_NEIGHBOR_SOLICIT || + pkt_icmp6->icmp6_code != 0) + continue; + + accepted_f = 0; + + if (idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK)) { + if (filters.nblocklinksrc) { + if (match_ether(filters.blocklinksrc, filters.nblocklinksrc, &(pkt_ether->src))) { + if (idata.verbose_f > 1) + print_filter_result(&idata, pktdata, BLOCKED); + + continue; + } + } + + if (filters.nblocklinkdst) { + if (match_ether(filters.blocklinkdst, filters.nblocklinkdst, &(pkt_ether->dst))) { + if (idata.verbose_f > 1) + print_filter_result(&idata, pktdata, BLOCKED); + + continue; + } + } + } + + if (filters.nblocksrc) { + if (match_ipv6(filters.blocksrc, filters.blocksrclen, filters.nblocksrc, + &(pkt_ipv6->ip6_src))) { + if (idata.verbose_f > 1) + print_filter_result(&idata, pktdata, BLOCKED); + + continue; + } + } + + if (filters.nblockdst) { + if (match_ipv6(filters.blockdst, filters.blockdstlen, filters.nblockdst, + &(pkt_ipv6->ip6_dst))) { + if (idata.verbose_f > 1) + print_filter_result(&idata, pktdata, BLOCKED); + + continue; + } + } + + if (filters.nblocktarget) { + if (match_ipv6(filters.blocktarget, filters.blocktargetlen, filters.nblocktarget, + &(pkt_ns->nd_ns_target))) { + if (idata.verbose_f > 1) + print_filter_result(&idata, pktdata, BLOCKED); + + continue; + } + } + + if (idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK)) { + if (filters.nacceptlinksrc) { + if (match_ether(filters.acceptlinksrc, filters.nacceptlinksrc, &(pkt_ether->src))) + accepted_f = 1; + } + + if (filters.nacceptlinkdst && !accepted_f) { + if (match_ether(filters.acceptlinkdst, filters.nacceptlinkdst, &(pkt_ether->dst))) + accepted_f = 1; + } + } + + if (filters.nacceptsrc && !accepted_f) { + if (match_ipv6(filters.acceptsrc, filters.acceptsrclen, filters.nacceptsrc, + &(pkt_ipv6->ip6_src))) + accepted_f = 1; + } + + if (filters.nacceptdst && !accepted_f) { + if (match_ipv6(filters.acceptdst, filters.acceptdstlen, filters.nacceptdst, + &(pkt_ipv6->ip6_dst))) + accepted_f = 1; + } + + if (filters.naccepttarget && !accepted_f) { + if (match_ipv6(filters.accepttarget, filters.accepttargetlen, filters.naccepttarget, + &(pkt_ns->nd_ns_target))) + accepted_f = 1; + } + + if (filters.acceptfilters_f && !accepted_f) { + if (idata.verbose_f > 1) + print_filter_result(&idata, pktdata, BLOCKED); + + continue; + } + + if (idata.verbose_f) + print_filter_result(&idata, pktdata, ACCEPTED); + + /* Send a Neighbor Advertisement */ + if (send_packet_to_ns(&idata, pkthdr, pktdata) == FAILURE) { + puts("Error while sending packet"); + exit(EXIT_FAILURE); + } + } + } + } + + exit(EXIT_SUCCESS); + } + else { + + if (!targetaddr_f) { + puts("Must specify a ND target address with the '-t' option"); + exit(EXIT_FAILURE); + } + + if (load_dst_and_pcap(&idata, LOAD_PCAP_ONLY) == FAILURE) { + puts("Error while learning Source Address and Next Hop"); + exit(EXIT_FAILURE); + } + + release_privileges(); + + if (pcap_compile(idata.pfd, &pcap_filter, PCAP_NOPACKETS_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1) { + printf("pcap_compile(): %s", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } + + if (pcap_setfilter(idata.pfd, &pcap_filter) == -1) { + printf("pcap_setfilter(): %s", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } + + pcap_freecode(&pcap_filter); + + srandom(time(NULL)); + + /* + If the IPv6 Source Address has not been specified, and the "-F" (flood) option has + not been specified, select a random link-local unicast address. + */ + if (!idata.srcaddr_f && !floods_f) { + /* + When randomizing a link-local IPv6 address, select addresses that belong to the + prefix fe80::/64 (that's what a link-local address looks-like in legitimate cases). + The KAME implementation discards addresses in which the second highe-order 16 bits + (srcaddr.s6_addr16[1] in our case) are not zero. + */ + if (inet_pton(AF_INET6, "fe80::", &(idata.srcaddr)) <= 0) { + puts("inet_pton(): Error when converting address"); + exit(EXIT_FAILURE); + } + + randomize_ipv6_addr(&(idata.srcaddr), &(idata.srcaddr), 64); + } + + /* + If the flood option ("-F") has been specified, but no prefix has been specified, + select the random Source Addresses from the link-local unicast prefix (fe80::/64). + */ + if (floods_f && !idata.srcprefix_f) { + if (inet_pton(AF_INET6, "fe80::", &(idata.srcaddr)) <= 0) { + puts("inet_pton(): Error when converting address"); + exit(EXIT_FAILURE); + } + + randomize_ipv6_addr(&(idata.srcaddr), &(idata.srcaddr), 64); + idata.srcpreflen = 64; + } + + /* + If the flood target option ("-T") was specified, but no prefix was specified, + select the random Target Addresses from the link-local unicast prefix (fe80::/64). + */ + if (floodt_f && !targetprefix_f) { + if (inet_pton(AF_INET6, "fe80::", &(targetaddr)) <= 0) { + puts("inet_pton(): Error when converting address"); + exit(EXIT_FAILURE); + } + + randomize_ipv6_addr(&(targetaddr), &(targetaddr), 64); + targetpreflen = 64; + } + + if (!floodt_f) + ntargets = 1; + + if (!idata.dstaddr_f) { /* Destination Address defaults to all-nodes (ff02::1) */ + if (inet_pton(AF_INET6, ALL_NODES_MULTICAST_ADDR, &(idata.dstaddr)) <= 0) { + puts("inet_pton(): address not valid"); + exit(EXIT_FAILURE); + } + } + + if (!idata.hsrcaddr_f && !floods_f) /* Source link-layer address is randomized by default */ + randomize_ether_addr(&(idata.hsrcaddr)); + + if (sllopt_f && !sllopta_f) { /* The value of the source link-layer address option */ + linkaddr[0] = idata.hsrcaddr; /* defaults to the source Ethernet address */ + nlinkaddr++; + } + + if (!idata.hdstaddr_f) /* Destination link-layer address defaults to all-nodes */ + if (ether_pton(ETHER_ALLNODES_LINK_ADDR, &(idata.hdstaddr), sizeof(idata.hdstaddr)) == 0) { + puts("ether_pton(): Error converting all-nodes multicast address"); + exit(EXIT_FAILURE); + } + + if (!floods_f) + nsources = 1; + + if (!sleep_f) + nsleep = 1; + + if (!idata.fragh_f && dstoptuhdr_f) { + puts("Dst. Options Header (Unfragmentable Part) set, but Fragmentation not specified"); + exit(EXIT_FAILURE); + } + + if (idata.verbose_f) { + print_attack_info(&idata); + } + + /* Set initial contents of the attack packet */ + init_packet_data(&idata); + + /* Fire a Neighbor Solicitarion message */ + send_packet(&idata); + + if (idata.verbose_f) + puts("Initial attack packet(s) sent successfully."); + + if (loop_f && idata.verbose_f) + printf("Now sending Neighbor Solicitations every %u second%s...\n", nsleep, ((nsleep > 1) ? "s" : "")); + + while (loop_f) { + sleep(nsleep); + send_packet(&idata); + } + } + exit(EXIT_SUCCESS); +} /* * Function: init_packet_data() @@ -1091,147 +1070,145 @@ int main(int argc, char **argv){ * Initialize the contents of the attack packet (Ethernet header, IPv6 Header, and ICMPv6 header) * that are expected to remain constant for the specified attack. */ -void init_packet_data(struct iface_data *idata){ - struct dlt_null *dlt_null; - ethernet= (struct ether_header *) buffer; - dlt_null= (struct dlt_null *) buffer; - v6buffer = buffer + idata->linkhsize; - ipv6 = (struct ip6_hdr *) v6buffer; - - if(idata->type == DLT_EN10MB){ - ethernet->ether_type = htons(ETHERTYPE_IPV6); - - if(!(idata->flags & IFACE_LOOPBACK)){ - ethernet->src = idata->hsrcaddr; - ethernet->dst = idata->hdstaddr; - } - } - else if(idata->type == DLT_NULL){ - dlt_null->family= PF_INET6; - } -#if defined (__OpenBSD__) - else if(idata->type == DLT_LOOP){ - dlt_null->family= htonl(PF_INET6); - } +void init_packet_data(struct iface_data *idata) { + struct dlt_null *dlt_null; + ethernet = (struct ether_header *)buffer; + dlt_null = (struct dlt_null *)buffer; + v6buffer = buffer + idata->linkhsize; + ipv6 = (struct ip6_hdr *)v6buffer; + + if (idata->type == DLT_EN10MB) { + ethernet->ether_type = htons(ETHERTYPE_IPV6); + + if (!(idata->flags & IFACE_LOOPBACK)) { + ethernet->src = idata->hsrcaddr; + ethernet->dst = idata->hdstaddr; + } + } + else if (idata->type == DLT_NULL) { + dlt_null->family = PF_INET6; + } +#if defined(__OpenBSD__) + else if (idata->type == DLT_LOOP) { + dlt_null->family = htonl(PF_INET6); + } #endif - ipv6->ip6_flow=0; - ipv6->ip6_vfc= 0x60; - ipv6->ip6_hlim= hoplimit; - ipv6->ip6_src= idata->srcaddr; - ipv6->ip6_dst= idata->dstaddr; - prev_nh = (unsigned char *) &(ipv6->ip6_nxt); - - ptr = (unsigned char *) v6buffer + MIN_IPV6_HLEN; - - if(hbhopthdr_f){ - hbhopthdrs=0; - - while(hbhopthdrs < nhbhopthdr){ - if((ptr+ hbhopthdrlen[hbhopthdrs]) > (v6buffer+ idata->mtu)){ - puts("Packet too large while processing HBH Opt. Header"); - exit(EXIT_FAILURE); - } - - *prev_nh = IPPROTO_HOPOPTS; - prev_nh = ptr; - memcpy(ptr, hbhopthdr[hbhopthdrs], hbhopthdrlen[hbhopthdrs]); - ptr = ptr + hbhopthdrlen[hbhopthdrs]; - hbhopthdrs++; - } - } - - if(dstoptuhdr_f){ - dstoptuhdrs=0; - - while(dstoptuhdrs < ndstoptuhdr){ - if((ptr+ dstoptuhdrlen[dstoptuhdrs]) > (v6buffer+ idata->mtu)){ - puts("Packet too large while processing Dest. Opt. Header (Unfrag. Part)"); - exit(EXIT_FAILURE); - } - - *prev_nh = IPPROTO_DSTOPTS; - prev_nh = ptr; - memcpy(ptr, dstoptuhdr[dstoptuhdrs], dstoptuhdrlen[dstoptuhdrs]); - ptr = ptr + dstoptuhdrlen[dstoptuhdrs]; - dstoptuhdrs++; - } - } - - /* Everything that follows is the Fragmentable Part of the packet */ - fragpart = ptr; - - if(idata->fragh_f){ - /* Check that we are able to send the Unfragmentable Part, together with a - Fragment Header and a chunk data over our link layer - */ - if( (fragpart+sizeof(fraghdr)+nfrags) > (v6buffer+idata->mtu)){ - printf("Unfragmentable part too large for current MTU (%u bytes)\n", idata->mtu); - exit(EXIT_FAILURE); - } - - /* We prepare a separete Fragment Header, but we do not include it in the packet to be sent. - This Fragment Header will be used (an assembled with the rest of the packet by the - send_packet() function. - */ - memset(&fraghdr, 0, FRAG_HDR_SIZE); - *prev_nh = IPPROTO_FRAGMENT; - prev_nh = (unsigned char *) &fraghdr; - } - - if(dstopthdr_f){ - dstopthdrs=0; - - while(dstopthdrs < ndstopthdr){ - if((ptr+ dstopthdrlen[dstopthdrs]) > (v6buffer+idata->max_packet_size)){ - puts("Packet too large while processing Dest. Opt. Header (U. part) (should be using the Frag. option?)"); - exit(EXIT_FAILURE); - } - - *prev_nh = IPPROTO_DSTOPTS; - prev_nh = ptr; - memcpy(ptr, dstopthdr[dstopthdrs], dstopthdrlen[dstopthdrs]); - ptr = ptr + dstopthdrlen[dstopthdrs]; - dstopthdrs++; - } - } - - *prev_nh = IPPROTO_ICMPV6; - - if( (ptr+sizeof(struct nd_neighbor_solicit)) > (v6buffer+idata->max_packet_size)){ - puts("Packet too large while inserting Neighbor Solicitation header (should be using Frag. option?)"); - exit(EXIT_FAILURE); - } - - ns= (struct nd_neighbor_solicit *) (ptr); - - ns->nd_ns_type = ND_NEIGHBOR_SOLICIT; - ns->nd_ns_code = 0; - ns->nd_ns_reserved = 0; - ns->nd_ns_target = targetaddr; - - ptr += sizeof(struct nd_neighbor_solicit); - sllaopt = (struct nd_opt_slla *) ptr; - - /* If a single source link-layer address is specified, it is included in all packets */ - if(sllopt_f && nlinkaddr==1){ - if( (ptr+sizeof(struct nd_opt_slla)) <= (v6buffer+idata->max_packet_size)){ - sllaopt->type= ND_OPT_SOURCE_LINKADDR; - sllaopt->length= SLLA_OPT_LEN; - memcpy(sllaopt->address, linkaddr[0].a, ETH_ALEN); - ptr += sizeof(struct nd_opt_slla); - } - else{ - puts("Packet too large while processing source link-layer address opt. (should be using Frag. option?)"); - exit(EXIT_FAILURE); - } - } - - startofprefixes = ptr; -} + ipv6->ip6_flow = 0; + ipv6->ip6_vfc = 0x60; + ipv6->ip6_hlim = hoplimit; + ipv6->ip6_src = idata->srcaddr; + ipv6->ip6_dst = idata->dstaddr; + prev_nh = (unsigned char *)&(ipv6->ip6_nxt); + + ptr = (unsigned char *)v6buffer + MIN_IPV6_HLEN; + + if (hbhopthdr_f) { + hbhopthdrs = 0; + + while (hbhopthdrs < nhbhopthdr) { + if ((ptr + hbhopthdrlen[hbhopthdrs]) > (v6buffer + idata->mtu)) { + puts("Packet too large while processing HBH Opt. Header"); + exit(EXIT_FAILURE); + } + + *prev_nh = IPPROTO_HOPOPTS; + prev_nh = ptr; + memcpy(ptr, hbhopthdr[hbhopthdrs], hbhopthdrlen[hbhopthdrs]); + ptr = ptr + hbhopthdrlen[hbhopthdrs]; + hbhopthdrs++; + } + } + + if (dstoptuhdr_f) { + dstoptuhdrs = 0; + + while (dstoptuhdrs < ndstoptuhdr) { + if ((ptr + dstoptuhdrlen[dstoptuhdrs]) > (v6buffer + idata->mtu)) { + puts("Packet too large while processing Dest. Opt. Header (Unfrag. Part)"); + exit(EXIT_FAILURE); + } + + *prev_nh = IPPROTO_DSTOPTS; + prev_nh = ptr; + memcpy(ptr, dstoptuhdr[dstoptuhdrs], dstoptuhdrlen[dstoptuhdrs]); + ptr = ptr + dstoptuhdrlen[dstoptuhdrs]; + dstoptuhdrs++; + } + } + + /* Everything that follows is the Fragmentable Part of the packet */ + fragpart = ptr; + + if (idata->fragh_f) { + /* Check that we are able to send the Unfragmentable Part, together with a + Fragment Header and a chunk data over our link layer + */ + if ((fragpart + sizeof(fraghdr) + nfrags) > (v6buffer + idata->mtu)) { + printf("Unfragmentable part too large for current MTU (%u bytes)\n", idata->mtu); + exit(EXIT_FAILURE); + } + + /* We prepare a separete Fragment Header, but we do not include it in the packet to be sent. + This Fragment Header will be used (an assembled with the rest of the packet by the + send_packet() function. + */ + memset(&fraghdr, 0, FRAG_HDR_SIZE); + *prev_nh = IPPROTO_FRAGMENT; + prev_nh = (unsigned char *)&fraghdr; + } + if (dstopthdr_f) { + dstopthdrs = 0; + + while (dstopthdrs < ndstopthdr) { + if ((ptr + dstopthdrlen[dstopthdrs]) > (v6buffer + idata->max_packet_size)) { + puts("Packet too large while processing Dest. Opt. Header (U. part) (should be using the Frag. " + "option?)"); + exit(EXIT_FAILURE); + } + + *prev_nh = IPPROTO_DSTOPTS; + prev_nh = ptr; + memcpy(ptr, dstopthdr[dstopthdrs], dstopthdrlen[dstopthdrs]); + ptr = ptr + dstopthdrlen[dstopthdrs]; + dstopthdrs++; + } + } + + *prev_nh = IPPROTO_ICMPV6; + if ((ptr + sizeof(struct nd_neighbor_solicit)) > (v6buffer + idata->max_packet_size)) { + puts("Packet too large while inserting Neighbor Solicitation header (should be using Frag. option?)"); + exit(EXIT_FAILURE); + } + ns = (struct nd_neighbor_solicit *)(ptr); + + ns->nd_ns_type = ND_NEIGHBOR_SOLICIT; + ns->nd_ns_code = 0; + ns->nd_ns_reserved = 0; + ns->nd_ns_target = targetaddr; + + ptr += sizeof(struct nd_neighbor_solicit); + sllaopt = (struct nd_opt_slla *)ptr; + + /* If a single source link-layer address is specified, it is included in all packets */ + if (sllopt_f && nlinkaddr == 1) { + if ((ptr + sizeof(struct nd_opt_slla)) <= (v6buffer + idata->max_packet_size)) { + sllaopt->type = ND_OPT_SOURCE_LINKADDR; + sllaopt->length = SLLA_OPT_LEN; + memcpy(sllaopt->address, linkaddr[0].a, ETH_ALEN); + ptr += sizeof(struct nd_opt_slla); + } + else { + puts("Packet too large while processing source link-layer address opt. (should be using Frag. option?)"); + exit(EXIT_FAILURE); + } + } + + startofprefixes = ptr; +} /* * Function: send_packet() @@ -1239,509 +1216,494 @@ void init_packet_data(struct iface_data *idata){ * Initialize the remaining fields of the Neighbor Solicitation message, and * send the attack packet(s). */ -void send_packet(struct iface_data *idata){ - sources=0; - - do{ - if(floods_f){ - /* - Randomize the IPv6 Source address based on the specified prefix and prefix length - (defaults to fe80::/64). - */ - randomize_ipv6_addr(&(ipv6->ip6_src), &(idata->srcaddr), idata->srcpreflen); - - if(!idata->hsrcaddr_f){ - randomize_ether_addr(&(ethernet->src)); - - /* - If the source-link layer address must be included, but no value was - specified we set it to the randomized Ethernet Source Address - */ - if(sllopt_f && !sllopta_f){ - memcpy(sllaopt->address, ethernet->src.a, ETH_ALEN); - } - } - } - - targets=0; - - do{ - if(floodt_f){ - /* - Randomizing the ND Target Address based on the prefix specified by "targetaddr" - and targetpreflen. - */ - randomize_ipv6_addr(&(ns->nd_ns_target), &(targetaddr), targetpreflen); - } - - if(nlinkaddr==1) /* If a single source link-layer address must be included, it is included */ - linkaddrs=1; /* by init_packet_data() (rather than by send_packet() */ - else - linkaddrs=0; - - do{ - newdata_f=0; - ptr = startofprefixes; - - while(linkaddrsmax_packet_size){ - sllaopt = (struct nd_opt_slla *) ptr; - sllaopt->type= ND_OPT_SOURCE_LINKADDR; - sllaopt->length= SLLA_OPT_LEN; - memcpy(sllaopt->address, linkaddr[linkaddrs].a, ETH_ALEN); - ptr += sizeof(struct nd_opt_slla); - linkaddrs++; - newdata_f=1; - } - - ns->nd_ns_cksum = 0; - ns->nd_ns_cksum = in_chksum(v6buffer, ns, ptr-((unsigned char *)ns), IPPROTO_ICMPV6); - - if(!idata->fragh_f){ - ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); - - if((nw=pcap_inject(idata->pfd, buffer, ptr - buffer)) == -1){ - printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); - exit(EXIT_FAILURE); - } - - if(nw != (ptr-buffer)){ - printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, \ - (LUI) (ptr-buffer)); - exit(EXIT_FAILURE); - } - } - else{ - ptrend= ptr; - ptr= fragpart; - fptr = fragbuffer; - fipv6 = (struct ip6_hdr *) (fragbuffer + ETHER_HDR_LEN); - fptrend = fptr + ETHER_HDR_LEN+MIN_IPV6_HLEN+MAX_IPV6_PAYLOAD; - memcpy(fptr, buffer, fragpart-buffer); - fptr = fptr + (fragpart-buffer); - - if( (fptr+FRAG_HDR_SIZE)> fptrend){ - puts("Unfragmentable Part is Too Large"); - exit(EXIT_FAILURE); - } - - memcpy(fptr, (char *) &fraghdr, FRAG_HDR_SIZE); - fh= (struct ip6_frag *) fptr; - fh->ip6f_ident=random(); - startoffragment = fptr + FRAG_HDR_SIZE; - - /* - * Check that the selected fragment size is not larger than the largest - * fragment size that can be sent - */ - if(nfrags > (fptrend - fptr)) - nfrags= (fptrend-fptr); - - m=IP6F_MORE_FRAG; - - while((ptr< ptrend) && m==IP6F_MORE_FRAG){ - fptr= startoffragment; - - if( (ptrend-ptr) <= nfrags){ - fragsize= ptrend-ptr; - m=0; - } - else{ - fragsize = (nfrags + 7) & ntohs(IP6F_OFF_MASK); - } - - memcpy(fptr, ptr, fragsize); - fh->ip6f_offlg = (htons(ptr-fragpart) & IP6F_OFF_MASK) | m; - ptr+=fragsize; - fptr+=fragsize; - - fipv6->ip6_plen = htons((fptr - fragbuffer) - MIN_IPV6_HLEN - ETHER_HDR_LEN); - - if((nw=pcap_inject(idata->pfd, fragbuffer, fptr - fragbuffer)) == -1){ - printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); - exit(EXIT_FAILURE); - } - - if(nw != (fptr- fragbuffer)){ - printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, \ - (LUI) (ptr-buffer)); - exit(EXIT_FAILURE); - } - } - } - - }while(linkaddrsip6_src), &(idata->srcaddr), idata->srcpreflen); + + if (!idata->hsrcaddr_f) { + randomize_ether_addr(&(ethernet->src)); + + /* + If the source-link layer address must be included, but no value was + specified we set it to the randomized Ethernet Source Address + */ + if (sllopt_f && !sllopta_f) { + memcpy(sllaopt->address, ethernet->src.a, ETH_ALEN); + } + } + } + + targets = 0; + + do { + if (floodt_f) { + /* + Randomizing the ND Target Address based on the prefix specified by "targetaddr" + and targetpreflen. + */ + randomize_ipv6_addr(&(ns->nd_ns_target), &(targetaddr), targetpreflen); + } + + if (nlinkaddr == 1) /* If a single source link-layer address must be included, it is included */ + linkaddrs = 1; /* by init_packet_data() (rather than by send_packet() */ + else + linkaddrs = 0; + + do { + newdata_f = 0; + ptr = startofprefixes; + + while (linkaddrs < nlinkaddr && + (ptr + sizeof(struct nd_opt_slla) - v6buffer) <= idata->max_packet_size) { + sllaopt = (struct nd_opt_slla *)ptr; + sllaopt->type = ND_OPT_SOURCE_LINKADDR; + sllaopt->length = SLLA_OPT_LEN; + memcpy(sllaopt->address, linkaddr[linkaddrs].a, ETH_ALEN); + ptr += sizeof(struct nd_opt_slla); + linkaddrs++; + newdata_f = 1; + } + + ns->nd_ns_cksum = 0; + ns->nd_ns_cksum = in_chksum(v6buffer, ns, ptr - ((unsigned char *)ns), IPPROTO_ICMPV6); + + if (!idata->fragh_f) { + ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); + + if ((nw = pcap_inject(idata->pfd, buffer, ptr - buffer)) == -1) { + printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); + exit(EXIT_FAILURE); + } + + if (nw != (ptr - buffer)) { + printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, (LUI)(ptr - buffer)); + exit(EXIT_FAILURE); + } + } + else { + ptrend = ptr; + ptr = fragpart; + fptr = fragbuffer; + fipv6 = (struct ip6_hdr *)(fragbuffer + ETHER_HDR_LEN); + fptrend = fptr + ETHER_HDR_LEN + MIN_IPV6_HLEN + MAX_IPV6_PAYLOAD; + memcpy(fptr, buffer, fragpart - buffer); + fptr = fptr + (fragpart - buffer); + + if ((fptr + FRAG_HDR_SIZE) > fptrend) { + puts("Unfragmentable Part is Too Large"); + exit(EXIT_FAILURE); + } + + memcpy(fptr, (char *)&fraghdr, FRAG_HDR_SIZE); + fh = (struct ip6_frag *)fptr; + fh->ip6f_ident = random(); + startoffragment = fptr + FRAG_HDR_SIZE; + + /* + * Check that the selected fragment size is not larger than the largest + * fragment size that can be sent + */ + if (nfrags > (fptrend - fptr)) + nfrags = (fptrend - fptr); + + m = IP6F_MORE_FRAG; + + while ((ptr < ptrend) && m == IP6F_MORE_FRAG) { + fptr = startoffragment; + + if ((ptrend - ptr) <= nfrags) { + fragsize = ptrend - ptr; + m = 0; + } + else { + fragsize = (nfrags + 7) & ntohs(IP6F_OFF_MASK); + } + + memcpy(fptr, ptr, fragsize); + fh->ip6f_offlg = (htons(ptr - fragpart) & IP6F_OFF_MASK) | m; + ptr += fragsize; + fptr += fragsize; + + fipv6->ip6_plen = htons((fptr - fragbuffer) - MIN_IPV6_HLEN - ETHER_HDR_LEN); + + if ((nw = pcap_inject(idata->pfd, fragbuffer, fptr - fragbuffer)) == -1) { + printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); + exit(EXIT_FAILURE); + } + + if (nw != (fptr - fragbuffer)) { + printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, + (LUI)(ptr - buffer)); + exit(EXIT_FAILURE); + } + } + } + + } while (linkaddrs < nlinkaddr && newdata_f); + + targets++; + + } while (targets < ntargets); + + sources++; + + } while (sources < nsources); } - - - - /* * Function: send_packet_to_ns() * * Initialize the remaining fields of the Neighbor Solicitation Message, and * send the attack packet(s). */ -int send_packet_to_ns(struct iface_data *idata, struct pcap_pkthdr *pkthdr, const u_char *pktdata){ - if(pktdata == NULL){ - sources=0; - } - else{ /* Sending a response to a Neighbor Solicitation message */ - pkt_ether = (struct ether_header *) pktdata; - pkt_ipv6 = (struct ip6_hdr *)((char *) pkt_ether + idata->linkhsize); - pkt_ns = (struct nd_neighbor_solicit *) ((char *) pkt_ipv6 + MIN_IPV6_HLEN); - - /* If the IPv6 Source Address of the incoming Neighbor Solicitation is the unspecified - address (::), the Neighbor Advertisement must be directed to the IPv6 all-nodes - multicast address (and the Ethernet Destination address should be 33:33:33:00:00:01). - Otherwise, the Neighbor Advertisement is sent to the IPv6 Source Address (and - Ethernet Source Address) of the incoming Neighbor Solicitation message - */ - pkt_ipv6addr = &(pkt_ipv6->ip6_src); - - - if(IN6_IS_ADDR_UNSPECIFIED(pkt_ipv6addr)){ - if ( inet_pton(AF_INET6, ALL_NODES_MULTICAST_ADDR, &(ipv6->ip6_dst)) <= 0){ - puts("inetr_pton(): Error converting all-nodes multicast address"); - return(FAILURE); - } - - if(ether_pton(ETHER_ALLNODES_LINK_ADDR, &(ethernet->dst), ETHER_ADDR_LEN) == 0){ - puts("ether_pton(): Error converting all-nodes link-local address"); - return(FAILURE); - } - } - else{ - ipv6->ip6_dst = pkt_ipv6->ip6_src; - ethernet->dst = pkt_ether->src; - } - - pkt_ipv6addr = &(pkt_ipv6->ip6_dst); - - /* - If the Neighbor Solicitation message was directed to a unicast address (unlikely), the - IPv6 Source Address and the Ethernet Source Address of the Neighbor Advertisement are set - to the IPv6 Destination Address and the Ethernet Destination Address of the incoming - Neighbor Solicitation, respectively. Otherwise, the IPv6 Source Address is set to the - ND Target Address (unless a specific IPv6 Source Address was specified with the "-s" - option), and the Ethernet is set to that specified by the "-S" option (or randomized). - */ - if(IN6_IS_ADDR_MULTICAST(pkt_ipv6addr)){ - if( !idata->srcaddr_f && IN6_IS_ADDR_LINKLOCAL(&(pkt_ns->nd_ns_target)) ) - ipv6->ip6_src = pkt_ns->nd_ns_target; - else - ipv6->ip6_src = idata->srcaddr; - - ethernet->src = idata->hsrcaddr; - sources=0; - multicastdst_f=1; - } - else{ - ipv6->ip6_src = pkt_ipv6->ip6_dst; - ethernet->src = pkt_ether->dst; - sources=nsources; - multicastdst_f=0; - } - - ns->nd_ns_target= pkt_ns->nd_ns_target; - } - - - do{ - if(floods_f && (pktdata==NULL || (pktdata != NULL && multicastdst_f))){ - /* - Randomizing the IPv6 Source address based on the prefix specified by - "srcaddr" and prefix length. - */ - randomize_ipv6_addr(&(ipv6->ip6_src), &(idata->srcaddr), idata->srcpreflen); - - if(!idata->hsrcaddr_f){ - randomize_ether_addr(&(ethernet->src)); - } - - if(sllopt_f && !sllopta_f){ - memcpy(sllaopt->address, ethernet->src.a, ETH_ALEN); - } - } - - targets=0; - - do{ - /* - * If a single target link-layer address option is to be included, it is included - * by init_packet_data() - */ - if(nlinkaddr==1) - linkaddrs=1; - else - linkaddrs=0; - - do{ - newdata_f=0; - ptr=startofprefixes; - - while(linkaddrsmax_packet_size){ - sllaopt = (struct nd_opt_slla *) ptr; - sllaopt->type= ND_OPT_SOURCE_LINKADDR; - sllaopt->length= SLLA_OPT_LEN; - memcpy(sllaopt->address, linkaddr[linkaddrs].a, ETH_ALEN); - ptr += sizeof(struct nd_opt_slla); - linkaddrs++; - newdata_f=1; - } - - ns->nd_ns_cksum = 0; - ns->nd_ns_cksum = in_chksum(v6buffer, ns, ptr-((unsigned char *)ns), IPPROTO_ICMPV6); - - - if(!idata->fragh_f){ - ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); - - if((nw=pcap_inject(idata->pfd, buffer, ptr - buffer)) == -1){ - printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); - return(FAILURE); - } - - if(nw != (ptr-buffer)){ - printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, \ - (LUI) (ptr-buffer)); - return(FAILURE); - } - } - else{ - ptrend= ptr; - ptr= fragpart; - fptr = fragbuffer; - fipv6 = (struct ip6_hdr *) (fragbuffer + ETHER_HDR_LEN); - fptrend = fptr + ETHER_HDR_LEN+MIN_IPV6_HLEN+MAX_IPV6_PAYLOAD; - memcpy(fptr, buffer, fragpart-buffer); - fptr = fptr + (fragpart-buffer); - - if( (fptr+FRAG_HDR_SIZE)> fptrend){ - puts("Unfragmentable Part is Too Large"); - return(FAILURE); - } - - memcpy(fptr, (char *) &fraghdr, FRAG_HDR_SIZE); - fh= (struct ip6_frag *) fptr; - fh->ip6f_ident=random(); - startoffragment = fptr + FRAG_HDR_SIZE; - - /* - * Check that the selected fragment size is not larger than the largest - * fragment size that can be sent - */ - if(nfrags > (fptrend - fptr)) - nfrags= (fptrend-fptr); - - m=IP6F_MORE_FRAG; - - while((ptr< ptrend) && m==IP6F_MORE_FRAG){ - fptr= startoffragment; - - if( (ptrend-ptr) <= nfrags){ - fragsize= ptrend-ptr; - m=0; - } - else{ - fragsize = (nfrags + 7) & ntohs(IP6F_OFF_MASK); - } - - memcpy(fptr, ptr, fragsize); - fh->ip6f_offlg = (htons(ptr-fragpart) & IP6F_OFF_MASK) | m; - ptr+=fragsize; - fptr+=fragsize; - - fipv6->ip6_plen = htons((fptr - fragbuffer) - MIN_IPV6_HLEN - ETHER_HDR_LEN); - - if((nw=pcap_inject(idata->pfd, fragbuffer, fptr - fragbuffer)) == -1){ - printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); - return(FAILURE); - } - - if(nw != (fptr- fragbuffer)){ - printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n"\ - , nw, (LUI) (ptr-buffer)); - return(FAILURE); - } - } - } - }while(linkaddrslinkhsize); + pkt_ns = (struct nd_neighbor_solicit *)((char *)pkt_ipv6 + MIN_IPV6_HLEN); + + /* If the IPv6 Source Address of the incoming Neighbor Solicitation is the unspecified + address (::), the Neighbor Advertisement must be directed to the IPv6 all-nodes + multicast address (and the Ethernet Destination address should be 33:33:33:00:00:01). + Otherwise, the Neighbor Advertisement is sent to the IPv6 Source Address (and + Ethernet Source Address) of the incoming Neighbor Solicitation message + */ + pkt_ipv6addr = &(pkt_ipv6->ip6_src); + + if (IN6_IS_ADDR_UNSPECIFIED(pkt_ipv6addr)) { + if (inet_pton(AF_INET6, ALL_NODES_MULTICAST_ADDR, &(ipv6->ip6_dst)) <= 0) { + puts("inetr_pton(): Error converting all-nodes multicast address"); + return (FAILURE); + } + + if (ether_pton(ETHER_ALLNODES_LINK_ADDR, &(ethernet->dst), ETHER_ADDR_LEN) == 0) { + puts("ether_pton(): Error converting all-nodes link-local address"); + return (FAILURE); + } + } + else { + ipv6->ip6_dst = pkt_ipv6->ip6_src; + ethernet->dst = pkt_ether->src; + } + + pkt_ipv6addr = &(pkt_ipv6->ip6_dst); + + /* + If the Neighbor Solicitation message was directed to a unicast address (unlikely), the + IPv6 Source Address and the Ethernet Source Address of the Neighbor Advertisement are set + to the IPv6 Destination Address and the Ethernet Destination Address of the incoming + Neighbor Solicitation, respectively. Otherwise, the IPv6 Source Address is set to the + ND Target Address (unless a specific IPv6 Source Address was specified with the "-s" + option), and the Ethernet is set to that specified by the "-S" option (or randomized). + */ + if (IN6_IS_ADDR_MULTICAST(pkt_ipv6addr)) { + if (!idata->srcaddr_f && IN6_IS_ADDR_LINKLOCAL(&(pkt_ns->nd_ns_target))) + ipv6->ip6_src = pkt_ns->nd_ns_target; + else + ipv6->ip6_src = idata->srcaddr; + + ethernet->src = idata->hsrcaddr; + sources = 0; + multicastdst_f = 1; + } + else { + ipv6->ip6_src = pkt_ipv6->ip6_dst; + ethernet->src = pkt_ether->dst; + sources = nsources; + multicastdst_f = 0; + } + + ns->nd_ns_target = pkt_ns->nd_ns_target; + } + do { + if (floods_f && (pktdata == NULL || (pktdata != NULL && multicastdst_f))) { + /* + Randomizing the IPv6 Source address based on the prefix specified by + "srcaddr" and prefix length. + */ + randomize_ipv6_addr(&(ipv6->ip6_src), &(idata->srcaddr), idata->srcpreflen); + + if (!idata->hsrcaddr_f) { + randomize_ether_addr(&(ethernet->src)); + } + + if (sllopt_f && !sllopta_f) { + memcpy(sllaopt->address, ethernet->src.a, ETH_ALEN); + } + } + + targets = 0; + + do { + /* + * If a single target link-layer address option is to be included, it is included + * by init_packet_data() + */ + if (nlinkaddr == 1) + linkaddrs = 1; + else + linkaddrs = 0; + + do { + newdata_f = 0; + ptr = startofprefixes; + + while (linkaddrs < nlinkaddr && + ((ptr + sizeof(struct nd_opt_slla)) - v6buffer) <= idata->max_packet_size) { + sllaopt = (struct nd_opt_slla *)ptr; + sllaopt->type = ND_OPT_SOURCE_LINKADDR; + sllaopt->length = SLLA_OPT_LEN; + memcpy(sllaopt->address, linkaddr[linkaddrs].a, ETH_ALEN); + ptr += sizeof(struct nd_opt_slla); + linkaddrs++; + newdata_f = 1; + } + + ns->nd_ns_cksum = 0; + ns->nd_ns_cksum = in_chksum(v6buffer, ns, ptr - ((unsigned char *)ns), IPPROTO_ICMPV6); + + if (!idata->fragh_f) { + ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); + + if ((nw = pcap_inject(idata->pfd, buffer, ptr - buffer)) == -1) { + printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); + return (FAILURE); + } + + if (nw != (ptr - buffer)) { + printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, (LUI)(ptr - buffer)); + return (FAILURE); + } + } + else { + ptrend = ptr; + ptr = fragpart; + fptr = fragbuffer; + fipv6 = (struct ip6_hdr *)(fragbuffer + ETHER_HDR_LEN); + fptrend = fptr + ETHER_HDR_LEN + MIN_IPV6_HLEN + MAX_IPV6_PAYLOAD; + memcpy(fptr, buffer, fragpart - buffer); + fptr = fptr + (fragpart - buffer); + + if ((fptr + FRAG_HDR_SIZE) > fptrend) { + puts("Unfragmentable Part is Too Large"); + return (FAILURE); + } + + memcpy(fptr, (char *)&fraghdr, FRAG_HDR_SIZE); + fh = (struct ip6_frag *)fptr; + fh->ip6f_ident = random(); + startoffragment = fptr + FRAG_HDR_SIZE; + + /* + * Check that the selected fragment size is not larger than the largest + * fragment size that can be sent + */ + if (nfrags > (fptrend - fptr)) + nfrags = (fptrend - fptr); + + m = IP6F_MORE_FRAG; + + while ((ptr < ptrend) && m == IP6F_MORE_FRAG) { + fptr = startoffragment; + + if ((ptrend - ptr) <= nfrags) { + fragsize = ptrend - ptr; + m = 0; + } + else { + fragsize = (nfrags + 7) & ntohs(IP6F_OFF_MASK); + } + + memcpy(fptr, ptr, fragsize); + fh->ip6f_offlg = (htons(ptr - fragpart) & IP6F_OFF_MASK) | m; + ptr += fragsize; + fptr += fragsize; + + fipv6->ip6_plen = htons((fptr - fragbuffer) - MIN_IPV6_HLEN - ETHER_HDR_LEN); + + if ((nw = pcap_inject(idata->pfd, fragbuffer, fptr - fragbuffer)) == -1) { + printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); + return (FAILURE); + } + + if (nw != (fptr - fragbuffer)) { + printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, + (LUI)(ptr - buffer)); + return (FAILURE); + } + } + } + } while (linkaddrs < nlinkaddr && newdata_f); + + targets++; + + } while (targets < ntargets); + + sources++; + } while (sources < nsources); + + return (SUCCESS); +} /* * Function: usage() * * Print the syntax of the ns6 tool */ -void usage(void){ - puts("usage: ns6 -i INTERFACE [-s SRC_ADDR[/LEN]] [-d DST_ADDR] [-y FRAG_SIZE] " - "[-u DST_OPT_HDR_SIZE] [-U DST_OPT_U_HDR_SIZE] [-H HBH_OPT_HDR_SIZE] " - "[-S LINK_SRC_ADDR] [-D LINK-DST-ADDR] [-E LINK_ADDR] [-e] [-t TARGET_ADDR[/LEN]] " - "[-F N_SOURCES] [-T N_TARGETS] [-z SECONDS] [-l] [-v] [-h]"); +void usage(void) { + puts("usage: ns6 -i INTERFACE [-s SRC_ADDR[/LEN]] [-d DST_ADDR] [-y FRAG_SIZE] " + "[-u DST_OPT_HDR_SIZE] [-U DST_OPT_U_HDR_SIZE] [-H HBH_OPT_HDR_SIZE] " + "[-S LINK_SRC_ADDR] [-D LINK-DST-ADDR] [-E LINK_ADDR] [-e] [-t TARGET_ADDR[/LEN]] " + "[-F N_SOURCES] [-T N_TARGETS] [-z SECONDS] [-l] [-v] [-h]"); } - /* * Function: print_help() * * Print help information for the ns6 tool */ -void print_help(void){ - puts(SI6_TOOLKIT); - puts("ns6: Security assessment tool for attack vectors based on NS messages\n"); - usage(); - - puts("\nOPTIONS:\n" - " --interface, -i Network interface\n" - " --src-addr, -s IPv6 Source Address\n" - " --dst-addr, -d IPv6 Destination Address\n" - " --frag-hdr. -y Fragment Header\n" - " --dst-opt-hdr, -u Destination Options Header (Fragmentable Part)\n" - " --dst-opt-u-hdr, -U Destination Options Header (Unfragmentable Part)\n" - " --hbh-opt-hdr, -H Hop by Hop Options Header\n" - " --link-src-addr, -S Link-layer Destination Address\n" - " --link-dst-addr, -D Link-layer Source Address\n" - " --target-address, -t ND Target Address\n" - " --source-lla-opt, -E Source link-layer address option\n" - " --add-slla-opt, -e Add Source link-layer address option\n" - " --flood-sources, -F Number of Source Addresses to forge randomly\n" - " --flood-targets, -T Flood with NA's for multiple Target Addresses\n" - " --loop, -l Send Neighbor Solicitations periodically\n" - " --sleep, -z Pause between peiodic Neighbor Solicitations\n" - " --help, -h Print help for the ns6 tool\n" - " --verbose, -v Be verbose\n" - "\n" - "Programmed by Fernando Gont for SI6 Networks \n" - "Please send any bug reports to " - ); +void print_help(void) { + puts(SI6_TOOLKIT); + puts("ns6: Security assessment tool for attack vectors based on NS messages\n"); + usage(); + + puts("\nOPTIONS:\n" + " --interface, -i Network interface\n" + " --src-addr, -s IPv6 Source Address\n" + " --dst-addr, -d IPv6 Destination Address\n" + " --frag-hdr. -y Fragment Header\n" + " --dst-opt-hdr, -u Destination Options Header (Fragmentable Part)\n" + " --dst-opt-u-hdr, -U Destination Options Header (Unfragmentable Part)\n" + " --hbh-opt-hdr, -H Hop by Hop Options Header\n" + " --link-src-addr, -S Link-layer Destination Address\n" + " --link-dst-addr, -D Link-layer Source Address\n" + " --target-address, -t ND Target Address\n" + " --source-lla-opt, -E Source link-layer address option\n" + " --add-slla-opt, -e Add Source link-layer address option\n" + " --flood-sources, -F Number of Source Addresses to forge randomly\n" + " --flood-targets, -T Flood with NA's for multiple Target Addresses\n" + " --loop, -l Send Neighbor Solicitations periodically\n" + " --sleep, -z Pause between peiodic Neighbor Solicitations\n" + " --help, -h Print help for the ns6 tool\n" + " --verbose, -v Be verbose\n" + "\n" + "Programmed by Fernando Gont for SI6 Networks \n" + "Please send any bug reports to "); } - - /* * Function: print_attack_info() * * Print attack details (when the verbose ("-v") option is specified). */ -void print_attack_info(struct iface_data *idata){ - if(floods_f) - printf("Flooding the target from %u different IPv6 Source Addresses\n", nsources); +void print_attack_info(struct iface_data *idata) { + if (floods_f) + printf("Flooding the target from %u different IPv6 Source Addresses\n", nsources); - if(floodt_f) - printf("Flooding the target with %u ND Target Addresses\n", ntargets); + if (floodt_f) + printf("Flooding the target with %u ND Target Addresses\n", ntargets); - if(!floods_f){ - if(ether_ntop(&(idata->hsrcaddr), plinkaddr, sizeof(plinkaddr)) == 0){ - puts("ether_ntop(): Error converting address"); - exit(EXIT_FAILURE); - } + if (!floods_f) { + if (ether_ntop(&(idata->hsrcaddr), plinkaddr, sizeof(plinkaddr)) == 0) { + puts("ether_ntop(): Error converting address"); + exit(EXIT_FAILURE); + } - printf("Ethernet Source Address: %s%s\n", plinkaddr, ((!idata->hsrcaddr_f)?" (randomized)":"")); + printf("Ethernet Source Address: %s%s\n", plinkaddr, ((!idata->hsrcaddr_f) ? " (randomized)" : "")); } - else{ - if(idata->hsrcaddr_f){ - if(ether_ntop(&(idata->hsrcaddr), plinkaddr, sizeof(plinkaddr)) == 0){ - puts("ether_ntop(): Error converting address"); - exit(EXIT_FAILURE); - } - - printf("Ethernet Source Address: %s\n", plinkaddr); - } - else - puts("Ethernet Source Address: randomized for each packet"); + else { + if (idata->hsrcaddr_f) { + if (ether_ntop(&(idata->hsrcaddr), plinkaddr, sizeof(plinkaddr)) == 0) { + puts("ether_ntop(): Error converting address"); + exit(EXIT_FAILURE); + } + + printf("Ethernet Source Address: %s\n", plinkaddr); + } + else + puts("Ethernet Source Address: randomized for each packet"); } - if(ether_ntop(&(idata->hdstaddr), phdstaddr, sizeof(phdstaddr)) == 0){ - puts("ether_ntop(): Error converting address"); - exit(EXIT_FAILURE); + if (ether_ntop(&(idata->hdstaddr), phdstaddr, sizeof(phdstaddr)) == 0) { + puts("ether_ntop(): Error converting address"); + exit(EXIT_FAILURE); } - printf("Ethernet Destination Address: %s%s\n", phdstaddr, \ - ((!idata->hdstaddr_f)?" (all-nodes multicast)":"")); + printf("Ethernet Destination Address: %s%s\n", phdstaddr, ((!idata->hdstaddr_f) ? " (all-nodes multicast)" : "")); - if(inet_ntop(AF_INET6, &(idata->srcaddr), psrcaddr, sizeof(psrcaddr)) == NULL){ - puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); - exit(EXIT_FAILURE); + if (inet_ntop(AF_INET6, &(idata->srcaddr), psrcaddr, sizeof(psrcaddr)) == NULL) { + puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); + exit(EXIT_FAILURE); } - if(!floods_f){ - printf("IPv6 Source Address: %s%s\n", psrcaddr, ((!idata->srcaddr_f)?" (randomized)":"")); + if (!floods_f) { + printf("IPv6 Source Address: %s%s\n", psrcaddr, ((!idata->srcaddr_f) ? " (randomized)" : "")); } - else{ - printf("IPv6 Source Address: randomized, from the %s/%u prefix%s\n", psrcaddr, idata->srcpreflen, \ - (!idata->srcprefix_f)?" (default)":""); + else { + printf("IPv6 Source Address: randomized, from the %s/%u prefix%s\n", psrcaddr, idata->srcpreflen, + (!idata->srcprefix_f) ? " (default)" : ""); } - if(inet_ntop(AF_INET6, &(idata->dstaddr), pdstaddr, sizeof(pdstaddr)) == NULL){ - puts("Error converting IPv6 Destination Address to presentation format"); - exit(EXIT_FAILURE); + if (inet_ntop(AF_INET6, &(idata->dstaddr), pdstaddr, sizeof(pdstaddr)) == NULL) { + puts("Error converting IPv6 Destination Address to presentation format"); + exit(EXIT_FAILURE); } - printf("IPv6 Destination Address: %s%s\n", pdstaddr, \ - ((!idata->dstaddr_f)?" (all-nodes link-local multicast)":"")); + printf("IPv6 Destination Address: %s%s\n", pdstaddr, + ((!idata->dstaddr_f) ? " (all-nodes link-local multicast)" : "")); + + printf("IPv6 Hop Limit: %u%s\n", hoplimit, (hoplimit_f) ? "" : " (default)"); - printf("IPv6 Hop Limit: %u%s\n", hoplimit, (hoplimit_f)?"":" (default)"); + for (i = 0; i < ndstoptuhdr; i++) + printf("Destination Options Header (Unfragmentable part): %u bytes\n", dstoptuhdrlen[i]); - for(i=0; ifragh_f) + printf("Sending each packet in fragments of %u bytes (plus the Unfragmentable part)\n", nfrags); - if(idata->fragh_f) - printf("Sending each packet in fragments of %u bytes (plus the Unfragmentable part)\n", nfrags); - - if(!floodt_f){ - if(targetaddr_f){ - if(inet_ntop(AF_INET6, &targetaddr, pv6addr, sizeof(pv6addr)) == NULL){ - puts("inet_ntop(): Error converting ND IPv6 Target Address to presentation format"); - exit(EXIT_FAILURE); - } + if (!floodt_f) { + if (targetaddr_f) { + if (inet_ntop(AF_INET6, &targetaddr, pv6addr, sizeof(pv6addr)) == NULL) { + puts("inet_ntop(): Error converting ND IPv6 Target Address to presentation format"); + exit(EXIT_FAILURE); + } - printf("ND Target Address: %s\n", pv6addr); - } + printf("ND Target Address: %s\n", pv6addr); + } } - else{ - if(inet_ntop(AF_INET6, &targetaddr, pv6addr, sizeof(pv6addr)) == NULL){ - puts("inet_ntop(): Error converting ND IPv6 Target Address to presentation format"); - exit(EXIT_FAILURE); - } - - printf("ND Target Address: randomized, from the %s/%u prefix%s\n", pv6addr, targetpreflen,\ - (!targetprefix_f)?" (default)":""); + else { + if (inet_ntop(AF_INET6, &targetaddr, pv6addr, sizeof(pv6addr)) == NULL) { + puts("inet_ntop(): Error converting ND IPv6 Target Address to presentation format"); + exit(EXIT_FAILURE); + } + + printf("ND Target Address: randomized, from the %s/%u prefix%s\n", pv6addr, targetpreflen, + (!targetprefix_f) ? " (default)" : ""); } - for(i=0;i Address: %s\n", \ - ((floods_f && !sllopta_f)?"(randomized for each packet)":plinkaddr)); + printf("Source Link-layer Address option -> Address: %s\n", + ((floods_f && !sllopta_f) ? "(randomized for each packet)" : plinkaddr)); } } - diff --git a/tools/ns6.h b/tools/ns6.h index 7a64aa1..89152ae 100644 --- a/tools/ns6.h +++ b/tools/ns6.h @@ -2,5 +2,3 @@ * Header file for the ns6 tool * */ - - diff --git a/tools/path6.c b/tools/path6.c index 69ae074..9a15583 100644 --- a/tools/path6.c +++ b/tools/path6.c @@ -18,1490 +18,1478 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - * + * * Build with: make path6 - * + * * It requires that the libpcap library be installed on your system. * * Please send any bug reports to Fernando Gont */ -#include #include -#include #include +#include +#include -#include #include -#include -#include #include +#include +#include +#include #include -#include -#include #include -#include #include -#include -#include -#include -#include #include #include +#include +#include +#include +#include +#include +#include +#include -#include "path6.h" #include "ipv6toolkit.h" #include "libipv6.h" - - +#include "path6.h" /* Function prototypes */ -void init_packet_data(struct iface_data *); -int send_probe(struct iface_data *, unsigned int, unsigned char, unsigned char, uint32_t); -void print_attack_info(struct iface_data *); -void print_help(void); -void usage(void); +void init_packet_data(struct iface_data *); +int send_probe(struct iface_data *, unsigned int, unsigned char, unsigned char, uint32_t); +void print_attack_info(struct iface_data *); +void print_help(void); +void usage(void); /* Used for router discovery */ -struct iface_data idata; +struct iface_data idata; -struct in6_addr randprefix; -unsigned char randpreflen; +struct in6_addr randprefix; +unsigned char randpreflen; /* Data structures for packets read from the wire */ -struct pcap_pkthdr *pkthdr; -const u_char *pktdata; -unsigned char *pkt_end, *pkt_ptr; -struct ether_header *pkt_ether; -struct ip6_hdr *pkt_ipv6; -struct ip6_frag *pkt_fh; -struct icmp6_hdr *pkt_icmp6; -struct tcp_hdr *pkt_tcp; -struct udp_hdr *pkt_udp; -struct ah_hdr *pkt_ah; -struct esp_hdr *pkt_esp; -struct ip6_eh *pkt_eh; +struct pcap_pkthdr *pkthdr; +const u_char *pktdata; +unsigned char *pkt_end, *pkt_ptr; +struct ether_header *pkt_ether; +struct ip6_hdr *pkt_ipv6; +struct ip6_frag *pkt_fh; +struct icmp6_hdr *pkt_icmp6; +struct tcp_hdr *pkt_tcp; +struct udp_hdr *pkt_udp; +struct ah_hdr *pkt_ah; +struct esp_hdr *pkt_esp; +struct ip6_eh *pkt_eh; struct nd_neighbor_solicit *pkt_ns; -struct in6_addr *pkt_ipv6addr; -unsigned int pktbytes; -unsigned int rhbytes, rhleft; - -bpf_u_int32 my_netmask; -bpf_u_int32 my_ip; -struct bpf_program pcap_filter; -char dev[64], errbuf[PCAP_ERRBUF_SIZE]; -unsigned char buffer[65556], buffrh[MIN_IPV6_HLEN + MIN_TCP_HLEN]; -unsigned char *v6buffer, *ptr, *startofprefixes; -char *pref; - -struct ip6_hdr *ipv6; -struct icmp6_hdr *icmp6; - -struct ether_header *ethernet; -struct dlt_null *dlt_null; +struct in6_addr *pkt_ipv6addr; +unsigned int pktbytes; +unsigned int rhbytes, rhleft; + +bpf_u_int32 my_netmask; +bpf_u_int32 my_ip; +struct bpf_program pcap_filter; +char dev[64], errbuf[PCAP_ERRBUF_SIZE]; +unsigned char buffer[65556], buffrh[MIN_IPV6_HLEN + MIN_TCP_HLEN]; +unsigned char *v6buffer, *ptr, *startofprefixes; +char *pref; + +struct ip6_hdr *ipv6; +struct icmp6_hdr *icmp6; + +struct ether_header *ethernet; +struct dlt_null *dlt_null; #if defined(__linux__) - struct sll_linux *sll_linux; +struct sll_linux *sll_linux; #endif -struct nd_opt_tlla *tllaopt; +struct nd_opt_tlla *tllaopt; + +char *lasts, *rpref; +char *charptr; + +int nw; +unsigned long ul_res, ul_val; +unsigned int i, j, startrand; +unsigned int skip; +unsigned int frags, nfrags; +uint16_t mask, ip6length; +uint8_t hoplimit; + +char plinkaddr[ETHER_ADDR_PLEN]; +char psrcaddr[INET6_ADDRSTRLEN], pdstaddr[INET6_ADDRSTRLEN], pv6addr[INET6_ADDRSTRLEN]; +unsigned char verbose_f = FALSE, numeric_f = TRUE; +unsigned char loop_f = FALSE, localaddr_f = 0, probe_f = 0, flowlabel_f = FALSE, flowlabelr_f = FALSE; +unsigned char srcprefix_f = FALSE, hoplimit_f = FALSE, ip6length_f = FALSE, icmp6psize_f = FALSE, send_f = FALSE, + end_f = FALSE, delayp_f = FALSE; -char *lasts, *rpref; -char *charptr; +/* Support for Extension Headers */ +unsigned int dstopthdrs, dstoptuhdrs, hbhopthdrs; +char hbhopthdr_f = 0, dstoptuhdr_f = 0, dstopthdr_f = 0; +unsigned char *dstopthdr[MAX_DST_OPT_HDR], *dstoptuhdr[MAX_DST_OPT_U_HDR]; +unsigned char *hbhopthdr[MAX_HBH_OPT_HDR]; +unsigned int dstopthdrlen[MAX_DST_OPT_HDR], dstoptuhdrlen[MAX_DST_OPT_U_HDR]; +unsigned int hbhopthdrlen[MAX_HBH_OPT_HDR], m, pad; + +struct ip6_frag *fh, fraghdr; +struct ip6_hdr *fipv6; +unsigned char fragbuffer[ETHER_HDR_LEN + MIN_IPV6_HLEN + MAX_IPV6_PAYLOAD]; + +unsigned char *fragpart, *fptr, *fptrend, *ptrend, *ptrhdr, *ptrhdrend; +unsigned int hdrlen, ndstopthdr = 0, nhbhopthdr = 0, ndstoptuhdr = 0; +unsigned int nfrags, fragsize; +unsigned char *prev_nh, *startoffragment; -int nw; -unsigned long ul_res, ul_val; -unsigned int i, j, startrand; -unsigned int skip; -unsigned int frags, nfrags; -uint16_t mask, ip6length; -uint8_t hoplimit; +/* Parameters for the probe packets */ +unsigned char probetype = PROBE_ICMP6_ECHO; +unsigned char dstport_f = FALSE, tcpflags_f = FALSE, pps_f = FALSE, bps_f = FALSE, endhost_f = FALSE, rhbytes_f = FALSE, + droppacket_f = FALSE; +unsigned char scriptmode_f = FALSE; +uint16_t dstport, pid; +uint8_t tcpflags = 0, cprobe, pprobe, nprobe, maxprobes, chop, phop, nhop, maxhops; + +struct in6_addr nsrc; +uint32_t tcpseq, spi, nflow = 0, flowlabel = 0; + +#define MAXHOPS 30 +#define MAXPROBES 3 +struct probe test[MAXHOPS][MAXPROBES]; +unsigned long pktinterval, rate; +unsigned int packetsize; + +char line[LINE_BUFFER_SIZE]; + +int main(int argc, char **argv) { + extern char *optarg; + fd_set sset, rset; + + int r, sel; + struct timeval curtime, start, lastprobe, sched, timeout; + uint8_t ulhtype; + struct target_ipv6 targetipv6; + unsigned long fl; + + static struct option longopts[] = {{"interface", required_argument, 0, 'i'}, + {"link-src-addr", required_argument, 0, 'S'}, + {"link-dst-addr", required_argument, 0, 'D'}, + {"src-addr", required_argument, 0, 's'}, + {"dst-addr", required_argument, 0, 'd'}, + {"dst-opt-hdr", required_argument, 0, 'u'}, + {"dst-opt-u-hdr", required_argument, 0, 'U'}, + {"hbh-opt-hdr", required_argument, 0, 'H'}, + {"frag-hdr", required_argument, 0, 'y'}, + {"numeric", no_argument, 0, 'n'}, + {"flow-label", required_argument, 0, 'f'}, + {"probe-type", required_argument, 0, 'p'}, + {"payload-size", required_argument, 0, 'P'}, + {"dst-port", required_argument, 0, 'a'}, + {"tcp-flags", required_argument, 0, 'X'}, + {"rate-limit", required_argument, 0, 'r'}, + {"mode", required_argument, 0, 'm'}, + {"verbose", no_argument, 0, 'v'}, + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0}}; + + const char shortopts[] = "i:S:D:s:d:u:U:H:y:nf:p:P:a:X:r:m:vh"; + + char option; + + if (argc <= 1) { + usage(); + exit(EXIT_FAILURE); + } + + srandom(time(NULL)); + hoplimit = 64 + random() % 180; + init_iface_data(&idata); + + while ((r = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { + option = r; + + switch (option) { + case 'i': /* Interface */ + strncpy(idata.iface, optarg, IFACE_LENGTH); + idata.iface[IFACE_LENGTH - 1] = 0; + idata.ifindex = if_nametoindex(idata.iface); + idata.iface_f = TRUE; + break; + + case 's': /* IPv6 Source Address */ + if ((charptr = strtok_r(optarg, "/", &lasts)) == NULL) { + puts("Error in Source Address"); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, charptr, &(idata.srcaddr)) <= 0) { + puts("inet_pton(): Source Address not valid"); + exit(EXIT_FAILURE); + } + + idata.srcaddr_f = 1; + + if ((charptr = strtok_r(NULL, " ", &lasts)) != NULL) { + idata.srcpreflen = atoi(charptr); + + if (idata.srcpreflen > 128) { + puts("Prefix length error in IPv6 Source Address"); + exit(EXIT_FAILURE); + } + + sanitize_ipv6_prefix(&(idata.srcaddr), idata.srcpreflen); + idata.srcprefix_f = 1; + } + + break; + + case 'd': /* IPv6 Destination Address */ + strncpy(targetipv6.name, optarg, NI_MAXHOST); + targetipv6.name[NI_MAXHOST - 1] = 0; + targetipv6.flags = AI_CANONNAME; + + if ((r = get_ipv6_target(&targetipv6)) != 0) { + + if (r < 0) { + printf("Unknown Destination: %s\n", gai_strerror(targetipv6.res)); + } + else { + puts("Unknown Destination: No IPv6 address found for specified destination"); + } + + exit(EXIT_FAILURE); + } + + idata.dstaddr = targetipv6.ip6; + idata.dstaddr_f = 1; + break; + + case 'u': /* Destinations Options Header */ + if (ndstopthdr >= MAX_DST_OPT_HDR) { + puts("Too many Destination Options Headers"); + exit(EXIT_FAILURE); + } + + hdrlen = atoi(optarg); + + if (hdrlen < 8) { + puts("Bad length in Destination Options Header"); + exit(EXIT_FAILURE); + } + + hdrlen = ((hdrlen + 7) / 8) * 8; + dstopthdrlen[ndstopthdr] = hdrlen; + + if ((dstopthdr[ndstopthdr] = malloc(hdrlen)) == NULL) { + puts("Not enough memory for Destination Options Header"); + exit(EXIT_FAILURE); + } + + ptrhdr = dstopthdr[ndstopthdr] + 2; + ptrhdrend = dstopthdr[ndstopthdr] + hdrlen; -char plinkaddr[ETHER_ADDR_PLEN]; -char psrcaddr[INET6_ADDRSTRLEN], pdstaddr[INET6_ADDRSTRLEN], pv6addr[INET6_ADDRSTRLEN]; -unsigned char verbose_f=FALSE, numeric_f= TRUE; -unsigned char loop_f=FALSE, localaddr_f=0, probe_f=0, flowlabel_f=FALSE, flowlabelr_f=FALSE; -unsigned char srcprefix_f=FALSE, hoplimit_f=FALSE, ip6length_f=FALSE, icmp6psize_f=FALSE, send_f=FALSE, end_f=FALSE, delayp_f=FALSE; + while (ptrhdr < ptrhdrend) { -/* Support for Extension Headers */ -unsigned int dstopthdrs, dstoptuhdrs, hbhopthdrs; -char hbhopthdr_f=0, dstoptuhdr_f=0, dstopthdr_f=0; -unsigned char *dstopthdr[MAX_DST_OPT_HDR], *dstoptuhdr[MAX_DST_OPT_U_HDR]; -unsigned char *hbhopthdr[MAX_HBH_OPT_HDR]; -unsigned int dstopthdrlen[MAX_DST_OPT_HDR], dstoptuhdrlen[MAX_DST_OPT_U_HDR]; -unsigned int hbhopthdrlen[MAX_HBH_OPT_HDR], m, pad; - -struct ip6_frag *fh, fraghdr; -struct ip6_hdr *fipv6; -unsigned char fragbuffer[ETHER_HDR_LEN+MIN_IPV6_HLEN+MAX_IPV6_PAYLOAD]; - -unsigned char *fragpart, *fptr, *fptrend, *ptrend, *ptrhdr, *ptrhdrend; -unsigned int hdrlen, ndstopthdr=0, nhbhopthdr=0, ndstoptuhdr=0; -unsigned int nfrags, fragsize; -unsigned char *prev_nh, *startoffragment; + if ((ptrhdrend - ptrhdr) > 257) + pad = 257; + else + pad = ptrhdrend - ptrhdr; + + if (!insert_pad_opt(ptrhdr, ptrhdrend, pad)) { + puts("Destination Options Header Too Big"); + exit(EXIT_FAILURE); + } + + ptrhdr = ptrhdr + pad; + } + + *(dstopthdr[ndstopthdr] + 1) = (hdrlen / 8) - 1; + ndstopthdr++; + dstopthdr_f = 1; + break; + + case 'U': /* Destination Options Header (Unfragmentable Part) */ + if (ndstoptuhdr >= MAX_DST_OPT_U_HDR) { + puts("Too many Destination Options Headers (Unfragmentable Part)"); + exit(EXIT_FAILURE); + } + + hdrlen = atoi(optarg); -/* Parameters for the probe packets */ -unsigned char probetype=PROBE_ICMP6_ECHO; -unsigned char dstport_f=FALSE, tcpflags_f=FALSE, pps_f=FALSE, bps_f=FALSE, endhost_f=FALSE, rhbytes_f=FALSE, droppacket_f=FALSE; -unsigned char scriptmode_f=FALSE; -uint16_t dstport, pid; -uint8_t tcpflags=0, cprobe, pprobe, nprobe, maxprobes, chop, phop, nhop, maxhops; - -struct in6_addr nsrc; -uint32_t tcpseq, spi, nflow=0, flowlabel=0; - -#define MAXHOPS 30 -#define MAXPROBES 3 -struct probe test[MAXHOPS][MAXPROBES]; -unsigned long pktinterval, rate; -unsigned int packetsize; - -char line[LINE_BUFFER_SIZE]; - - -int main(int argc, char **argv){ - extern char *optarg; - fd_set sset, rset; - - int r, sel; - struct timeval curtime, start, lastprobe, sched, timeout; - uint8_t ulhtype; - struct target_ipv6 targetipv6; - unsigned long fl; - - static struct option longopts[] = { - {"interface", required_argument, 0, 'i'}, - {"link-src-addr", required_argument, 0, 'S'}, - {"link-dst-addr", required_argument, 0, 'D'}, - {"src-addr", required_argument, 0, 's'}, - {"dst-addr", required_argument, 0, 'd'}, - {"dst-opt-hdr", required_argument, 0, 'u'}, - {"dst-opt-u-hdr", required_argument, 0, 'U'}, - {"hbh-opt-hdr", required_argument, 0, 'H'}, - {"frag-hdr", required_argument, 0, 'y'}, - {"numeric", no_argument, 0, 'n'}, - {"flow-label", required_argument, 0, 'f'}, - {"probe-type", required_argument, 0, 'p'}, - {"payload-size", required_argument, 0, 'P'}, - {"dst-port", required_argument, 0, 'a'}, - {"tcp-flags", required_argument, 0, 'X'}, - {"rate-limit", required_argument, 0, 'r'}, - {"mode", required_argument, 0, 'm'}, - {"verbose", no_argument, 0, 'v'}, - {"help", no_argument, 0, 'h'}, - {0, 0, 0, 0} - }; - - const char shortopts[]= "i:S:D:s:d:u:U:H:y:nf:p:P:a:X:r:m:vh"; - - char option; - - if(argc<=1){ - usage(); - exit(EXIT_FAILURE); - } - - - srandom(time(NULL)); - hoplimit=64+random()%180; - init_iface_data(&idata); - - while((r=getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { - option= r; - - switch(option) { - case 'i': /* Interface */ - strncpy(idata.iface, optarg, IFACE_LENGTH); - idata.iface[IFACE_LENGTH-1]=0; - idata.ifindex= if_nametoindex(idata.iface); - idata.iface_f=TRUE; - break; - - case 's': /* IPv6 Source Address */ - if((charptr = strtok_r(optarg, "/", &lasts)) == NULL){ - puts("Error in Source Address"); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, charptr, &(idata.srcaddr)) <= 0){ - puts("inet_pton(): Source Address not valid"); - exit(EXIT_FAILURE); - } - - idata.srcaddr_f = 1; - - if((charptr = strtok_r(NULL, " ", &lasts)) != NULL){ - idata.srcpreflen = atoi(charptr); - - if(idata.srcpreflen>128){ - puts("Prefix length error in IPv6 Source Address"); - exit(EXIT_FAILURE); - } - - sanitize_ipv6_prefix(&(idata.srcaddr), idata.srcpreflen); - idata.srcprefix_f=1; - } - - break; - - case 'd': /* IPv6 Destination Address */ - strncpy( targetipv6.name, optarg, NI_MAXHOST); - targetipv6.name[NI_MAXHOST-1]= 0; - targetipv6.flags= AI_CANONNAME; - - if( (r=get_ipv6_target(&targetipv6)) != 0){ - - if(r < 0){ - printf("Unknown Destination: %s\n", gai_strerror(targetipv6.res)); - } - else{ - puts("Unknown Destination: No IPv6 address found for specified destination"); - } - - exit(EXIT_FAILURE); - } - - idata.dstaddr= targetipv6.ip6; - idata.dstaddr_f = 1; - break; - - case 'u': /* Destinations Options Header */ - if(ndstopthdr >= MAX_DST_OPT_HDR){ - puts("Too many Destination Options Headers"); - exit(EXIT_FAILURE); - } - - hdrlen= atoi(optarg); - - if(hdrlen < 8){ - puts("Bad length in Destination Options Header"); - exit(EXIT_FAILURE); - } - - hdrlen = ((hdrlen+7)/8) * 8; - dstopthdrlen[ndstopthdr]= hdrlen; - - if( (dstopthdr[ndstopthdr]= malloc(hdrlen)) == NULL){ - puts("Not enough memory for Destination Options Header"); - exit(EXIT_FAILURE); - } - - ptrhdr= dstopthdr[ndstopthdr] + 2; - ptrhdrend= dstopthdr[ndstopthdr] + hdrlen; - - while( ptrhdr < ptrhdrend){ - - if( (ptrhdrend-ptrhdr)>257) - pad= 257; - else - pad= ptrhdrend-ptrhdr; - - if(!insert_pad_opt(ptrhdr, ptrhdrend, pad)){ - puts("Destination Options Header Too Big"); - exit(EXIT_FAILURE); - } - - ptrhdr= ptrhdr + pad; - } - - *(dstopthdr[ndstopthdr]+1)= (hdrlen/8)-1; - ndstopthdr++; - dstopthdr_f=1; - break; - - case 'U': /* Destination Options Header (Unfragmentable Part) */ - if(ndstoptuhdr >= MAX_DST_OPT_U_HDR){ - puts("Too many Destination Options Headers (Unfragmentable Part)"); - exit(EXIT_FAILURE); - } - - hdrlen= atoi(optarg); - - if(hdrlen < 8){ - puts("Bad length in Destination Options Header (Unfragmentable Part)"); - exit(EXIT_FAILURE); - } - - hdrlen = ((hdrlen+7)/8) * 8; - dstoptuhdrlen[ndstoptuhdr]= hdrlen; - - if( (dstoptuhdr[ndstoptuhdr]= malloc(hdrlen)) == NULL){ - puts("Not enough memory for Destination Options Header (Unfragmentable Part)"); - exit(EXIT_FAILURE); - } - - ptrhdr= dstoptuhdr[ndstoptuhdr]+2; - ptrhdrend= dstoptuhdr[ndstoptuhdr] + hdrlen; - - while( ptrhdr < ptrhdrend){ - - if( (ptrhdrend-ptrhdr)>257) - pad= 257; - else - pad= ptrhdrend-ptrhdr; - - if(!insert_pad_opt(ptrhdr, ptrhdrend, pad)){ - puts("Destination Options Header (Unfragmentable Part) Too Big"); - exit(EXIT_FAILURE); - } - - ptrhdr = ptrhdr + pad; - } - - *(dstoptuhdr[ndstoptuhdr]+1)= (hdrlen/8) - 1; - ndstoptuhdr++; - dstoptuhdr_f=1; - break; - - case 'H': /* Hop-by-Hop Options Header */ - if(nhbhopthdr >= MAX_HBH_OPT_HDR){ - puts("Too many Hop-by-Hop Options Headers"); - exit(EXIT_FAILURE); - } - - hdrlen= atoi(optarg); - - if(hdrlen < 8){ - puts("Bad length in Hop-by-Hop Options Header"); - exit(EXIT_FAILURE); - } - - hdrlen = ((hdrlen+7)/8) * 8; - hbhopthdrlen[nhbhopthdr]= hdrlen; - - if( (hbhopthdr[nhbhopthdr]= malloc(hdrlen)) == NULL){ - puts("Not enough memory for Hop-by-Hop Options Header"); - exit(EXIT_FAILURE); - } - - ptrhdr= hbhopthdr[nhbhopthdr] + 2; - ptrhdrend= hbhopthdr[nhbhopthdr] + hdrlen; - - - while( ptrhdr < ptrhdrend){ - - if( (ptrhdrend-ptrhdr)>257) - pad= 257; - else - pad= ptrhdrend-ptrhdr; - - if(!insert_pad_opt(ptrhdr, ptrhdrend, pad)){ - puts("Hop-by-Hop Options Header Too Big"); - exit(EXIT_FAILURE); - } - - ptrhdr = ptrhdr + pad; - } - - *(hbhopthdr[nhbhopthdr]+1)= (hdrlen/8) - 1; - nhbhopthdr++; - hbhopthdr_f=1; - break; - - case 'y': /* Fragment header */ - nfrags= atoi(optarg); - if(nfrags < 8){ - puts("Error in Fragmentation option: Fragment Size must be at least 8 bytes"); - exit(EXIT_FAILURE); - } - - idata.fragh_f=TRUE; - break; - - case 'n': /* Print IPv6 addresses ratther than hostnames */ - numeric_f=TRUE; - break; - - case 'S': /* Source Ethernet address */ - if(ether_pton(optarg, &(idata.hsrcaddr), sizeof(idata.hsrcaddr)) == 0){ - puts("Error in Source link-layer address."); - exit(EXIT_FAILURE); - } - - idata.hsrcaddr_f = 1; - break; - - case 'D': /* Destination Ethernet Address */ - if(ether_pton(optarg, &(idata.hdstaddr), sizeof(idata.hdstaddr)) == 0){ - puts("Error in Source link-layer address."); - exit(EXIT_FAILURE); - } - - idata.hdstaddr_f = 1; - break; - - case 'f': /* Flow Label */ - if(strncmp(optarg, "rand", sizeof(rand)) == 0){ - flowlabelr_f= TRUE; - } - else{ - if( (fl = strtoul(optarg, NULL, 0)) == ULONG_MAX){ - puts("Flow Label value is too large"); - exit(EXIT_FAILURE); - } - - flowlabel= fl & 0x000fffff; -/* flowlabel= atoi(optarg) & 0x000fffff; */ - flowlabel_f= TRUE; - } - - break; - - case 'p': /* Probe type */ - if(strncmp(optarg, "echo", strlen("echo")) == 0 || strncmp(optarg, "icmp", strlen("icmp")) == 0){ - probetype= PROBE_ICMP6_ECHO; - probe_f=TRUE; - } - else if(strncmp(optarg, "udp", strlen("udp")) == 0){ - probetype= PROBE_UDP; - probe_f=TRUE; - } - else if(strncmp(optarg, "tcp", strlen("tcp")) == 0){ - probetype= PROBE_TCP; - probe_f=TRUE; - } - else if(strncmp(optarg, "esp", strlen("ESP")) == 0){ - probetype= PROBE_ESP; - probe_f=TRUE; - } - else if(strncmp(optarg, "ah", strlen("AH")) == 0){ - probetype= PROBE_AH; - probe_f=TRUE; - } - else{ - puts("Error in '-p' option: Unknown probe type"); - exit(EXIT_FAILURE); - } - - break; - - case 'P': /* Payload Size*/ - rhbytes= atoi(optarg); - rhbytes_f= 1; - break; - - case 'a': /* TCP/UDP Destination Port */ - dstport= atoi(optarg); - dstport_f=TRUE; - break; - - case 'X': - if(strncmp(optarg, "no", 2) == 0 || strncmp(optarg, "noflags", strlen("noflags")) == 0){ - tcpflags_f=1; - break; - } - - charptr = optarg; - while(*charptr){ - switch(*charptr){ - case 'F': - tcpflags= tcpflags | TH_FIN; - break; - - case 'S': - tcpflags= tcpflags | TH_SYN; - break; - - case 'R': - tcpflags= tcpflags | TH_RST; - break; - - case 'P': - tcpflags= tcpflags | TH_PUSH; - break; - - case 'A': - tcpflags= tcpflags | TH_ACK; - break; - - case 'U': - tcpflags= tcpflags | TH_URG; - break; - - case 'X': /* No TCP flags */ - break; - - default: - printf("Error: Unknown TCP flag '%c'\n", *charptr); - exit(EXIT_FAILURE); - break; - } - - if(*charptr == 'X') - break; - - charptr++; - } - - tcpflags_f=TRUE; - break; - - case 'r': - if( Strnlen(optarg, LINE_BUFFER_SIZE-1) >= (LINE_BUFFER_SIZE-1)){ - puts("scan6: -r option is too long"); - exit(EXIT_FAILURE); - } - - sscanf(optarg, "%lu%s", &rate, line); - - line[LINE_BUFFER_SIZE-1]=0; - - if(strncmp(line, "pps", 3) == 0) - pps_f=TRUE; - else if(strncmp(line, "bps", 3) == 0) - bps_f=TRUE; - else{ - puts("scan6: Unknown unit of for the rate limit ('-r' option). Unit should be 'bps' or 'pps'"); - exit(EXIT_FAILURE); - } - - break; - - case 'm': - if(strncmp(optarg, "num", sizeof("num")) == 0){ - numeric_f= TRUE; - } - else if(strncmp(optarg, "script", sizeof("script")) == 0){ - scriptmode_f= TRUE; - } - - break; - - case 'v': /* Be verbose */ - idata.verbose_f++; - break; - - case 'h': /* Help */ - print_help(); - - exit(EXIT_FAILURE); - break; - - default: - usage(); - exit(EXIT_FAILURE); - break; - - } /* switch */ - } /* while(getopt) */ - - verbose_f= idata.verbose_f; - - if(geteuid()) { - puts("path6 needs root privileges to run."); - exit(EXIT_FAILURE); - } - - if(!idata.dstaddr_f){ - puts("Error: Must specify Destination System"); - exit(EXIT_FAILURE); - } - - if(!idata.iface_f){ - if(idata.dstaddr_f && IN6_IS_ADDR_LINKLOCAL(&(idata.dstaddr))){ - puts("Must specify a network interface for link-local destinations"); - exit(EXIT_FAILURE); - } - } - - if(load_dst_and_pcap(&idata, LOAD_SRC_NXT_HOP) == FAILURE){ - puts("Error while learning Source Address and Next Hop"); - exit(EXIT_FAILURE); - } - - release_privileges(); - - if((idata.ip6_local_flag && idata.ip6_global_flag) && !idata.srcaddr_f) - localaddr_f=1; - - if(!probe_f) - probetype= PROBE_ICMP6_ECHO; - - - if(probetype == PROBE_TCP){ - if(!dstport_f) - dstport= 80; - - if(!tcpflags_f) - tcpflags= TH_SYN; - - tcpseq=random() & 0x7fffffff; - } - else if(probetype == PROBE_UDP){ - if(!dstport_f) - dstport= 60000 + random() % 5000; - } - else if(probetype == PROBE_ESP || probetype == PROBE_AH){ - spi= random(); - } - - if(pps_f){ - if(rate < 1) - rate=1; - - pktinterval= 1000000/rate; - } - - - if(bps_f){ - switch(probetype){ - case PROBE_ICMP6_ECHO: - packetsize= MIN_IPV6_HLEN + MIN_DST_OPT_HDR_SIZE + sizeof(struct icmp6_hdr); - break; - - case PROBE_TCP: - packetsize= MIN_IPV6_HLEN + sizeof(struct tcp_hdr); - break; - - case PROBE_ESP: - packetsize= MIN_IPV6_HLEN + sizeof(struct esp_hdr); - break; - - case PROBE_AH: - packetsize= MIN_IPV6_HLEN + sizeof(struct ah_hdr); - break; - } - - if(rate == 0 || ((packetsize * 8)/rate) <= 0) - pktinterval= 1000000; - else - pktinterval= ((packetsize * 8)/rate) * 1000000; - } - - /* We Default to 10 pps */ - if(!pps_f && !bps_f) - pktinterval= 100000; - - if(inet_ntop(AF_INET6, &(idata.dstaddr), pv6addr, sizeof(pv6addr)) == NULL){ - puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); - exit(EXIT_FAILURE); - } - - if(idata.verbose_f){ - print_attack_info(&idata); - } - - if(!scriptmode_f) - printf("Tracing path to %s (%s)...\n\n", targetipv6.name, pv6addr); - - /* Set initial contents of the attack packet */ - init_packet_data(&idata); - - /* - Set filter for receiving IPv6 packets - XXX: This filter should probably be refined - */ - if(pcap_compile(idata.pfd, &pcap_filter, PCAP_IPV6_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1){ - printf("pcap_compile(): %s\n", pcap_geterr(idata.pfd)); - exit(EXIT_FAILURE); - } - - if(pcap_setfilter(idata.pfd, &pcap_filter) == -1){ - printf("pcap_setfilter(): %s\n", pcap_geterr(idata.pfd)); - exit(EXIT_FAILURE); - } - - pid= getpid(); - - pcap_freecode(&pcap_filter); - - maxhops=MAXHOPS; - maxprobes=MAXPROBES; - - /* Initialize the table of results for the different tests */ - memset(test, 0, sizeof(test)); - - FD_ZERO(&sset); - FD_SET(idata.fd, &sset); - - /* Next probe to be printed out */ - phop=0; - pprobe=0; - - /* Next probe to be sent */ - chop=0; - cprobe=0; - - if(gettimeofday(&start, NULL) == -1){ - if(idata.verbose_f) - perror("path6"); - - exit(EXIT_FAILURE); - } - - /* PROBE_TIMEOUT is in seconds */ - sched.tv_sec= PROBE_TIMEOUT; - sched.tv_usec= 0; - - lastprobe= timeval_sub(&start, &sched); - - end_f=0; - - while(!end_f){ - if(gettimeofday(&curtime, NULL) == -1){ - if(idata.verbose_f) - perror("path6"); - - exit(EXIT_FAILURE); - } - - if(scriptmode_f && phop < maxhops && pprobe < maxprobes && test[phop][pprobe].sent){ - if(test[phop][pprobe].received){ - /* If a response was received, print the RTT. */ - if(inet_ntop(AF_INET6, &(test[phop][pprobe].srcaddr), psrcaddr, sizeof(psrcaddr)) == NULL){ - puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); - exit(EXIT_FAILURE); - } - - printf("#%02d#%s#%08x#%08x#%.3f\n", phop+1, psrcaddr, test[phop][pprobe].sflow, \ - test[phop][pprobe].rflow, time_diff_ms(&(test[phop][pprobe].rtstamp), &(test[phop][pprobe].ststamp))); - - pprobe++; - - if(pprobe >= maxprobes){ - pprobe=0; - phop++; - - if(phop >= maxhops) - end_f=1; - } - -/* puts(""); */ - - - } - else if(is_time_elapsed(&curtime, &(test[phop][pprobe].ststamp), PROBE_TIMEOUT * 1000000)){ - /* If there was a probe timeout, we allow to send another probe */ - send_f=1; - printf("#%02d####\n", phop+1); - - pprobe++; - - if(pprobe >= maxprobes){ - pprobe=0; - phop++; - - if(phop >= maxhops) - end_f=1; - } - } - }else if(phop < maxhops && pprobe < maxprobes && test[phop][pprobe].sent){ - /* - If the next probe to be printed out has been sent, evaluate whether it is time to print out - the result. - - phop: Holds hop to be printed - probe: Holds probe number to be printed - */ - if(test[phop][pprobe].received){ - /* If a response was received, print the RTT. */ - if(inet_ntop(AF_INET6, &(test[phop][pprobe].srcaddr), psrcaddr, sizeof(psrcaddr)) == NULL){ - puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); - exit(EXIT_FAILURE); - } - - /* - delayp_f is set when no response has been received for this specific hop. So we wait until we receive - a response, such that we can print the IPv6 address followed by asterisks (for each missing response) - */ - if(delayp_f){ - if(numeric_f){ - printf(" %2d (%s)", phop+1, psrcaddr); - } - else{ - - } - - for(i=0; i= maxprobes){ - puts(""); - - pprobe=0; - phop++; - - if(phop >= maxhops) - end_f=1; - } - - fflush(stdout); - } - else if(is_time_elapsed(&curtime, &(test[phop][pprobe].ststamp), PROBE_TIMEOUT * 1000000)){ - /* If there was a probe timeout, we allow to send another probe */ - send_f=1; - - /* - If more than probe_timeout seconds have elapsed, consider the probe lost. - Print an asterisk, and wait for the next probe. - */ - - if(pprobe == 0 || delayp_f){ - pprobe++; - - if(pprobe >= maxprobes){ - printf("%2d () * * *\n", phop+1); - fflush(stdout); - pprobe=0; - phop++; - - if(phop >= maxhops) - end_f=1; - - delayp_f=0; - } - else{ - delayp_f=1; - } - } - else{ - printf(" *"); - pprobe++; - - if(pprobe >= maxprobes){ - puts(""); - pprobe=0; - - phop++; - - if(phop >= maxhops) - end_f=1; - } - - fflush(stdout); - } - } - } - - /* If there is a probe to be sent, and rate-limiting allows, send the probe send_f || */ - while( ( is_time_elapsed(&curtime, &lastprobe, pktinterval)) && chop < maxhops && cprobe < maxprobes){ - if(gettimeofday(&curtime, NULL) == -1){ - if(idata.verbose_f) - perror("path6"); - - exit(EXIT_FAILURE); - } - - if(flowlabelr_f) - flowlabel= random() & 0x00fffff; - - test[chop][cprobe].sent= TRUE; - test[chop][cprobe].ststamp= curtime; - test[chop][cprobe].sflow= flowlabel; - lastprobe= curtime; - - if(send_probe(&idata, probetype, chop, cprobe, flowlabel) == -1){ - puts("path6: Error while sending probe packet"); - exit(EXIT_FAILURE); - } - - send_f=0; - - cprobe++; - - if(cprobe >= maxprobes){ - cprobe=0; - chop++; - } - } - - /* - XXX: This should be improved. Essentially, select() might sleep for at most one second (if no - packets are received). Then a bunch of probe packets might be sent out all at once. - */ - rset= sset; - timeout.tv_sec= pktinterval / 1000000 ; - timeout.tv_usec= pktinterval % 1000000; - - /* - Since we cannot count on the pcap_socket being readable, we should wait the smaller of 10ms or - the packet rate "timeout" - */ + if (hdrlen < 8) { + puts("Bad length in Destination Options Header (Unfragmentable Part)"); + exit(EXIT_FAILURE); + } + + hdrlen = ((hdrlen + 7) / 8) * 8; + dstoptuhdrlen[ndstoptuhdr] = hdrlen; + + if ((dstoptuhdr[ndstoptuhdr] = malloc(hdrlen)) == NULL) { + puts("Not enough memory for Destination Options Header (Unfragmentable Part)"); + exit(EXIT_FAILURE); + } + + ptrhdr = dstoptuhdr[ndstoptuhdr] + 2; + ptrhdrend = dstoptuhdr[ndstoptuhdr] + hdrlen; + + while (ptrhdr < ptrhdrend) { + + if ((ptrhdrend - ptrhdr) > 257) + pad = 257; + else + pad = ptrhdrend - ptrhdr; + + if (!insert_pad_opt(ptrhdr, ptrhdrend, pad)) { + puts("Destination Options Header (Unfragmentable Part) Too Big"); + exit(EXIT_FAILURE); + } + + ptrhdr = ptrhdr + pad; + } + + *(dstoptuhdr[ndstoptuhdr] + 1) = (hdrlen / 8) - 1; + ndstoptuhdr++; + dstoptuhdr_f = 1; + break; + + case 'H': /* Hop-by-Hop Options Header */ + if (nhbhopthdr >= MAX_HBH_OPT_HDR) { + puts("Too many Hop-by-Hop Options Headers"); + exit(EXIT_FAILURE); + } + + hdrlen = atoi(optarg); + + if (hdrlen < 8) { + puts("Bad length in Hop-by-Hop Options Header"); + exit(EXIT_FAILURE); + } + + hdrlen = ((hdrlen + 7) / 8) * 8; + hbhopthdrlen[nhbhopthdr] = hdrlen; + + if ((hbhopthdr[nhbhopthdr] = malloc(hdrlen)) == NULL) { + puts("Not enough memory for Hop-by-Hop Options Header"); + exit(EXIT_FAILURE); + } + + ptrhdr = hbhopthdr[nhbhopthdr] + 2; + ptrhdrend = hbhopthdr[nhbhopthdr] + hdrlen; + + while (ptrhdr < ptrhdrend) { + + if ((ptrhdrend - ptrhdr) > 257) + pad = 257; + else + pad = ptrhdrend - ptrhdr; + + if (!insert_pad_opt(ptrhdr, ptrhdrend, pad)) { + puts("Hop-by-Hop Options Header Too Big"); + exit(EXIT_FAILURE); + } + + ptrhdr = ptrhdr + pad; + } + + *(hbhopthdr[nhbhopthdr] + 1) = (hdrlen / 8) - 1; + nhbhopthdr++; + hbhopthdr_f = 1; + break; + + case 'y': /* Fragment header */ + nfrags = atoi(optarg); + if (nfrags < 8) { + puts("Error in Fragmentation option: Fragment Size must be at least 8 bytes"); + exit(EXIT_FAILURE); + } + + idata.fragh_f = TRUE; + break; + + case 'n': /* Print IPv6 addresses ratther than hostnames */ + numeric_f = TRUE; + break; + + case 'S': /* Source Ethernet address */ + if (ether_pton(optarg, &(idata.hsrcaddr), sizeof(idata.hsrcaddr)) == 0) { + puts("Error in Source link-layer address."); + exit(EXIT_FAILURE); + } + + idata.hsrcaddr_f = 1; + break; + + case 'D': /* Destination Ethernet Address */ + if (ether_pton(optarg, &(idata.hdstaddr), sizeof(idata.hdstaddr)) == 0) { + puts("Error in Source link-layer address."); + exit(EXIT_FAILURE); + } + + idata.hdstaddr_f = 1; + break; + + case 'f': /* Flow Label */ + if (strncmp(optarg, "rand", sizeof(rand)) == 0) { + flowlabelr_f = TRUE; + } + else { + if ((fl = strtoul(optarg, NULL, 0)) == ULONG_MAX) { + puts("Flow Label value is too large"); + exit(EXIT_FAILURE); + } + + flowlabel = fl & 0x000fffff; + /* flowlabel= atoi(optarg) & 0x000fffff; */ + flowlabel_f = TRUE; + } + + break; + + case 'p': /* Probe type */ + if (strncmp(optarg, "echo", strlen("echo")) == 0 || strncmp(optarg, "icmp", strlen("icmp")) == 0) { + probetype = PROBE_ICMP6_ECHO; + probe_f = TRUE; + } + else if (strncmp(optarg, "udp", strlen("udp")) == 0) { + probetype = PROBE_UDP; + probe_f = TRUE; + } + else if (strncmp(optarg, "tcp", strlen("tcp")) == 0) { + probetype = PROBE_TCP; + probe_f = TRUE; + } + else if (strncmp(optarg, "esp", strlen("ESP")) == 0) { + probetype = PROBE_ESP; + probe_f = TRUE; + } + else if (strncmp(optarg, "ah", strlen("AH")) == 0) { + probetype = PROBE_AH; + probe_f = TRUE; + } + else { + puts("Error in '-p' option: Unknown probe type"); + exit(EXIT_FAILURE); + } + + break; + + case 'P': /* Payload Size*/ + rhbytes = atoi(optarg); + rhbytes_f = 1; + break; + + case 'a': /* TCP/UDP Destination Port */ + dstport = atoi(optarg); + dstport_f = TRUE; + break; + + case 'X': + if (strncmp(optarg, "no", 2) == 0 || strncmp(optarg, "noflags", strlen("noflags")) == 0) { + tcpflags_f = 1; + break; + } + + charptr = optarg; + while (*charptr) { + switch (*charptr) { + case 'F': + tcpflags = tcpflags | TH_FIN; + break; + + case 'S': + tcpflags = tcpflags | TH_SYN; + break; + + case 'R': + tcpflags = tcpflags | TH_RST; + break; + + case 'P': + tcpflags = tcpflags | TH_PUSH; + break; + + case 'A': + tcpflags = tcpflags | TH_ACK; + break; + + case 'U': + tcpflags = tcpflags | TH_URG; + break; + + case 'X': /* No TCP flags */ + break; + + default: + printf("Error: Unknown TCP flag '%c'\n", *charptr); + exit(EXIT_FAILURE); + break; + } + + if (*charptr == 'X') + break; + + charptr++; + } + + tcpflags_f = TRUE; + break; + + case 'r': + if (Strnlen(optarg, LINE_BUFFER_SIZE - 1) >= (LINE_BUFFER_SIZE - 1)) { + puts("scan6: -r option is too long"); + exit(EXIT_FAILURE); + } + + sscanf(optarg, "%lu%s", &rate, line); + + line[LINE_BUFFER_SIZE - 1] = 0; + + if (strncmp(line, "pps", 3) == 0) + pps_f = TRUE; + else if (strncmp(line, "bps", 3) == 0) + bps_f = TRUE; + else { + puts("scan6: Unknown unit of for the rate limit ('-r' option). Unit should be 'bps' or 'pps'"); + exit(EXIT_FAILURE); + } + + break; + + case 'm': + if (strncmp(optarg, "num", sizeof("num")) == 0) { + numeric_f = TRUE; + } + else if (strncmp(optarg, "script", sizeof("script")) == 0) { + scriptmode_f = TRUE; + } + + break; + + case 'v': /* Be verbose */ + idata.verbose_f++; + break; + + case 'h': /* Help */ + print_help(); + + exit(EXIT_FAILURE); + break; + + default: + usage(); + exit(EXIT_FAILURE); + break; + + } /* switch */ + } /* while(getopt) */ + + verbose_f = idata.verbose_f; + + if (geteuid()) { + puts("path6 needs root privileges to run."); + exit(EXIT_FAILURE); + } + + if (!idata.dstaddr_f) { + puts("Error: Must specify Destination System"); + exit(EXIT_FAILURE); + } + + if (!idata.iface_f) { + if (idata.dstaddr_f && IN6_IS_ADDR_LINKLOCAL(&(idata.dstaddr))) { + puts("Must specify a network interface for link-local destinations"); + exit(EXIT_FAILURE); + } + } + + if (load_dst_and_pcap(&idata, LOAD_SRC_NXT_HOP) == FAILURE) { + puts("Error while learning Source Address and Next Hop"); + exit(EXIT_FAILURE); + } + + release_privileges(); + + if ((idata.ip6_local_flag && idata.ip6_global_flag) && !idata.srcaddr_f) + localaddr_f = 1; + + if (!probe_f) + probetype = PROBE_ICMP6_ECHO; + + if (probetype == PROBE_TCP) { + if (!dstport_f) + dstport = 80; + + if (!tcpflags_f) + tcpflags = TH_SYN; + + tcpseq = random() & 0x7fffffff; + } + else if (probetype == PROBE_UDP) { + if (!dstport_f) + dstport = 60000 + random() % 5000; + } + else if (probetype == PROBE_ESP || probetype == PROBE_AH) { + spi = random(); + } + + if (pps_f) { + if (rate < 1) + rate = 1; + + pktinterval = 1000000 / rate; + } + + if (bps_f) { + switch (probetype) { + case PROBE_ICMP6_ECHO: + packetsize = MIN_IPV6_HLEN + MIN_DST_OPT_HDR_SIZE + sizeof(struct icmp6_hdr); + break; + + case PROBE_TCP: + packetsize = MIN_IPV6_HLEN + sizeof(struct tcp_hdr); + break; + + case PROBE_ESP: + packetsize = MIN_IPV6_HLEN + sizeof(struct esp_hdr); + break; + + case PROBE_AH: + packetsize = MIN_IPV6_HLEN + sizeof(struct ah_hdr); + break; + } + + if (rate == 0 || ((packetsize * 8) / rate) <= 0) + pktinterval = 1000000; + else + pktinterval = ((packetsize * 8) / rate) * 1000000; + } + + /* We Default to 10 pps */ + if (!pps_f && !bps_f) + pktinterval = 100000; + + if (inet_ntop(AF_INET6, &(idata.dstaddr), pv6addr, sizeof(pv6addr)) == NULL) { + puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); + exit(EXIT_FAILURE); + } + + if (idata.verbose_f) { + print_attack_info(&idata); + } + + if (!scriptmode_f) + printf("Tracing path to %s (%s)...\n\n", targetipv6.name, pv6addr); + + /* Set initial contents of the attack packet */ + init_packet_data(&idata); + + /* + Set filter for receiving IPv6 packets + XXX: This filter should probably be refined + */ + if (pcap_compile(idata.pfd, &pcap_filter, PCAP_IPV6_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1) { + printf("pcap_compile(): %s\n", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } + + if (pcap_setfilter(idata.pfd, &pcap_filter) == -1) { + printf("pcap_setfilter(): %s\n", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } + + pid = getpid(); + + pcap_freecode(&pcap_filter); + + maxhops = MAXHOPS; + maxprobes = MAXPROBES; + + /* Initialize the table of results for the different tests */ + memset(test, 0, sizeof(test)); + + FD_ZERO(&sset); + FD_SET(idata.fd, &sset); + + /* Next probe to be printed out */ + phop = 0; + pprobe = 0; + + /* Next probe to be sent */ + chop = 0; + cprobe = 0; + + if (gettimeofday(&start, NULL) == -1) { + if (idata.verbose_f) + perror("path6"); + + exit(EXIT_FAILURE); + } + + /* PROBE_TIMEOUT is in seconds */ + sched.tv_sec = PROBE_TIMEOUT; + sched.tv_usec = 0; + + lastprobe = timeval_sub(&start, &sched); + + end_f = 0; + + while (!end_f) { + if (gettimeofday(&curtime, NULL) == -1) { + if (idata.verbose_f) + perror("path6"); + + exit(EXIT_FAILURE); + } + + if (scriptmode_f && phop < maxhops && pprobe < maxprobes && test[phop][pprobe].sent) { + if (test[phop][pprobe].received) { + /* If a response was received, print the RTT. */ + if (inet_ntop(AF_INET6, &(test[phop][pprobe].srcaddr), psrcaddr, sizeof(psrcaddr)) == NULL) { + puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); + exit(EXIT_FAILURE); + } + + printf("#%02d#%s#%08x#%08x#%.3f\n", phop + 1, psrcaddr, test[phop][pprobe].sflow, + test[phop][pprobe].rflow, + time_diff_ms(&(test[phop][pprobe].rtstamp), &(test[phop][pprobe].ststamp))); + + pprobe++; + + if (pprobe >= maxprobes) { + pprobe = 0; + phop++; + + if (phop >= maxhops) + end_f = 1; + } + + /* puts(""); */ + } + else if (is_time_elapsed(&curtime, &(test[phop][pprobe].ststamp), PROBE_TIMEOUT * 1000000)) { + /* If there was a probe timeout, we allow to send another probe */ + send_f = 1; + printf("#%02d####\n", phop + 1); + + pprobe++; + + if (pprobe >= maxprobes) { + pprobe = 0; + phop++; + + if (phop >= maxhops) + end_f = 1; + } + } + } + else if (phop < maxhops && pprobe < maxprobes && test[phop][pprobe].sent) { + /* + If the next probe to be printed out has been sent, evaluate whether it is time to print out + the result. + + phop: Holds hop to be printed + probe: Holds probe number to be printed + */ + if (test[phop][pprobe].received) { + /* If a response was received, print the RTT. */ + if (inet_ntop(AF_INET6, &(test[phop][pprobe].srcaddr), psrcaddr, sizeof(psrcaddr)) == NULL) { + puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); + exit(EXIT_FAILURE); + } + + /* + delayp_f is set when no response has been received for this specific hop. So we wait until we receive + a response, such that we can print the IPv6 address followed by asterisks (for each missing response) + */ + if (delayp_f) { + if (numeric_f) { + printf(" %2d (%s)", phop + 1, psrcaddr); + } + else { + } + + for (i = 0; i < pprobe; i++) + printf(" *"); + + printf(" %.3f ms", time_diff_ms(&(test[phop][pprobe].rtstamp), &(test[phop][pprobe].ststamp))); + + delayp_f = 0; + } + else { + /* If this is the first "response" for this probe, print the IPv6 address + and the reverse domain name. + */ + if (pprobe == 0) { + if (numeric_f) { + printf("%2d (%s)", phop + 1, psrcaddr); + } + else { + } + } + + printf(" %.3f ms", time_diff_ms(&(test[phop][pprobe].rtstamp), &(test[phop][pprobe].ststamp))); + } + + pprobe++; + + if (pprobe >= maxprobes) { + puts(""); + + pprobe = 0; + phop++; + + if (phop >= maxhops) + end_f = 1; + } + + fflush(stdout); + } + else if (is_time_elapsed(&curtime, &(test[phop][pprobe].ststamp), PROBE_TIMEOUT * 1000000)) { + /* If there was a probe timeout, we allow to send another probe */ + send_f = 1; + + /* + If more than probe_timeout seconds have elapsed, consider the probe lost. + Print an asterisk, and wait for the next probe. + */ + + if (pprobe == 0 || delayp_f) { + pprobe++; + + if (pprobe >= maxprobes) { + printf("%2d () * * *\n", phop + 1); + fflush(stdout); + pprobe = 0; + phop++; + + if (phop >= maxhops) + end_f = 1; + + delayp_f = 0; + } + else { + delayp_f = 1; + } + } + else { + printf(" *"); + pprobe++; + + if (pprobe >= maxprobes) { + puts(""); + pprobe = 0; + + phop++; + + if (phop >= maxhops) + end_f = 1; + } + + fflush(stdout); + } + } + } + + /* If there is a probe to be sent, and rate-limiting allows, send the probe send_f || */ + while ((is_time_elapsed(&curtime, &lastprobe, pktinterval)) && chop < maxhops && cprobe < maxprobes) { + if (gettimeofday(&curtime, NULL) == -1) { + if (idata.verbose_f) + perror("path6"); + + exit(EXIT_FAILURE); + } + + if (flowlabelr_f) + flowlabel = random() & 0x00fffff; + + test[chop][cprobe].sent = TRUE; + test[chop][cprobe].ststamp = curtime; + test[chop][cprobe].sflow = flowlabel; + lastprobe = curtime; + + if (send_probe(&idata, probetype, chop, cprobe, flowlabel) == -1) { + puts("path6: Error while sending probe packet"); + exit(EXIT_FAILURE); + } + + send_f = 0; + + cprobe++; + + if (cprobe >= maxprobes) { + cprobe = 0; + chop++; + } + } + + /* + XXX: This should be improved. Essentially, select() might sleep for at most one second (if no + packets are received). Then a bunch of probe packets might be sent out all at once. + */ + rset = sset; + timeout.tv_sec = pktinterval / 1000000; + timeout.tv_usec = pktinterval % 1000000; + + /* + Since we cannot count on the pcap_socket being readable, we should wait the smaller of 10ms or + the packet rate "timeout" + */ #if defined(sun) || defined(__sun) || defined(__linux__) - if(timeout.tv_sec || timeout.tv_usec > 10000){ - timeout.tv_sec= 0; - timeout.tv_usec= 10000; - } + if (timeout.tv_sec || timeout.tv_usec > 10000) { + timeout.tv_sec = 0; + timeout.tv_usec = 10000; + } #endif - if((sel=select(idata.fd+1, &rset, NULL, NULL, &timeout)) == -1){ - if(errno == EINTR){ - continue; - } - else{ - if(idata.verbose_f) - puts("Error in select()"); + if ((sel = select(idata.fd + 1, &rset, NULL, NULL, &timeout)) == -1) { + if (errno == EINTR) { + continue; + } + else { + if (idata.verbose_f) + puts("Error in select()"); - exit(EXIT_FAILURE); - } - } + exit(EXIT_FAILURE); + } + } #if defined(sun) || defined(__sun) || defined(__linux__) - if(TRUE){ + if (TRUE) { #else - if(FD_ISSET(idata.fd, &rset)){ + if (FD_ISSET(idata.fd, &rset)) { #endif - /* Read a packet (Echo Reply, ICMPv6 Error, or Neighbor Solicitation) */ - if((r=pcap_next_ex(idata.pfd, &pkthdr, &pktdata)) == -1){ - if(idata.verbose_f) - printf("pcap_next_ex(): %s", pcap_geterr(idata.pfd)); - - exit(EXIT_FAILURE); - } - else if(r == 1 && pktdata != NULL){ + /* Read a packet (Echo Reply, ICMPv6 Error, or Neighbor Solicitation) */ + if ((r = pcap_next_ex(idata.pfd, &pkthdr, &pktdata)) == -1) { + if (idata.verbose_f) + printf("pcap_next_ex(): %s", pcap_geterr(idata.pfd)); + + exit(EXIT_FAILURE); + } + else if (r == 1 && pktdata != NULL) { #ifdef DEBUG -puts("Got packet"); + puts("Got packet"); #endif - nflow= 0xffffffff; - pkt_ether = (struct ether_header *) pktdata; - pkt_ipv6 = (struct ip6_hdr *)((char *) pkt_ether + idata.linkhsize); - pkt_end = (unsigned char *) pktdata + pkthdr->caplen; - - if( (pkt_end - pktdata) < (idata.linkhsize + MIN_IPV6_HLEN)) - continue; - - /* - We currently handle two cases: In the first case, there are extension headers, and hence we need to walk through - the extension header chain. In the other, the upper layer protocol is right after the fixed IPv6 header - */ - if(pkt_ipv6->ip6_nxt != IPPROTO_ICMPV6 && pkt_ipv6->ip6_nxt != IPPROTO_TCP && pkt_ipv6->ip6_nxt != IPPROTO_UDP && \ - pkt_ipv6->ip6_nxt != IPPROTO_ESP && pkt_ipv6->ip6_nxt != IPPROTO_AH){ - pkt_eh= (struct ip6_eh *) ((char *) pkt_ipv6 + sizeof(struct ip6_hdr)); - - while( ( (unsigned char *) pkt_eh + MIN_EXT_HLEN) <= pkt_end && (pkt_eh->eh_nxt != IPPROTO_ICMPV6 && \ - pkt_eh->eh_nxt != IPPROTO_TCP && pkt_eh->eh_nxt != IPPROTO_UDP && \ - pkt_ipv6->ip6_nxt != IPPROTO_ESP && pkt_ipv6->ip6_nxt != IPPROTO_AH)){ - pkt_eh= (struct ip6_eh *) ( (char *) pkt_eh + (pkt_eh->eh_len + 1) * 8); - } - - if( (unsigned char *)pkt_eh >= pkt_end){ - continue; - } - else{ - ulhtype= pkt_eh->eh_nxt; - pkt_icmp6= (struct icmp6_hdr *) ( (char *) pkt_eh + (pkt_eh->eh_len + 1) * 8); - pkt_udp= (struct udp_hdr *) pkt_icmp6; - pkt_icmp6 = (struct icmp6_hdr *) pkt_icmp6; - pkt_tcp = (struct tcp_hdr *) pkt_icmp6; - pkt_ah= (struct ah_hdr *) pkt_icmp6; - pkt_esp= (struct esp_hdr *) pkt_icmp6; - pkt_ns= (struct nd_neighbor_solicit *) pkt_icmp6; - } - } - else{ - ulhtype= pkt_ipv6->ip6_nxt; - pkt_icmp6 = (struct icmp6_hdr *) ((char *) pkt_ipv6 + sizeof(struct ip6_hdr)); - pkt_ns= (struct nd_neighbor_solicit *) pkt_icmp6; - pkt_tcp= (struct tcp_hdr *) pkt_icmp6; - pkt_ah= (struct ah_hdr *) pkt_icmp6; - pkt_esp= (struct esp_hdr *) pkt_icmp6; - pkt_udp= (struct udp_hdr *) pkt_icmp6; - } - - /* - At this point, we have skipped IPv6 EHs if there were any, and pkt_* pointers are set - accordingly. - */ - if(ulhtype == IPPROTO_ICMPV6){ - if(idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK) && pkt_icmp6->icmp6_type == ND_NEIGHBOR_SOLICIT){ - if( (pkt_end - (unsigned char *) pkt_ns) < sizeof(struct nd_neighbor_solicit)) - continue; - /* - If the addresses that we're using are not actually configured on the local system - (i.e., they are "spoofed", we must check whether it is a Neighbor Solicitation for - one of our addresses, and respond with a Neighbor Advertisement. Otherwise, the kernel - will take care of that. - */ - if(!localaddr_f && is_eq_in6_addr(&(pkt_ns->nd_ns_target), &idata.srcaddr)){ - if(send_neighbor_advert(&idata, idata.pfd, pktdata) == -1){ - puts("Error sending Neighbor Advertisement"); - exit(EXIT_FAILURE); - } - } - - continue; - } - else if( probetype == PROBE_ICMP6_ECHO && (pkt_icmp6->icmp6_type == ICMP6_ECHO_REPLY)){ + nflow = 0xffffffff; + pkt_ether = (struct ether_header *)pktdata; + pkt_ipv6 = (struct ip6_hdr *)((char *)pkt_ether + idata.linkhsize); + pkt_end = (unsigned char *)pktdata + pkthdr->caplen; + + if ((pkt_end - pktdata) < (idata.linkhsize + MIN_IPV6_HLEN)) + continue; + + /* + We currently handle two cases: In the first case, there are extension headers, and hence we need to + walk through the extension header chain. In the other, the upper layer protocol is right after the + fixed IPv6 header + */ + if (pkt_ipv6->ip6_nxt != IPPROTO_ICMPV6 && pkt_ipv6->ip6_nxt != IPPROTO_TCP && + pkt_ipv6->ip6_nxt != IPPROTO_UDP && pkt_ipv6->ip6_nxt != IPPROTO_ESP && + pkt_ipv6->ip6_nxt != IPPROTO_AH) { + pkt_eh = (struct ip6_eh *)((char *)pkt_ipv6 + sizeof(struct ip6_hdr)); + + while (((unsigned char *)pkt_eh + MIN_EXT_HLEN) <= pkt_end && + (pkt_eh->eh_nxt != IPPROTO_ICMPV6 && pkt_eh->eh_nxt != IPPROTO_TCP && + pkt_eh->eh_nxt != IPPROTO_UDP && pkt_ipv6->ip6_nxt != IPPROTO_ESP && + pkt_ipv6->ip6_nxt != IPPROTO_AH)) { + pkt_eh = (struct ip6_eh *)((char *)pkt_eh + (pkt_eh->eh_len + 1) * 8); + } + + if ((unsigned char *)pkt_eh >= pkt_end) { + continue; + } + else { + ulhtype = pkt_eh->eh_nxt; + pkt_icmp6 = (struct icmp6_hdr *)((char *)pkt_eh + (pkt_eh->eh_len + 1) * 8); + pkt_udp = (struct udp_hdr *)pkt_icmp6; + pkt_icmp6 = (struct icmp6_hdr *)pkt_icmp6; + pkt_tcp = (struct tcp_hdr *)pkt_icmp6; + pkt_ah = (struct ah_hdr *)pkt_icmp6; + pkt_esp = (struct esp_hdr *)pkt_icmp6; + pkt_ns = (struct nd_neighbor_solicit *)pkt_icmp6; + } + } + else { + ulhtype = pkt_ipv6->ip6_nxt; + pkt_icmp6 = (struct icmp6_hdr *)((char *)pkt_ipv6 + sizeof(struct ip6_hdr)); + pkt_ns = (struct nd_neighbor_solicit *)pkt_icmp6; + pkt_tcp = (struct tcp_hdr *)pkt_icmp6; + pkt_ah = (struct ah_hdr *)pkt_icmp6; + pkt_esp = (struct esp_hdr *)pkt_icmp6; + pkt_udp = (struct udp_hdr *)pkt_icmp6; + } + + /* + At this point, we have skipped IPv6 EHs if there were any, and pkt_* pointers are set + accordingly. + */ + if (ulhtype == IPPROTO_ICMPV6) { + if (idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK) && + pkt_icmp6->icmp6_type == ND_NEIGHBOR_SOLICIT) { + if ((pkt_end - (unsigned char *)pkt_ns) < sizeof(struct nd_neighbor_solicit)) + continue; + /* + If the addresses that we're using are not actually configured on the local system + (i.e., they are "spoofed", we must check whether it is a Neighbor Solicitation for + one of our addresses, and respond with a Neighbor Advertisement. Otherwise, the kernel + will take care of that. + */ + if (!localaddr_f && is_eq_in6_addr(&(pkt_ns->nd_ns_target), &idata.srcaddr)) { + if (send_neighbor_advert(&idata, idata.pfd, pktdata) == -1) { + puts("Error sending Neighbor Advertisement"); + exit(EXIT_FAILURE); + } + } + + continue; + } + else if (probetype == PROBE_ICMP6_ECHO && (pkt_icmp6->icmp6_type == ICMP6_ECHO_REPLY)) { #ifdef DEBUG -puts("Got Echo Reply"); + puts("Got Echo Reply"); #endif - /* Process the ICMPv6 Echo Reply */ - if( (pkt_end - (unsigned char *) pkt_icmp6) < sizeof(struct icmp6_hdr)) - continue; + /* Process the ICMPv6 Echo Reply */ + if ((pkt_end - (unsigned char *)pkt_icmp6) < sizeof(struct icmp6_hdr)) + continue; - if(ntohs(pkt_icmp6->icmp6_data16[0]) != pid ) - continue; + if (ntohs(pkt_icmp6->icmp6_data16[0]) != pid) + continue; - nhop= ntohs(pkt_icmp6->icmp6_data16[1]) >> 8; - nprobe= ntohs(pkt_icmp6->icmp6_data16[1]) & 0x00ff; + nhop = ntohs(pkt_icmp6->icmp6_data16[1]) >> 8; + nprobe = ntohs(pkt_icmp6->icmp6_data16[1]) & 0x00ff; - if(nhop >= maxhops) - continue; + if (nhop >= maxhops) + continue; - if(!is_eq_in6_addr(&(pkt_ipv6->ip6_src), &(idata.dstaddr))) - continue; + if (!is_eq_in6_addr(&(pkt_ipv6->ip6_src), &(idata.dstaddr))) + continue; - nsrc= pkt_ipv6->ip6_src; - endhost_f=1; - } - else if((pkt_icmp6->icmp6_type == ICMP6_TIME_EXCEEDED && pkt_icmp6->icmp6_code == ICMP6_TIME_EXCEED_TRANSIT) || - pkt_icmp6->icmp6_type == ICMP6_DST_UNREACH || pkt_icmp6->icmp6_type == ICMP6_PARAM_PROB){ + nsrc = pkt_ipv6->ip6_src; + endhost_f = 1; + } + else if ((pkt_icmp6->icmp6_type == ICMP6_TIME_EXCEEDED && + pkt_icmp6->icmp6_code == ICMP6_TIME_EXCEED_TRANSIT) || + pkt_icmp6->icmp6_type == ICMP6_DST_UNREACH || pkt_icmp6->icmp6_type == ICMP6_PARAM_PROB) { #ifdef DEBUG -puts("Got ICMPv6 error"); -#endif - /* XXX: TODO: THe code currently does not differentiate between different ICMPv6 error types. - This should be properly signaled to the user */ - /* Process the ICMPv6 Error message */ - /* Record the source address of the error message */ - nsrc= pkt_ipv6->ip6_src; - - if(is_eq_in6_addr(&nsrc, &(idata.dstaddr))) - endhost_f=1; - - if(inet_ntop(AF_INET6, &(nsrc), psrcaddr, sizeof(psrcaddr)) == NULL){ - puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); - exit(EXIT_FAILURE); - } - - /* IPv6 header of embedded payload */ - pkt_ipv6= (struct ip6_hdr *) ((char *) pkt_icmp6 + sizeof(struct icmp6_hdr)); - - - /* - Discard the packet if the ICMPv6 error does not contain a full IPv6 header - embedded in the ICMPv6 payload - */ - if( ((unsigned char *)pkt_ipv6 + sizeof(struct ip6_hdr)) > pkt_end) - continue; - - /* - Discard the packet if the embeded IPv6 packet was not directed to our - current destination. - */ - if(!is_eq_in6_addr(&(pkt_ipv6->ip6_dst), &(idata.dstaddr))) - continue; - - /* - Discard the packet if the embeded IPv6 packet did not use our current - Source Address. - */ - if(!is_eq_in6_addr(&(pkt_ipv6->ip6_src), &(idata.srcaddr))) - continue; - - nflow= ntohl(pkt_ipv6->ip6_flow) & 0x000fffff; - - ulhtype= pkt_ipv6->ip6_nxt; - pkt_eh= (struct ip6_eh *) ((char *) pkt_ipv6 + sizeof(struct ip6_hdr)); - - droppacket_f= FALSE; + puts("Got ICMPv6 error"); +#endif + /* XXX: TODO: THe code currently does not differentiate between different ICMPv6 error types. + This should be properly signaled to the user */ + /* Process the ICMPv6 Error message */ + /* Record the source address of the error message */ + nsrc = pkt_ipv6->ip6_src; + + if (is_eq_in6_addr(&nsrc, &(idata.dstaddr))) + endhost_f = 1; + + if (inet_ntop(AF_INET6, &(nsrc), psrcaddr, sizeof(psrcaddr)) == NULL) { + puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); + exit(EXIT_FAILURE); + } + + /* IPv6 header of embedded payload */ + pkt_ipv6 = (struct ip6_hdr *)((char *)pkt_icmp6 + sizeof(struct icmp6_hdr)); + + /* + Discard the packet if the ICMPv6 error does not contain a full IPv6 header + embedded in the ICMPv6 payload + */ + if (((unsigned char *)pkt_ipv6 + sizeof(struct ip6_hdr)) > pkt_end) + continue; + + /* + Discard the packet if the embeded IPv6 packet was not directed to our + current destination. + */ + if (!is_eq_in6_addr(&(pkt_ipv6->ip6_dst), &(idata.dstaddr))) + continue; + + /* + Discard the packet if the embeded IPv6 packet did not use our current + Source Address. + */ + if (!is_eq_in6_addr(&(pkt_ipv6->ip6_src), &(idata.srcaddr))) + continue; + + nflow = ntohl(pkt_ipv6->ip6_flow) & 0x000fffff; + + ulhtype = pkt_ipv6->ip6_nxt; + pkt_eh = (struct ip6_eh *)((char *)pkt_ipv6 + sizeof(struct ip6_hdr)); + + droppacket_f = FALSE; #ifdef DEBUG -puts("Passed all basic checks"); -#endif - - /* If the embedded packet contains EHs, we need to skip the EHs to get to the upper layer protocol */ - /* XXX - The current code assumes that anything that's not a possible probe packet or an ICMPv6 error - is an EH. Other ULPs will be processed as malformed EHs, and thus be dealt with gracefully. - However, the code should only process currently-specified EHs, or drop the packet when any other - header type (whether EH or ULP) is found. - */ - while(ulhtype != IPPROTO_ICMPV6 && ulhtype != IPPROTO_TCP && ulhtype != IPPROTO_UDP && \ - ulhtype != IPPROTO_ESP && ulhtype != IPPROTO_AH && !droppacket_f){ - if( (unsigned char *)pkt_eh >= pkt_end){ - droppacket_f= TRUE; - break; - } - - if(ulhtype == IPPROTO_FRAGMENT){ - if( ((unsigned char *)pkt_eh + sizeof(struct ip6_frag)) > pkt_end){ - droppacket_f= TRUE; - break; - } - - fh= (struct ip6_frag *) ((char *) pkt_eh); - - if(fh->ip6f_offlg & IP6F_OFF_MASK){ - droppacket_f= TRUE; - break; - } - - ulhtype= fh->ip6f_nxt; - - /* XXX */ - pkt_eh = (struct ip6_eh *) ((char *) fh + sizeof(struct ip6_frag)); - break; - } - else{ - if( ((unsigned char *)pkt_eh + sizeof(struct ip6_eh)) > pkt_end){ - droppacket_f=TRUE; - break; - } - - ulhtype= pkt_eh->eh_nxt; - pkt_eh= (struct ip6_eh *) ( (char *) pkt_eh + (pkt_eh->eh_len + 1) * 8); - } - } - - if(droppacket_f){ - continue; - } - - pkt_icmp6 = (struct icmp6_hdr *) ((char *) pkt_eh); - pkt_tcp= (struct tcp_hdr *) ((char *) pkt_eh); - pkt_udp= (struct udp_hdr *) ((char *) pkt_eh); - pkt_esp= (struct esp_hdr *) ((char *) pkt_eh); - pkt_ah= (struct ah_hdr *) ((char *) pkt_eh); + puts("Passed all basic checks"); +#endif + + /* If the embedded packet contains EHs, we need to skip the EHs to get to the upper layer + * protocol */ + /* XXX + The current code assumes that anything that's not a possible probe packet or an ICMPv6 error + is an EH. Other ULPs will be processed as malformed EHs, and thus be dealt with gracefully. + However, the code should only process currently-specified EHs, or drop the packet when any + other header type (whether EH or ULP) is found. + */ + while (ulhtype != IPPROTO_ICMPV6 && ulhtype != IPPROTO_TCP && ulhtype != IPPROTO_UDP && + ulhtype != IPPROTO_ESP && ulhtype != IPPROTO_AH && !droppacket_f) { + if ((unsigned char *)pkt_eh >= pkt_end) { + droppacket_f = TRUE; + break; + } + + if (ulhtype == IPPROTO_FRAGMENT) { + if (((unsigned char *)pkt_eh + sizeof(struct ip6_frag)) > pkt_end) { + droppacket_f = TRUE; + break; + } + + fh = (struct ip6_frag *)((char *)pkt_eh); + + if (fh->ip6f_offlg & IP6F_OFF_MASK) { + droppacket_f = TRUE; + break; + } + + ulhtype = fh->ip6f_nxt; + + /* XXX */ + pkt_eh = (struct ip6_eh *)((char *)fh + sizeof(struct ip6_frag)); + break; + } + else { + if (((unsigned char *)pkt_eh + sizeof(struct ip6_eh)) > pkt_end) { + droppacket_f = TRUE; + break; + } + + ulhtype = pkt_eh->eh_nxt; + pkt_eh = (struct ip6_eh *)((char *)pkt_eh + (pkt_eh->eh_len + 1) * 8); + } + } + + if (droppacket_f) { + continue; + } + + pkt_icmp6 = (struct icmp6_hdr *)((char *)pkt_eh); + pkt_tcp = (struct tcp_hdr *)((char *)pkt_eh); + pkt_udp = (struct udp_hdr *)((char *)pkt_eh); + pkt_esp = (struct esp_hdr *)((char *)pkt_eh); + pkt_ah = (struct ah_hdr *)((char *)pkt_eh); #ifdef DEBUG -puts("Passed even more checks"); -#endif - /* Packet was an ICMPv6 error, and we're now processing the embedded payload */ + puts("Passed even more checks"); +#endif + /* Packet was an ICMPv6 error, and we're now processing the embedded payload */ - if(probetype == PROBE_ICMP6_ECHO && ulhtype == IPPROTO_ICMPV6 && - pkt_icmp6->icmp6_type == ICMP6_ECHO_REQUEST){ + if (probetype == PROBE_ICMP6_ECHO && ulhtype == IPPROTO_ICMPV6 && + pkt_icmp6->icmp6_type == ICMP6_ECHO_REQUEST) { - if( (pkt_end - (unsigned char *) pkt_icmp6) < sizeof(struct icmp6_hdr)) - continue; + if ((pkt_end - (unsigned char *)pkt_icmp6) < sizeof(struct icmp6_hdr)) + continue; - if(ntohs(pkt_icmp6->icmp6_data16[0]) != pid ) - continue; + if (ntohs(pkt_icmp6->icmp6_data16[0]) != pid) + continue; - nhop= ntohs(pkt_icmp6->icmp6_data16[1]) >> 8; - nprobe= ntohs(pkt_icmp6->icmp6_data16[1]) & 0x00ff; + nhop = ntohs(pkt_icmp6->icmp6_data16[1]) >> 8; + nprobe = ntohs(pkt_icmp6->icmp6_data16[1]) & 0x00ff; #ifdef DEBUG -printf("hop %d, probe: %d\n", nhop, nprobe); -#endif - } - else if(probetype == PROBE_TCP && ulhtype == IPPROTO_TCP){ - /* Must still verify the TCP checksum */ + printf("hop %d, probe: %d\n", nhop, nprobe); +#endif + } + else if (probetype == PROBE_TCP && ulhtype == IPPROTO_TCP) { + /* Must still verify the TCP checksum */ - if( (pkt_end - (unsigned char *) pkt_tcp) < sizeof(struct tcp_hdr)) - continue; + if ((pkt_end - (unsigned char *)pkt_tcp) < sizeof(struct tcp_hdr)) + continue; - if( ntohl(pkt_tcp->th_seq) != tcpseq) - continue; + if (ntohl(pkt_tcp->th_seq) != tcpseq) + continue; - nhop= (ntohs(pkt_tcp->th_sport) >> 8) - PROBE_PORT_OFFSET; - nprobe= ntohs(pkt_tcp->th_sport) & 0xff; + nhop = (ntohs(pkt_tcp->th_sport) >> 8) - PROBE_PORT_OFFSET; + nprobe = ntohs(pkt_tcp->th_sport) & 0xff; #ifdef DEBUG -puts("Got Time Exceeded for TCP probe"); + puts("Got Time Exceeded for TCP probe"); #endif - } - else if(probetype == PROBE_UDP && ulhtype == IPPROTO_UDP){ - /* Must still verify the UDP checksum */ - if( (pkt_end - (unsigned char *) pkt_udp) < sizeof(struct udp_hdr)) - continue; + } + else if (probetype == PROBE_UDP && ulhtype == IPPROTO_UDP) { + /* Must still verify the UDP checksum */ + if ((pkt_end - (unsigned char *)pkt_udp) < sizeof(struct udp_hdr)) + continue; - if(ntohs(pkt_udp->uh_ulen) < sizeof(struct udp_hdr)) - continue; + if (ntohs(pkt_udp->uh_ulen) < sizeof(struct udp_hdr)) + continue; - nhop= (ntohs(pkt_udp->uh_sport) >> 8) - PROBE_PORT_OFFSET; - nprobe= ntohs(pkt_udp->uh_sport) & 0xff; + nhop = (ntohs(pkt_udp->uh_sport) >> 8) - PROBE_PORT_OFFSET; + nprobe = ntohs(pkt_udp->uh_sport) & 0xff; #ifdef DEBUG -puts("Got Time Exceeded for UDP probe"); + puts("Got Time Exceeded for UDP probe"); #endif - } + } - else if(probetype == PROBE_ESP && ulhtype == IPPROTO_ESP){ - if( (pkt_end - (unsigned char *) pkt_esp) < sizeof(struct esp_hdr)) - continue; + else if (probetype == PROBE_ESP && ulhtype == IPPROTO_ESP) { + if ((pkt_end - (unsigned char *)pkt_esp) < sizeof(struct esp_hdr)) + continue; - if(pkt_esp->esp_spi != spi) - continue; + if (pkt_esp->esp_spi != spi) + continue; - nhop= ntohl(pkt_esp->esp_seq) >> 16; - nprobe= ntohl(pkt_esp->esp_seq) & 0x000000ff; - } - else if(probetype == PROBE_AH && ulhtype == IPPROTO_AH){ - if( (pkt_end - (unsigned char *) pkt_ah) < sizeof(struct ah_hdr)) - continue; + nhop = ntohl(pkt_esp->esp_seq) >> 16; + nprobe = ntohl(pkt_esp->esp_seq) & 0x000000ff; + } + else if (probetype == PROBE_AH && ulhtype == IPPROTO_AH) { + if ((pkt_end - (unsigned char *)pkt_ah) < sizeof(struct ah_hdr)) + continue; - if(pkt_ah->ah_spi != spi) - continue; + if (pkt_ah->ah_spi != spi) + continue; - nhop= ntohl(pkt_ah->ah_seq) >> 16; - nprobe= ntohl(pkt_ah->ah_seq) & 0x000000ff; + nhop = ntohl(pkt_ah->ah_seq) >> 16; + nprobe = ntohl(pkt_ah->ah_seq) & 0x000000ff; #ifdef DEBUG -puts("Got time exceeeded for AH"); -#endif - } - } - else{ - continue; - } - } - else if(ulhtype == IPPROTO_TCP && probetype == PROBE_TCP){ - /* Must still verify the TCP checksum -- We do not do it yet */ - - if( (pkt_end - (unsigned char *) pkt_tcp) < sizeof(struct tcp_hdr)) - continue; - - if(!is_eq_in6_addr(&(pkt_ipv6->ip6_src), &(idata.dstaddr))){ - continue; - } - - - /* XXX: This check should really take into account the payload size */ - if( ntohl(pkt_tcp->th_ack) < tcpseq || ntohl(pkt_tcp->th_ack) > (tcpseq+100000)){ - continue; - } - - if(ntohs(pkt_tcp->th_sport) != dstport){ - continue; - } - - nhop= (ntohs(pkt_tcp->th_dport) >> 8) - PROBE_PORT_OFFSET; - nprobe= ntohs(pkt_tcp->th_dport) & 0x00ff; - - nsrc= pkt_ipv6->ip6_src; - endhost_f=1; - } - else if(probetype == PROBE_UDP && ulhtype == IPPROTO_UDP){ - /* Must still verify the UDP checksum */ - if( (pkt_end - (unsigned char *) pkt_udp) < sizeof(struct udp_hdr)) - continue; - - if(ntohs(pkt_udp->uh_sport) != dstport){ - continue; - } - - nprobe= (ntohs(pkt_udp->uh_sport) >> 8) - PROBE_PORT_OFFSET; - nhop= ntohs(pkt_udp->uh_sport) & 0x00ff; - - nsrc= pkt_ipv6->ip6_src; - endhost_f=1; - } - else{ - continue; - } - - if(nprobe >= maxprobes){ + puts("Got time exceeeded for AH"); +#endif + } + } + else { + continue; + } + } + else if (ulhtype == IPPROTO_TCP && probetype == PROBE_TCP) { + /* Must still verify the TCP checksum -- We do not do it yet */ + + if ((pkt_end - (unsigned char *)pkt_tcp) < sizeof(struct tcp_hdr)) + continue; + + if (!is_eq_in6_addr(&(pkt_ipv6->ip6_src), &(idata.dstaddr))) { + continue; + } + + /* XXX: This check should really take into account the payload size */ + if (ntohl(pkt_tcp->th_ack) < tcpseq || ntohl(pkt_tcp->th_ack) > (tcpseq + 100000)) { + continue; + } + + if (ntohs(pkt_tcp->th_sport) != dstport) { + continue; + } + + nhop = (ntohs(pkt_tcp->th_dport) >> 8) - PROBE_PORT_OFFSET; + nprobe = ntohs(pkt_tcp->th_dport) & 0x00ff; + + nsrc = pkt_ipv6->ip6_src; + endhost_f = 1; + } + else if (probetype == PROBE_UDP && ulhtype == IPPROTO_UDP) { + /* Must still verify the UDP checksum */ + if ((pkt_end - (unsigned char *)pkt_udp) < sizeof(struct udp_hdr)) + continue; + + if (ntohs(pkt_udp->uh_sport) != dstport) { + continue; + } + + nprobe = (ntohs(pkt_udp->uh_sport) >> 8) - PROBE_PORT_OFFSET; + nhop = ntohs(pkt_udp->uh_sport) & 0x00ff; + + nsrc = pkt_ipv6->ip6_src; + endhost_f = 1; + } + else { + continue; + } + + if (nprobe >= maxprobes) { #ifdef DEBUG - printf("Descarte por nprobe mayor o igual que maxprobe (%u >= %u)\n", nprobe, maxprobes); + printf("Descarte por nprobe mayor o igual que maxprobe (%u >= %u)\n", nprobe, maxprobes); #endif - continue; - } + continue; + } - if(nhop >= maxhops){ + if (nhop >= maxhops) { #ifdef DEBUG - printf("Descarte por nhop mayor o igual que maxhops (%u >= %u)\n", nhop, maxhops); + printf("Descarte por nhop mayor o igual que maxhops (%u >= %u)\n", nhop, maxhops); #endif - continue; - } + continue; + } - if(test[nhop][nprobe].received){ + if (test[nhop][nprobe].received) { #ifdef DEBUG - printf("Descarte por (nhop, nprobe) ya habia sido recibido (%u, %u)\n", nhop, nprobe); + printf("Descarte por (nhop, nprobe) ya habia sido recibido (%u, %u)\n", nhop, nprobe); #endif - continue; - } + continue; + } - if(test[nhop][nprobe].sent == FALSE){ + if (test[nhop][nprobe].sent == FALSE) { #ifdef DEBUG - printf("Descarte por (nhop, nprobe) no habia sido enviado (%u, %u)\n", nhop, nprobe); + printf("Descarte por (nhop, nprobe) no habia sido enviado (%u, %u)\n", nhop, nprobe); #endif - continue; - } - - test[nhop][nprobe].received= TRUE; - - /* Record the receive time from the pkthdr timestamp - XXX: We employ the ts member (struct timeval) in struct pcap_pkthdr. That way we do not need to - hurry up to process the received packets, and can e.g. do DNS resolutions without screwing up the - measured RTTs. - */ - test[nhop][nprobe].rtstamp.tv_sec= (pkthdr->ts).tv_sec; - test[nhop][nprobe].rtstamp.tv_usec= (pkthdr->ts).tv_usec; - test[nhop][nprobe].srcaddr= nsrc; - test[nhop][nprobe].rflow= nflow; - - /* If we got a response to a probe packet, allow for an additional probe to be sent */ - send_f= TRUE; - - /* - If we received a response from the end host, we artificially change maxhops such that we do not - send probes for larger Hop Limits - */ - - if(endhost_f && nhop < maxhops && phop <= nhop) - maxhops=nhop+1; - - endhost_f=0; - } - } - } - - exit(EXIT_SUCCESS); + continue; + } + + test[nhop][nprobe].received = TRUE; + + /* Record the receive time from the pkthdr timestamp + XXX: We employ the ts member (struct timeval) in struct pcap_pkthdr. That way we do not need to + hurry up to process the received packets, and can e.g. do DNS resolutions without screwing up the + measured RTTs. + */ + test[nhop][nprobe].rtstamp.tv_sec = (pkthdr->ts).tv_sec; + test[nhop][nprobe].rtstamp.tv_usec = (pkthdr->ts).tv_usec; + test[nhop][nprobe].srcaddr = nsrc; + test[nhop][nprobe].rflow = nflow; + + /* If we got a response to a probe packet, allow for an additional probe to be sent */ + send_f = TRUE; + + /* + If we received a response from the end host, we artificially change maxhops such that we do not + send probes for larger Hop Limits + */ + + if (endhost_f && nhop < maxhops && phop <= nhop) + maxhops = nhop + 1; + + endhost_f = 0; + } + } + } + + exit(EXIT_SUCCESS); } - /* * Function: usage() * * Prints the syntax of the frag6 tool */ -void usage(void){ - puts("usage: path6 -d DST_ADDR [-i INTERFACE] [-S LINK_SRC_ADDR] [-D LINK-DST-ADDR]\n" - " [-s SRC_ADDR[/LEN]] [-u DST_OPT_HDR_SIZE] [-U DST_OPT_U_HDR_SIZE]\n" - " [-H HBH_OPT_HDR_SIZE] [-y FRAG:SIZE] [-f FLOW_LABEL]\n" - " [-m MODE] [-p PROBE_TYPE] [-P PAYLOAD_SIZE] [-a DST_PORT] \n" - " [-X TCP_FLAGS] [-r RATE_LIMIT] [-v] [-h]"); +void usage(void) { + puts("usage: path6 -d DST_ADDR [-i INTERFACE] [-S LINK_SRC_ADDR] [-D LINK-DST-ADDR]\n" + " [-s SRC_ADDR[/LEN]] [-u DST_OPT_HDR_SIZE] [-U DST_OPT_U_HDR_SIZE]\n" + " [-H HBH_OPT_HDR_SIZE] [-y FRAG:SIZE] [-f FLOW_LABEL]\n" + " [-m MODE] [-p PROBE_TYPE] [-P PAYLOAD_SIZE] [-a DST_PORT] \n" + " [-X TCP_FLAGS] [-r RATE_LIMIT] [-v] [-h]"); } - /* * Function: print_help() * * Prints help information for the path6 tool */ -void print_help(void){ - puts(SI6_TOOLKIT); - puts( "path6: A versatile IPv6 traceroute\n"); - usage(); - - puts("\nOPTIONS:\n" - " --interface, -i Network interface\n" - " --link-src-addr, -S Link-layer Destination Address\n" - " --link-dst-addr, -D Link-layer Source Address\n" - " --src-addr, -s IPv6 Source Address\n" - " --dst-addr, -d IPv6 Destination Address\n" - " --frag-hdr. -y Fragment Header\n" - " --dst-opt-hdr, -u Destination Options Header (Fragmentable Part)\n" - " --dst-opt-u-hdr, -U Destination Options Header (Unfragmentable Part)\n" - " --hbh-opt-hdr, -H Hop by Hop Options Header\n" - " --flow-label, -f Specifies the Flow Label Value (or 'random')\n" - " --output-mode, -m Specifies output mode (e.g. 'script')\n" - " --probe-type, -p Probe type {icmp, tcp, udp, ah, esp}\n" - " --payload-size, -P Payload Size\n" - " --dst-port, -a Transport-layer Destination Port\n" - " --tcp-flags, -X TCP Flags\n" - " --rate-limit, -r Rate limit the probe packets\n" - " --verbose, -v Be verbose\n" - " --help, -h Print help for the path6 tool\n" - "\n" - "Programmed by Fernando Gont for SI6 Networks \n" - "Please send any bug reports to \n" - ); +void print_help(void) { + puts(SI6_TOOLKIT); + puts("path6: A versatile IPv6 traceroute\n"); + usage(); + + puts("\nOPTIONS:\n" + " --interface, -i Network interface\n" + " --link-src-addr, -S Link-layer Destination Address\n" + " --link-dst-addr, -D Link-layer Source Address\n" + " --src-addr, -s IPv6 Source Address\n" + " --dst-addr, -d IPv6 Destination Address\n" + " --frag-hdr. -y Fragment Header\n" + " --dst-opt-hdr, -u Destination Options Header (Fragmentable Part)\n" + " --dst-opt-u-hdr, -U Destination Options Header (Unfragmentable Part)\n" + " --hbh-opt-hdr, -H Hop by Hop Options Header\n" + " --flow-label, -f Specifies the Flow Label Value (or 'random')\n" + " --output-mode, -m Specifies output mode (e.g. 'script')\n" + " --probe-type, -p Probe type {icmp, tcp, udp, ah, esp}\n" + " --payload-size, -P Payload Size\n" + " --dst-port, -a Transport-layer Destination Port\n" + " --tcp-flags, -X TCP Flags\n" + " --rate-limit, -r Rate limit the probe packets\n" + " --verbose, -v Be verbose\n" + " --help, -h Print help for the path6 tool\n" + "\n" + "Programmed by Fernando Gont for SI6 Networks \n" + "Please send any bug reports to \n"); } - /* * Function: print_attack_info() * * Prints attack details (when the verbose ("-v") option is specified). */ - -void print_attack_info(struct iface_data *idata){ - if(idata->type == DLT_EN10MB && !(idata->flags & IFACE_LOOPBACK)){ - if(ether_ntop(&(idata->hsrcaddr), plinkaddr, sizeof(plinkaddr)) == 0){ - puts("ether_ntop(): Error converting address"); - exit(EXIT_FAILURE); - } - - printf("Ethernet Source Address: %s%s\n", plinkaddr, (!idata->hsrcaddr_f)?" (automatically selected)":""); - - /* - Ethernet Destination Address only used if a IPv6 Destination Address or an - Ethernet Destination Address were specified. - */ - if(ether_ntop(&(idata->hdstaddr), plinkaddr, sizeof(plinkaddr)) == 0){ - puts("ether_ntop(): Error converting address"); - exit(EXIT_FAILURE); - } - - printf("Ethernet Destination Address: %s%s\n", plinkaddr, (!idata->hdstaddr_f)?" (automatically selected)":""); - } - - if(inet_ntop(AF_INET6, &(idata->srcaddr), psrcaddr, sizeof(psrcaddr)) == NULL){ - puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); - exit(EXIT_FAILURE); - } - - if(idata->dstaddr_f){ - printf("IPv6 Source Address: %s%s\n", psrcaddr, ((!idata->srcaddr_f)?" (automatically selected)":"")); - } - - if(inet_ntop(AF_INET6, &(idata->dstaddr), pdstaddr, sizeof(pdstaddr)) == NULL){ - puts("inet_ntop(): Error converting IPv6 Destination Address to presentation format"); - exit(EXIT_FAILURE); - } - - printf("IPv6 Destination Address: %s\n", pdstaddr); - - for(i=0; i 1)?"s":""); - } -} - +void print_attack_info(struct iface_data *idata) { + if (idata->type == DLT_EN10MB && !(idata->flags & IFACE_LOOPBACK)) { + if (ether_ntop(&(idata->hsrcaddr), plinkaddr, sizeof(plinkaddr)) == 0) { + puts("ether_ntop(): Error converting address"); + exit(EXIT_FAILURE); + } + + printf("Ethernet Source Address: %s%s\n", plinkaddr, (!idata->hsrcaddr_f) ? " (automatically selected)" : ""); + + /* + Ethernet Destination Address only used if a IPv6 Destination Address or an + Ethernet Destination Address were specified. + */ + if (ether_ntop(&(idata->hdstaddr), plinkaddr, sizeof(plinkaddr)) == 0) { + puts("ether_ntop(): Error converting address"); + exit(EXIT_FAILURE); + } + + printf("Ethernet Destination Address: %s%s\n", plinkaddr, + (!idata->hdstaddr_f) ? " (automatically selected)" : ""); + } + + if (inet_ntop(AF_INET6, &(idata->srcaddr), psrcaddr, sizeof(psrcaddr)) == NULL) { + puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); + exit(EXIT_FAILURE); + } + + if (idata->dstaddr_f) { + printf("IPv6 Source Address: %s%s\n", psrcaddr, ((!idata->srcaddr_f) ? " (automatically selected)" : "")); + } + + if (inet_ntop(AF_INET6, &(idata->dstaddr), pdstaddr, sizeof(pdstaddr)) == NULL) { + puts("inet_ntop(): Error converting IPv6 Destination Address to presentation format"); + exit(EXIT_FAILURE); + } + + printf("IPv6 Destination Address: %s\n", pdstaddr); + + for (i = 0; i < ndstoptuhdr; i++) + printf("Destination Options Header (Unfragmentable part): %u bytes\n", dstoptuhdrlen[i]); + + for (i = 0; i < nhbhopthdr; i++) + printf("Hop by Hop Options Header: %u bytes\n", hbhopthdrlen[i]); + + for (i = 0; i < ndstopthdr; i++) + printf("Destination Options Header: %u bytes\n", dstopthdrlen[i]); + + switch (probetype) { + case PROBE_ICMP6_ECHO: + puts("Probe type: ICMPv6 Echo Request"); + + break; + + case PROBE_UDP: + puts("Probe type: UDP"); + printf("Destination Port: %u%s\n", dstport, (dstport_f ? "" : " (default)")); + break; + + case PROBE_TCP: + puts("Probe type: TCP"); + printf("TCP Flags: %s%s%s%s%s%s%s%s\t", ((tcpflags & TH_FIN) ? "F" : ""), ((tcpflags & TH_SYN) ? "S" : ""), + ((tcpflags & TH_RST) ? "R" : ""), ((tcpflags & TH_PUSH) ? "P" : ""), ((tcpflags & TH_ACK) ? "A" : ""), + ((tcpflags & TH_URG) ? "U" : ""), ((!tcpflags) ? "none" : ""), ((!tcpflags_f) ? " (default)" : "")); + + printf("Destination Port: %u%s\n", dstport, (dstport_f ? "" : " (default)")); + break; + + case PROBE_ESP: + puts("Probe type: ESP"); + break; + + case PROBE_AH: + puts("Probe type: AH"); + break; + + default: + puts("Probe type: Unknown"); /* Should never get here */ + break; + } + + if (rhbytes_f) { + printf("Payload size: %u byte%s\n", rhbytes, (rhbytes > 1) ? "s" : ""); + } +} /* * Function: init_packet_data() @@ -1509,420 +1497,417 @@ void print_attack_info(struct iface_data *idata){ * Initialize the contents of the attack packet (Ethernet header, IPv6 Header, and ICMPv6 header) * that are expected to remain constant for the specified attack. */ -void init_packet_data(struct iface_data *idata){ - ethernet= (struct ether_header *) buffer; - dlt_null= (struct dlt_null *) buffer; - v6buffer = buffer + idata->linkhsize; - ipv6 = (struct ip6_hdr *) v6buffer; +void init_packet_data(struct iface_data *idata) { + ethernet = (struct ether_header *)buffer; + dlt_null = (struct dlt_null *)buffer; + v6buffer = buffer + idata->linkhsize; + ipv6 = (struct ip6_hdr *)v6buffer; #if defined(__linux__) - sll_linux= (struct sll_linux *) buffer; + sll_linux = (struct sll_linux *)buffer; #endif - if(idata->type == DLT_EN10MB){ - ethernet->ether_type = htons(ETHERTYPE_IPV6); - - if(idata->flags != IFACE_LOOPBACK){ - ethernet->src = idata->hsrcaddr; - ethernet->dst = idata->hdstaddr; - } - } - else if(idata->type == DLT_NULL){ - dlt_null->family= PF_INET6; - } -#if defined (__OpenBSD__) - else if(idata->type == DLT_LOOP){ - dlt_null->family= htonl(PF_INET6); - } + if (idata->type == DLT_EN10MB) { + ethernet->ether_type = htons(ETHERTYPE_IPV6); + + if (idata->flags != IFACE_LOOPBACK) { + ethernet->src = idata->hsrcaddr; + ethernet->dst = idata->hdstaddr; + } + } + else if (idata->type == DLT_NULL) { + dlt_null->family = PF_INET6; + } +#if defined(__OpenBSD__) + else if (idata->type == DLT_LOOP) { + dlt_null->family = htonl(PF_INET6); + } #elif defined(__linux__) - else if(idata->type == DLT_LINUX_SLL){ - sll_linux->sll_pkttype= htons(0x0004); - sll_linux->sll_hatype= htons(0xffff); - sll_linux->sll_halen= htons(0x0000); - sll_linux->sll_protocol= htons(ETHERTYPE_IPV6); - } + else if (idata->type == DLT_LINUX_SLL) { + sll_linux->sll_pkttype = htons(0x0004); + sll_linux->sll_hatype = htons(0xffff); + sll_linux->sll_halen = htons(0x0000); + sll_linux->sll_protocol = htons(ETHERTYPE_IPV6); + } #endif - ipv6->ip6_flow= htonl(flowlabel); - ipv6->ip6_vfc= 0x60; - ipv6->ip6_src= idata->srcaddr; - ipv6->ip6_dst= idata->dstaddr; - - prev_nh = (unsigned char *) &(ipv6->ip6_nxt); - - ptr = (unsigned char *) v6buffer + MIN_IPV6_HLEN; - - if(hbhopthdr_f){ - hbhopthdrs=0; - - while(hbhopthdrs < nhbhopthdr){ - if((ptr+ hbhopthdrlen[hbhopthdrs]) > (v6buffer+ idata->mtu)){ - puts("Packet too large while processing HBH Opt. Header"); - exit(EXIT_FAILURE); - } - - *prev_nh = IPPROTO_HOPOPTS; - prev_nh = ptr; - memcpy(ptr, hbhopthdr[hbhopthdrs], hbhopthdrlen[hbhopthdrs]); - ptr = ptr + hbhopthdrlen[hbhopthdrs]; - hbhopthdrs++; - } - } - - if(dstoptuhdr_f){ - dstoptuhdrs=0; - - while(dstoptuhdrs < ndstoptuhdr){ - if((ptr+ dstoptuhdrlen[dstoptuhdrs]) > (v6buffer+ idata->mtu)){ - puts("Packet too large while processing Dest. Opt. Header (Unfrag. Part)"); - exit(EXIT_FAILURE); - } - - *prev_nh = IPPROTO_DSTOPTS; - prev_nh = ptr; - memcpy(ptr, dstoptuhdr[dstoptuhdrs], dstoptuhdrlen[dstoptuhdrs]); - ptr = ptr + dstoptuhdrlen[dstoptuhdrs]; - dstoptuhdrs++; - } - } - - /* Everything that follows is the Fragmentable Part of the packet */ - fragpart = ptr; - - if(idata->fragh_f){ - /* Check that we are able to send the Unfragmentable Part, together with a - Fragment Header and a chunk data over our link layer - */ - if( (fragpart+sizeof(fraghdr)+nfrags) > (v6buffer+ idata->mtu)){ - printf("Unfragmentable part too large for current MTU (%u bytes)\n", idata->mtu); - exit(EXIT_FAILURE); - } - - /* We prepare a separate Fragment Header, but we do not include it in the packet to be sent. - This Fragment Header will be used (an assembled with the rest of the packet by the - send_packet() function. - */ - memset(&fraghdr, 0, FRAG_HDR_SIZE); - *prev_nh = IPPROTO_FRAGMENT; - prev_nh = (unsigned char *) &fraghdr; - } - - if(dstopthdr_f){ - dstopthdrs=0; - - while(dstopthdrs < ndstopthdr){ - if((ptr+ dstopthdrlen[dstopthdrs]) > (v6buffer+idata->max_packet_size)){ - puts("Packet too large while processing Dest. Opt. Header (should be using the Frag. option?)"); - exit(EXIT_FAILURE); - } - - *prev_nh = IPPROTO_DSTOPTS; - prev_nh = ptr; - memcpy(ptr, dstopthdr[dstopthdrs], dstopthdrlen[dstopthdrs]); - ptr = ptr + dstopthdrlen[dstopthdrs]; - dstopthdrs++; - } - } - - startofprefixes=ptr; + ipv6->ip6_flow = htonl(flowlabel); + ipv6->ip6_vfc = 0x60; + ipv6->ip6_src = idata->srcaddr; + ipv6->ip6_dst = idata->dstaddr; + + prev_nh = (unsigned char *)&(ipv6->ip6_nxt); + + ptr = (unsigned char *)v6buffer + MIN_IPV6_HLEN; + + if (hbhopthdr_f) { + hbhopthdrs = 0; + + while (hbhopthdrs < nhbhopthdr) { + if ((ptr + hbhopthdrlen[hbhopthdrs]) > (v6buffer + idata->mtu)) { + puts("Packet too large while processing HBH Opt. Header"); + exit(EXIT_FAILURE); + } + + *prev_nh = IPPROTO_HOPOPTS; + prev_nh = ptr; + memcpy(ptr, hbhopthdr[hbhopthdrs], hbhopthdrlen[hbhopthdrs]); + ptr = ptr + hbhopthdrlen[hbhopthdrs]; + hbhopthdrs++; + } + } + + if (dstoptuhdr_f) { + dstoptuhdrs = 0; + + while (dstoptuhdrs < ndstoptuhdr) { + if ((ptr + dstoptuhdrlen[dstoptuhdrs]) > (v6buffer + idata->mtu)) { + puts("Packet too large while processing Dest. Opt. Header (Unfrag. Part)"); + exit(EXIT_FAILURE); + } + + *prev_nh = IPPROTO_DSTOPTS; + prev_nh = ptr; + memcpy(ptr, dstoptuhdr[dstoptuhdrs], dstoptuhdrlen[dstoptuhdrs]); + ptr = ptr + dstoptuhdrlen[dstoptuhdrs]; + dstoptuhdrs++; + } + } + + /* Everything that follows is the Fragmentable Part of the packet */ + fragpart = ptr; + + if (idata->fragh_f) { + /* Check that we are able to send the Unfragmentable Part, together with a + Fragment Header and a chunk data over our link layer + */ + if ((fragpart + sizeof(fraghdr) + nfrags) > (v6buffer + idata->mtu)) { + printf("Unfragmentable part too large for current MTU (%u bytes)\n", idata->mtu); + exit(EXIT_FAILURE); + } + + /* We prepare a separate Fragment Header, but we do not include it in the packet to be sent. + This Fragment Header will be used (an assembled with the rest of the packet by the + send_packet() function. + */ + memset(&fraghdr, 0, FRAG_HDR_SIZE); + *prev_nh = IPPROTO_FRAGMENT; + prev_nh = (unsigned char *)&fraghdr; + } + + if (dstopthdr_f) { + dstopthdrs = 0; + + while (dstopthdrs < ndstopthdr) { + if ((ptr + dstopthdrlen[dstopthdrs]) > (v6buffer + idata->max_packet_size)) { + puts("Packet too large while processing Dest. Opt. Header (should be using the Frag. option?)"); + exit(EXIT_FAILURE); + } + + *prev_nh = IPPROTO_DSTOPTS; + prev_nh = ptr; + memcpy(ptr, dstopthdr[dstopthdrs], dstopthdrlen[dstopthdrs]); + ptr = ptr + dstopthdrlen[dstopthdrs]; + dstopthdrs++; + } + } + + startofprefixes = ptr; } - /* * Function: send_probe() * * Send a probe packet */ -int send_probe(struct iface_data *idata, unsigned int probetype, unsigned char chop, unsigned char cprobe, uint32_t flowlabel){ - struct tcp_hdr *tcp; - struct udp_hdr *udp; - struct ah_hdr *ah; - struct esp_hdr *esp; - struct icmp6_hdr *icmp6; - - ptr=startofprefixes; - ipv6->ip6_hlim= chop+1; - - if(flowlabelr_f) - ipv6->ip6_flow= (ipv6->ip6_flow & htonl(0xfff00000)) | htonl(flowlabel); - - if(probetype == PROBE_ICMP6_ECHO){ - *prev_nh = IPPROTO_ICMPV6; - - if( (ptr+sizeof(struct icmp6_hdr)) > (v6buffer+ idata->max_packet_size)){ - puts("Packet too large while inserting ICMPv6 header (should be using Frag. option?)"); - exit(EXIT_FAILURE); - } - - icmp6= (struct icmp6_hdr *) ptr; - - icmp6->icmp6_type = ICMP6_ECHO_REQUEST; - icmp6->icmp6_code = 0; - /* - The Identifier field (icmp6_data16[0]) contains the PID of this process (as usual - for the ping(8) tool. The "Sequence Number" field (icmp6_data16[1]) encodes the original - Hop Limit and the probe number. The probe number is encoded in the upper 8 bits, while the - hop limit is encoded in the lower 8 bits. - */ - icmp6->icmp6_data16[0]= htons(pid); - icmp6->icmp6_data16[1]= htons( ((uint16_t) chop << 8) + (cprobe & 0xff) ); - ptr += sizeof(struct icmp6_hdr); - - if(rhbytes){ - rhleft=rhbytes; - - if( (ptr + rhleft) > (v6buffer+ idata->max_packet_size)){ - puts("Packet Too Large while inserting TCP segment"); - exit(EXIT_FAILURE); - } - - while(rhleft>=4){ - *(uint32_t *)ptr = random(); - ptr += sizeof(uint32_t); - rhleft -= sizeof(uint32_t); - } - - while(rhleft>0){ - *(uint8_t *) ptr= (uint8_t) random(); - ptr++; - rhleft--; - } - } - - icmp6->icmp6_cksum = 0; - icmp6->icmp6_cksum = in_chksum(v6buffer, icmp6, ptr-((unsigned char *)icmp6), IPPROTO_ICMPV6); - } - else if(probetype == PROBE_TCP){ - *prev_nh = IPPROTO_TCP; - - if( (ptr+sizeof(struct tcp_hdr)) > (v6buffer+ idata->max_packet_size)){ - puts("Packet too large while inserting ICMPv6 header (should be using Frag. option?)"); - exit(EXIT_FAILURE); - } - - tcp= (struct tcp_hdr *) ptr; - ptr+= sizeof(struct tcp_hdr); - memset(tcp, 0, sizeof(struct tcp_hdr)); - - /* - For TCP, we encode the probe number and the current Hop Limit in the TCP Source Port. - The probe number is encoded in the upper eight bits, while the current Hop Limit is - encoded in the lower eight bits. A constant "offset" is employed for encoding the probe - number, such that the resulting Source Port falls into what is typically known as the - dynamic ports range (say, ports larger than 50000). - */ - tcp->th_sport= htons( (((uint16_t) chop + PROBE_PORT_OFFSET) << 8) + cprobe); - tcp->th_dport= htons(dstport); - tcp->th_seq = htonl(tcpseq); - - /* - If no flags were specified, we set the ACK bit, since all TCP segments other than SYNs - are required to have the ACK bit set. - */ - tcp->th_ack= htonl((tcpflags & TH_ACK)?random():0); - tcp->th_flags= tcpflags; - tcp->th_urp= htons(0); - tcp->th_win= htons((random() + 1024) & 0x7f00); - tcp->th_off= MIN_TCP_HLEN >> 2; - - if(rhbytes){ - rhleft=rhbytes; - - if( (ptr + rhleft) > (v6buffer+ idata->max_packet_size)){ - puts("Packet Too Large while inserting TCP segment"); - exit(EXIT_FAILURE); - } - - while(rhleft>=4){ - *(uint32_t *)ptr = random(); - ptr += sizeof(uint32_t); - rhleft -= sizeof(uint32_t); - } - - while(rhleft>0){ - *(uint8_t *) ptr= (uint8_t) random(); - ptr++; - rhleft--; - } - } - - ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); - tcp->th_sum= 0; - tcp->th_sum = in_chksum(v6buffer, tcp, ptr-((unsigned char *)tcp), IPPROTO_TCP); - } - else if(probetype == PROBE_UDP){ - *prev_nh = IPPROTO_UDP; - - if( (ptr+sizeof(struct udp_hdr)) > (v6buffer+ idata->max_packet_size)){ - puts("Packet too large while inserting ICMPv6 header (should be using Frag. option?)"); - exit(EXIT_FAILURE); - } - - udp= (struct udp_hdr *) ptr; - ptr+= sizeof(struct udp_hdr); - memset(udp, 0, sizeof(struct udp_hdr)); - - /* - For UDP, we encode the current probe number and the current Hop Limit as fr TCP. - Namely, we encode the probe number and the current Hop Limit in the TCP Source Port. - The probe number is encoded in the upper eight bits, while the current Hop Limit is - encoded in the lower eight bits. A constant "offset" is employed for encoding the probe - number, such that the resulting Source Port falls into what is typically known as the - dynamic ports range (say, ports larger than 50000). - */ - - udp->uh_sport= htons( (((uint16_t) chop + PROBE_PORT_OFFSET) << 8) + cprobe); - - udp->uh_dport= htons(dstport + (chop*3)+cprobe); - - if(rhbytes){ - rhleft=rhbytes; - - if( (ptr + rhleft) > (v6buffer+ idata->max_packet_size)){ - puts("Packet Too Large while inserting TCP segment"); - exit(EXIT_FAILURE); - } - - while(rhleft>=4){ - *(uint32_t *)ptr = random(); - ptr += sizeof(uint32_t); - rhleft -= sizeof(uint32_t); - } - - while(rhleft>0){ - *(uint8_t *) ptr= (uint8_t) random(); - ptr++; - rhleft--; - } - } - - ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); - udp->uh_ulen= htons(ptr - (unsigned char *) udp); - udp->uh_sum=0; - udp->uh_sum = in_chksum(v6buffer, udp, ptr-((unsigned char *)udp), IPPROTO_UDP); - } - - else if(probetype == PROBE_AH){ - *prev_nh = IPPROTO_AH; - - if( (ptr+sizeof(struct ah_hdr)) > (v6buffer+ idata->max_packet_size)){ - puts("Packet too large while inserting AH header (should be using Frag. option?)"); - exit(EXIT_FAILURE); - } - - ah= (struct ah_hdr *) ptr; - ptr+= sizeof(struct ah_hdr); - memset(ah, 0, sizeof(struct ah_hdr)); - - /* - For AH, we set the SPI to a random value, and encode the probe numbers in the SEQ - */ - - ah->ah_spi= spi; - ah->ah_seq= htonl( (((uint32_t) chop) << 16) + cprobe); - - ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); - ah->ah_nxt= IPPROTO_TCP; /* XXX: This should be changed */ - ah->ah_len= sizeof(struct ah_hdr) / 4; /* XXX: Should be modified if we relax the AH format */ - } - - else if(probetype == PROBE_ESP){ - *prev_nh = IPPROTO_ESP; - - if( (ptr+sizeof(struct esp_hdr)) > (v6buffer+ idata->max_packet_size)){ - puts("Packet too large while inserting ESP header (should be using Frag. option?)"); - exit(EXIT_FAILURE); - } - - esp= (struct esp_hdr *) ptr; - ptr+= sizeof(struct esp_hdr); - memset(esp, 0, sizeof(struct esp_hdr)); - - /* - For ESP, we set the SPI to a random value, and encode the probe numbers in the SEQ - */ - - esp->esp_spi= spi; - esp->esp_seq= htonl( (((uint32_t) chop) << 16) + cprobe); - - ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); - } - - if(!idata->fragh_f){ - ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); - - if((nw=pcap_inject(idata->pfd, buffer, ptr - buffer)) == -1){ - printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); - return(-1); - } - - if(nw != (ptr-buffer)){ - printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", \ - nw, (LUI) (ptr-buffer)); - return(-1); - } - - return(0); - } - else{ - ptrend= ptr; - ptr= fragpart; - fptr = fragbuffer; - fipv6 = (struct ip6_hdr *) (fragbuffer + idata->linkhsize); - fptrend = fptr + idata->linkhsize+MIN_IPV6_HLEN+MAX_IPV6_PAYLOAD; - memcpy(fptr, buffer, fragpart-buffer); - fptr = fptr + (fragpart-buffer); - - if( (fptr+FRAG_HDR_SIZE)> fptrend){ - puts("Unfragmentable Part is Too Large"); - exit(EXIT_FAILURE); - } - - memcpy(fptr, (char *) &fraghdr, FRAG_HDR_SIZE); - fh= (struct ip6_frag *) fptr; - fh->ip6f_ident=random(); - startoffragment = fptr + FRAG_HDR_SIZE; - - /* - * Check that the selected fragment size is not larger than the largest - * fragment size that can be sent - */ - - if(nfrags > (fptrend - fptr)) - nfrags= (fptrend-fptr); - - m=IP6F_MORE_FRAG; - - while((ptr< ptrend) && m==IP6F_MORE_FRAG){ - fptr= startoffragment; - - if( (ptrend-ptr) <= nfrags){ - fragsize= ptrend-ptr; - m=0; - } - else{ - fragsize = (nfrags + 7) & ntohs(IP6F_OFF_MASK); - } - - memcpy(fptr, ptr, fragsize); - fh->ip6f_offlg = (htons(ptr-fragpart) & IP6F_OFF_MASK) | m; - ptr+=fragsize; - fptr+=fragsize; - - fipv6->ip6_plen = htons((fptr - fragbuffer) - MIN_IPV6_HLEN - idata->linkhsize); - - if((nw=pcap_inject(idata->pfd, fragbuffer, fptr - fragbuffer)) == -1){ - printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); - exit(EXIT_FAILURE); - } - - if(nw != (fptr- fragbuffer)){ - printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", \ - nw, (LUI) (ptr-buffer)); - exit(EXIT_FAILURE); - } - } /* Sending fragments */ - - return(0); - } /* Sending fragmented datagram */ +int send_probe(struct iface_data *idata, unsigned int probetype, unsigned char chop, unsigned char cprobe, + uint32_t flowlabel) { + struct tcp_hdr *tcp; + struct udp_hdr *udp; + struct ah_hdr *ah; + struct esp_hdr *esp; + struct icmp6_hdr *icmp6; + + ptr = startofprefixes; + ipv6->ip6_hlim = chop + 1; + + if (flowlabelr_f) + ipv6->ip6_flow = (ipv6->ip6_flow & htonl(0xfff00000)) | htonl(flowlabel); + + if (probetype == PROBE_ICMP6_ECHO) { + *prev_nh = IPPROTO_ICMPV6; + + if ((ptr + sizeof(struct icmp6_hdr)) > (v6buffer + idata->max_packet_size)) { + puts("Packet too large while inserting ICMPv6 header (should be using Frag. option?)"); + exit(EXIT_FAILURE); + } + + icmp6 = (struct icmp6_hdr *)ptr; + + icmp6->icmp6_type = ICMP6_ECHO_REQUEST; + icmp6->icmp6_code = 0; + /* + The Identifier field (icmp6_data16[0]) contains the PID of this process (as usual + for the ping(8) tool. The "Sequence Number" field (icmp6_data16[1]) encodes the original + Hop Limit and the probe number. The probe number is encoded in the upper 8 bits, while the + hop limit is encoded in the lower 8 bits. + */ + icmp6->icmp6_data16[0] = htons(pid); + icmp6->icmp6_data16[1] = htons(((uint16_t)chop << 8) + (cprobe & 0xff)); + ptr += sizeof(struct icmp6_hdr); + + if (rhbytes) { + rhleft = rhbytes; + + if ((ptr + rhleft) > (v6buffer + idata->max_packet_size)) { + puts("Packet Too Large while inserting TCP segment"); + exit(EXIT_FAILURE); + } + + while (rhleft >= 4) { + *(uint32_t *)ptr = random(); + ptr += sizeof(uint32_t); + rhleft -= sizeof(uint32_t); + } + + while (rhleft > 0) { + *(uint8_t *)ptr = (uint8_t)random(); + ptr++; + rhleft--; + } + } + + icmp6->icmp6_cksum = 0; + icmp6->icmp6_cksum = in_chksum(v6buffer, icmp6, ptr - ((unsigned char *)icmp6), IPPROTO_ICMPV6); + } + else if (probetype == PROBE_TCP) { + *prev_nh = IPPROTO_TCP; + + if ((ptr + sizeof(struct tcp_hdr)) > (v6buffer + idata->max_packet_size)) { + puts("Packet too large while inserting ICMPv6 header (should be using Frag. option?)"); + exit(EXIT_FAILURE); + } + + tcp = (struct tcp_hdr *)ptr; + ptr += sizeof(struct tcp_hdr); + memset(tcp, 0, sizeof(struct tcp_hdr)); + + /* + For TCP, we encode the probe number and the current Hop Limit in the TCP Source Port. + The probe number is encoded in the upper eight bits, while the current Hop Limit is + encoded in the lower eight bits. A constant "offset" is employed for encoding the probe + number, such that the resulting Source Port falls into what is typically known as the + dynamic ports range (say, ports larger than 50000). + */ + tcp->th_sport = htons((((uint16_t)chop + PROBE_PORT_OFFSET) << 8) + cprobe); + tcp->th_dport = htons(dstport); + tcp->th_seq = htonl(tcpseq); + + /* + If no flags were specified, we set the ACK bit, since all TCP segments other than SYNs + are required to have the ACK bit set. + */ + tcp->th_ack = htonl((tcpflags & TH_ACK) ? random() : 0); + tcp->th_flags = tcpflags; + tcp->th_urp = htons(0); + tcp->th_win = htons((random() + 1024) & 0x7f00); + tcp->th_off = MIN_TCP_HLEN >> 2; + + if (rhbytes) { + rhleft = rhbytes; + + if ((ptr + rhleft) > (v6buffer + idata->max_packet_size)) { + puts("Packet Too Large while inserting TCP segment"); + exit(EXIT_FAILURE); + } + + while (rhleft >= 4) { + *(uint32_t *)ptr = random(); + ptr += sizeof(uint32_t); + rhleft -= sizeof(uint32_t); + } + + while (rhleft > 0) { + *(uint8_t *)ptr = (uint8_t)random(); + ptr++; + rhleft--; + } + } + + ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); + tcp->th_sum = 0; + tcp->th_sum = in_chksum(v6buffer, tcp, ptr - ((unsigned char *)tcp), IPPROTO_TCP); + } + else if (probetype == PROBE_UDP) { + *prev_nh = IPPROTO_UDP; + + if ((ptr + sizeof(struct udp_hdr)) > (v6buffer + idata->max_packet_size)) { + puts("Packet too large while inserting ICMPv6 header (should be using Frag. option?)"); + exit(EXIT_FAILURE); + } + + udp = (struct udp_hdr *)ptr; + ptr += sizeof(struct udp_hdr); + memset(udp, 0, sizeof(struct udp_hdr)); + + /* + For UDP, we encode the current probe number and the current Hop Limit as fr TCP. + Namely, we encode the probe number and the current Hop Limit in the TCP Source Port. + The probe number is encoded in the upper eight bits, while the current Hop Limit is + encoded in the lower eight bits. A constant "offset" is employed for encoding the probe + number, such that the resulting Source Port falls into what is typically known as the + dynamic ports range (say, ports larger than 50000). + */ + + udp->uh_sport = htons((((uint16_t)chop + PROBE_PORT_OFFSET) << 8) + cprobe); + + udp->uh_dport = htons(dstport + (chop * 3) + cprobe); + + if (rhbytes) { + rhleft = rhbytes; + + if ((ptr + rhleft) > (v6buffer + idata->max_packet_size)) { + puts("Packet Too Large while inserting TCP segment"); + exit(EXIT_FAILURE); + } + + while (rhleft >= 4) { + *(uint32_t *)ptr = random(); + ptr += sizeof(uint32_t); + rhleft -= sizeof(uint32_t); + } + + while (rhleft > 0) { + *(uint8_t *)ptr = (uint8_t)random(); + ptr++; + rhleft--; + } + } + + ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); + udp->uh_ulen = htons(ptr - (unsigned char *)udp); + udp->uh_sum = 0; + udp->uh_sum = in_chksum(v6buffer, udp, ptr - ((unsigned char *)udp), IPPROTO_UDP); + } + + else if (probetype == PROBE_AH) { + *prev_nh = IPPROTO_AH; + + if ((ptr + sizeof(struct ah_hdr)) > (v6buffer + idata->max_packet_size)) { + puts("Packet too large while inserting AH header (should be using Frag. option?)"); + exit(EXIT_FAILURE); + } + + ah = (struct ah_hdr *)ptr; + ptr += sizeof(struct ah_hdr); + memset(ah, 0, sizeof(struct ah_hdr)); + + /* + For AH, we set the SPI to a random value, and encode the probe numbers in the SEQ + */ + + ah->ah_spi = spi; + ah->ah_seq = htonl((((uint32_t)chop) << 16) + cprobe); + + ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); + ah->ah_nxt = IPPROTO_TCP; /* XXX: This should be changed */ + ah->ah_len = sizeof(struct ah_hdr) / 4; /* XXX: Should be modified if we relax the AH format */ + } + + else if (probetype == PROBE_ESP) { + *prev_nh = IPPROTO_ESP; + + if ((ptr + sizeof(struct esp_hdr)) > (v6buffer + idata->max_packet_size)) { + puts("Packet too large while inserting ESP header (should be using Frag. option?)"); + exit(EXIT_FAILURE); + } + + esp = (struct esp_hdr *)ptr; + ptr += sizeof(struct esp_hdr); + memset(esp, 0, sizeof(struct esp_hdr)); + + /* + For ESP, we set the SPI to a random value, and encode the probe numbers in the SEQ + */ + + esp->esp_spi = spi; + esp->esp_seq = htonl((((uint32_t)chop) << 16) + cprobe); + + ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); + } + + if (!idata->fragh_f) { + ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); + + if ((nw = pcap_inject(idata->pfd, buffer, ptr - buffer)) == -1) { + printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); + return (-1); + } + + if (nw != (ptr - buffer)) { + printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, (LUI)(ptr - buffer)); + return (-1); + } + + return (0); + } + else { + ptrend = ptr; + ptr = fragpart; + fptr = fragbuffer; + fipv6 = (struct ip6_hdr *)(fragbuffer + idata->linkhsize); + fptrend = fptr + idata->linkhsize + MIN_IPV6_HLEN + MAX_IPV6_PAYLOAD; + memcpy(fptr, buffer, fragpart - buffer); + fptr = fptr + (fragpart - buffer); + + if ((fptr + FRAG_HDR_SIZE) > fptrend) { + puts("Unfragmentable Part is Too Large"); + exit(EXIT_FAILURE); + } + + memcpy(fptr, (char *)&fraghdr, FRAG_HDR_SIZE); + fh = (struct ip6_frag *)fptr; + fh->ip6f_ident = random(); + startoffragment = fptr + FRAG_HDR_SIZE; + + /* + * Check that the selected fragment size is not larger than the largest + * fragment size that can be sent + */ + + if (nfrags > (fptrend - fptr)) + nfrags = (fptrend - fptr); + + m = IP6F_MORE_FRAG; + + while ((ptr < ptrend) && m == IP6F_MORE_FRAG) { + fptr = startoffragment; + + if ((ptrend - ptr) <= nfrags) { + fragsize = ptrend - ptr; + m = 0; + } + else { + fragsize = (nfrags + 7) & ntohs(IP6F_OFF_MASK); + } + + memcpy(fptr, ptr, fragsize); + fh->ip6f_offlg = (htons(ptr - fragpart) & IP6F_OFF_MASK) | m; + ptr += fragsize; + fptr += fragsize; + + fipv6->ip6_plen = htons((fptr - fragbuffer) - MIN_IPV6_HLEN - idata->linkhsize); + + if ((nw = pcap_inject(idata->pfd, fragbuffer, fptr - fragbuffer)) == -1) { + printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); + exit(EXIT_FAILURE); + } + + if (nw != (fptr - fragbuffer)) { + printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, (LUI)(ptr - buffer)); + exit(EXIT_FAILURE); + } + } /* Sending fragments */ + + return (0); + } /* Sending fragmented datagram */ } - diff --git a/tools/path6.h b/tools/path6.h index 0d96975..d61a1b5 100644 --- a/tools/path6.h +++ b/tools/path6.h @@ -3,23 +3,21 @@ * */ +#define PROBE_ICMP6_ECHO 1 +#define PROBE_TCP 3 +#define PROBE_UDP 4 +#define PROBE_AH 5 +#define PROBE_ESP 6 -#define PROBE_ICMP6_ECHO 1 -#define PROBE_TCP 3 -#define PROBE_UDP 4 -#define PROBE_AH 5 -#define PROBE_ESP 6 +#define PROBE_PORT_OFFSET 0x00c4 +#define PROBE_TIMEOUT 4 -#define PROBE_PORT_OFFSET 0x00c4 -#define PROBE_TIMEOUT 4 - - -struct probe{ - unsigned char sent; - unsigned char received; - uint32_t rflow; - uint32_t sflow; - struct timeval rtstamp; - struct timeval ststamp; - struct in6_addr srcaddr; +struct probe { + unsigned char sent; + unsigned char received; + uint32_t rflow; + uint32_t sflow; + struct timeval rtstamp; + struct timeval ststamp; + struct in6_addr srcaddr; }; diff --git a/tools/ra6.c b/tools/ra6.c index 08f483e..d24f6bb 100644 --- a/tools/ra6.c +++ b/tools/ra6.c @@ -1,5 +1,5 @@ /* - * ra6: A security assessment tool for attack vectors based on + * ra6: A security assessment tool for attack vectors based on * ICMPv6 Router Advertisement messages * * Copyright (C) 2009-2020 Fernando Gont @@ -19,1380 +19,1355 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - * + * * Build with: make ra6 - * + * * The libpcap library must be previously installed on your system. * * Please send any bug reports to Fernando Gont */ - -#include #include -#include #include +#include +#include +#include #include +#include #include -#include #include -#include #include -#include #include +#include +#include #include #include +#include #include -#include #include -#include -#include "ra6.h" #include "ipv6toolkit.h" #include "libipv6.h" +#include "ra6.h" -void init_packet_data(struct iface_data *); -void send_packet(struct iface_data *, const u_char *); -void usage(void); -void print_help(void); -void print_attack_info(struct iface_data *); - -struct pcap_pkthdr *pkthdr; -const u_char *pktdata; -struct in6_addr *pkt_ipv6addr; -bpf_u_int32 my_netmask; -bpf_u_int32 my_ip; -struct bpf_program pcap_filter; -char dev[64], errbuf[PCAP_ERRBUF_SIZE]; -char all_nodes_addr[]= ALL_NODES_MULTICAST_ADDR; - -unsigned char buffer[ETHER_HDR_LEN+MIN_IPV6_HLEN+MAX_IPV6_PAYLOAD]; -unsigned char fragbuffer[ETHER_HDR_LEN+MIN_IPV6_HLEN+MAX_IPV6_PAYLOAD]; -unsigned char *v6buffer, *ptr, *startofprefixes, *ptrhdr, *ptrhdrend; -unsigned char *fragpart, *fptr, *fptrend, *ptrend; - -struct ip6_hdr *ipv6, *pkt_ipv6, *fipv6; -struct nd_router_advert *ra; -struct nd_router_solicit *pkt_rs; -struct nd_opt_rdnss_l *dnsopt; -struct ether_header *ethernet, *pkt_ether; -struct nd_opt_mtu *mtuopt; -struct nd_opt_slla *sllaopt; -struct nd_opt_prefix_info *prefixopt; -struct nd_opt_route_info_l *routeopt; - -char *lasts, *rpref, *endptr; - -int nw; -uint16_t lifetime; -uint32_t reachable; -uint32_t retrans; -uint8_t curhop, hoplimit, prefbits=0; -int preference=0; -unsigned int nprefixes=0, nroutes=0, nfrags=0; -unsigned int hdrlen, ndstopthdr=0, nhbhopthdr=0, ndstoptuhdr=0; -unsigned int dstopthdrs, dstoptuhdrs, hbhopthdrs; -unsigned char hbhopthdr_f=0, dstoptuhdr_f=0, dstopthdr_f=0; -unsigned char *dstopthdr[MAX_DST_OPT_HDR], *dstoptuhdr[MAX_DST_OPT_U_HDR]; -unsigned char *hbhopthdr[MAX_HBH_OPT_HDR]; -unsigned int dstopthdrlen[MAX_DST_OPT_HDR], dstoptuhdrlen[MAX_DST_OPT_U_HDR]; -unsigned int hbhopthdrlen[MAX_HBH_OPT_HDR], nfrags, fragsize, m, pad; -unsigned char *prev_nh, *startoffragment; -struct ip6_frag fraghdr, *fh; - -unsigned long ul_res, ul_val; -unsigned int i, j, startrand, sources, nsources, prefixes, routes, mtus; -unsigned int nfloodp, nfloodr, endrand; -unsigned int nfloodda, nflooddoa, nsleep; -uint32_t mask; -uint8_t prefixlen[MAX_PREFIX_OPTION]; -uint32_t prefixvalid[MAX_PREFIX_OPTION]; -uint32_t prefixpref[MAX_PREFIX_OPTION]; -struct in6_addr prefix[MAX_PREFIX_OPTION]; -uint8_t prefixflags[MAX_PREFIX_OPTION]; - -struct in6_addr route[MAX_ROUTE_OPTION]; -uint8_t routelen[MAX_ROUTE_OPTION]; -uint32_t routelife[MAX_ROUTE_OPTION]; -uint8_t routepref[MAX_ROUTE_OPTION]; - -struct in6_addr rdnss[MAX_RDNSS_OPTION][MAX_RDNSS_OPT_ADDRS]; -uint32_t rdnsslife[MAX_RDNSS_OPTION]; -unsigned int nrdnss=0, dnsopts; -unsigned int nrdnssopt[MAX_RDNSS_OPTION]; -int smaxaddrs; - -uint16_t mtu[MAX_MTU_OPTION]; -unsigned int nmtu=0; - -struct ether_addr linkaddr[MAX_SLLA_OPTION]; -unsigned int nlinkaddr=0, linkaddrs; - -char *pref; -char *preflen; -char *prefvalid; -char *prefpref; -char *prefflags; -char *charptr; - -char plinkaddr[ETHER_ADDR_PLEN], phsrcaddr[ETHER_ADDR_PLEN], phdstaddr[ETHER_ADDR_PLEN]; -char psrcaddr[INET6_ADDRSTRLEN], pdstaddr[INET6_ADDRSTRLEN], pprefix[INET6_ADDRSTRLEN]; -char pv6addr[INET6_ADDRSTRLEN]; - +void init_packet_data(struct iface_data *); +void send_packet(struct iface_data *, const u_char *); +void usage(void); +void print_help(void); +void print_attack_info(struct iface_data *); + +struct pcap_pkthdr *pkthdr; +const u_char *pktdata; +struct in6_addr *pkt_ipv6addr; +bpf_u_int32 my_netmask; +bpf_u_int32 my_ip; +struct bpf_program pcap_filter; +char dev[64], errbuf[PCAP_ERRBUF_SIZE]; +char all_nodes_addr[] = ALL_NODES_MULTICAST_ADDR; + +unsigned char buffer[ETHER_HDR_LEN + MIN_IPV6_HLEN + MAX_IPV6_PAYLOAD]; +unsigned char fragbuffer[ETHER_HDR_LEN + MIN_IPV6_HLEN + MAX_IPV6_PAYLOAD]; +unsigned char *v6buffer, *ptr, *startofprefixes, *ptrhdr, *ptrhdrend; +unsigned char *fragpart, *fptr, *fptrend, *ptrend; + +struct ip6_hdr *ipv6, *pkt_ipv6, *fipv6; +struct nd_router_advert *ra; +struct nd_router_solicit *pkt_rs; +struct nd_opt_rdnss_l *dnsopt; +struct ether_header *ethernet, *pkt_ether; +struct nd_opt_mtu *mtuopt; +struct nd_opt_slla *sllaopt; +struct nd_opt_prefix_info *prefixopt; +struct nd_opt_route_info_l *routeopt; + +char *lasts, *rpref, *endptr; + +int nw; +uint16_t lifetime; +uint32_t reachable; +uint32_t retrans; +uint8_t curhop, hoplimit, prefbits = 0; +int preference = 0; +unsigned int nprefixes = 0, nroutes = 0, nfrags = 0; +unsigned int hdrlen, ndstopthdr = 0, nhbhopthdr = 0, ndstoptuhdr = 0; +unsigned int dstopthdrs, dstoptuhdrs, hbhopthdrs; +unsigned char hbhopthdr_f = 0, dstoptuhdr_f = 0, dstopthdr_f = 0; +unsigned char *dstopthdr[MAX_DST_OPT_HDR], *dstoptuhdr[MAX_DST_OPT_U_HDR]; +unsigned char *hbhopthdr[MAX_HBH_OPT_HDR]; +unsigned int dstopthdrlen[MAX_DST_OPT_HDR], dstoptuhdrlen[MAX_DST_OPT_U_HDR]; +unsigned int hbhopthdrlen[MAX_HBH_OPT_HDR], nfrags, fragsize, m, pad; +unsigned char *prev_nh, *startoffragment; +struct ip6_frag fraghdr, *fh; + +unsigned long ul_res, ul_val; +unsigned int i, j, startrand, sources, nsources, prefixes, routes, mtus; +unsigned int nfloodp, nfloodr, endrand; +unsigned int nfloodda, nflooddoa, nsleep; +uint32_t mask; +uint8_t prefixlen[MAX_PREFIX_OPTION]; +uint32_t prefixvalid[MAX_PREFIX_OPTION]; +uint32_t prefixpref[MAX_PREFIX_OPTION]; +struct in6_addr prefix[MAX_PREFIX_OPTION]; +uint8_t prefixflags[MAX_PREFIX_OPTION]; + +struct in6_addr route[MAX_ROUTE_OPTION]; +uint8_t routelen[MAX_ROUTE_OPTION]; +uint32_t routelife[MAX_ROUTE_OPTION]; +uint8_t routepref[MAX_ROUTE_OPTION]; + +struct in6_addr rdnss[MAX_RDNSS_OPTION][MAX_RDNSS_OPT_ADDRS]; +uint32_t rdnsslife[MAX_RDNSS_OPTION]; +unsigned int nrdnss = 0, dnsopts; +unsigned int nrdnssopt[MAX_RDNSS_OPTION]; +int smaxaddrs; + +uint16_t mtu[MAX_MTU_OPTION]; +unsigned int nmtu = 0; + +struct ether_addr linkaddr[MAX_SLLA_OPTION]; +unsigned int nlinkaddr = 0, linkaddrs; + +char *pref; +char *preflen; +char *prefvalid; +char *prefpref; +char *prefflags; +char *charptr; + +char plinkaddr[ETHER_ADDR_PLEN], phsrcaddr[ETHER_ADDR_PLEN], phdstaddr[ETHER_ADDR_PLEN]; +char psrcaddr[INET6_ADDRSTRLEN], pdstaddr[INET6_ADDRSTRLEN], pprefix[INET6_ADDRSTRLEN]; +char pv6addr[INET6_ADDRSTRLEN]; /* Flags used for option processing */ -uint8_t managed_f=0, other_f=0, home_f=0, proxy_f=0; -unsigned char mtuopt_f=0, sllopt_f=0, sllopta_f=0, prefopt_f=0, hoplimit_f=0; -unsigned char listen_f = 0, floodp_f=0, floods_f=0, floodr_f=0, multicastdst_f=0, floodd_f=0; -unsigned char loop_f=0, sleep_f=0, accepted_f=0, newdata_f=0; +uint8_t managed_f = 0, other_f = 0, home_f = 0, proxy_f = 0; +unsigned char mtuopt_f = 0, sllopt_f = 0, sllopta_f = 0, prefopt_f = 0, hoplimit_f = 0; +unsigned char listen_f = 0, floodp_f = 0, floods_f = 0, floodr_f = 0, multicastdst_f = 0, floodd_f = 0; +unsigned char loop_f = 0, sleep_f = 0, accepted_f = 0, newdata_f = 0; + +struct iface_data idata; +struct filters filters; + +int main(int argc, char **argv) { + extern char *optarg; + int r, sel, rtepref; + fd_set sset, rset; +#if defined(sun) || defined(__sun) || defined(__linux__) + struct timeval timeout; +#endif + struct target_ipv6 targetipv6; + + static struct option longopts[] = {{"interface", required_argument, 0, 'i'}, + {"src-addr", required_argument, 0, 's'}, + {"dst-addr", required_argument, 0, 'd'}, + {"hop-limit", required_argument, 0, 'A'}, + {"dst-opt-hdr", required_argument, 0, 'u'}, + {"dst-opt-u-hdr", required_argument, 0, 'U'}, + {"hbh-opt-hdr", required_argument, 0, 'H'}, + {"frag-hdr", required_argument, 0, 'y'}, + {"curhop", required_argument, 0, 'c'}, + {"lifetime", required_argument, 0, 't'}, + {"reachable", required_argument, 0, 'r'}, + {"retrans", required_argument, 0, 'x'}, + {"managed", no_argument, 0, 'm'}, + {"other", no_argument, 0, 'o'}, + {"home-agent", no_argument, 0, 'a'}, + {"nd-proxy", no_argument, 0, 'q'}, + {"preference", required_argument, 0, 'p'}, + {"src-link-opt", required_argument, 0, 'E'}, + {"add-slla-opt", no_argument, 0, 'e'}, + {"prefix-opt", required_argument, 0, 'P'}, + {"route-opt", required_argument, 0, 'R'}, + {"mtu-opt", required_argument, 0, 'M'}, + {"rdnss-opt", required_argument, 0, 'N'}, + {"link-src-addr", required_argument, 0, 'S'}, + {"link-dst-addr", required_argument, 0, 'D'}, + {"flood-prefixes", required_argument, 0, 'f'}, + {"flood-sources", required_argument, 0, 'F'}, + {"flood-routes", required_argument, 0, 'w'}, + {"flood-dns", required_argument, 0, 'W'}, + {"block-src-addr", required_argument, 0, 'j'}, + {"block-dst-addr", required_argument, 0, 'k'}, + {"block-link-src-addr", required_argument, 0, 'J'}, + {"block-link-dst-addr", required_argument, 0, 'K'}, + {"accept-src-addr", required_argument, 0, 'b'}, + {"accept-dst-addr", required_argument, 0, 'g'}, + {"accept-link-src-addr", required_argument, 0, 'B'}, + {"accept-link-dst-addr", required_argument, 0, 'G'}, + {"loop", no_argument, 0, 'l'}, + {"sleep", required_argument, 0, 'z'}, + {"listen", no_argument, 0, 'L'}, + {"verbose", no_argument, 0, 'v'}, + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0}}; + + const char shortopts[] = "i:s:d:A:u:U:H:y:c:t:r:x:moaqp:E:eP:R:M:N:S:D:f:F:w:W:lz:Lj:k:J:K:b:g:B:G:vh"; + char option; + + if (argc <= 1) { + usage(); + exit(EXIT_FAILURE); + } + + hoplimit = 255; + curhop = 255; + prefbits = DEFAULT_ROUTER_PREFERENCE; + preference = prefbits >> 3; + lifetime = DEFAULT_ROUTER_LIFETIME; + reachable = DEFAULT_ROUTER_REACHABLE; + retrans = DEFAULT_ROUTER_RETRANS; + srandom(time(NULL)); + + /* Initialize filters structure */ + if (init_filters(&filters) == -1) { + puts("Error initializing internal data structure"); + exit(EXIT_FAILURE); + } -struct iface_data idata; -struct filters filters; + if (init_iface_data(&idata) == FAILURE) { + puts("Error initializing internal data structure"); + exit(EXIT_FAILURE); + } + while ((r = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { + option = r; -int main(int argc, char **argv){ - extern char *optarg; - int r, sel, rtepref; - fd_set sset, rset; -#if defined(sun) || defined(__sun) || defined(__linux__) - struct timeval timeout; -#endif - struct target_ipv6 targetipv6; - - static struct option longopts[] = { - {"interface", required_argument, 0, 'i'}, - {"src-addr", required_argument, 0, 's'}, - {"dst-addr", required_argument, 0, 'd'}, - {"hop-limit", required_argument, 0, 'A'}, - {"dst-opt-hdr", required_argument, 0, 'u'}, - {"dst-opt-u-hdr", required_argument, 0, 'U'}, - {"hbh-opt-hdr", required_argument, 0, 'H'}, - {"frag-hdr", required_argument, 0, 'y'}, - {"curhop", required_argument, 0, 'c'}, - {"lifetime", required_argument, 0, 't'}, - {"reachable", required_argument, 0, 'r'}, - {"retrans", required_argument, 0, 'x'}, - {"managed", no_argument, 0, 'm'}, - {"other", no_argument, 0, 'o'}, - {"home-agent", no_argument, 0, 'a'}, - {"nd-proxy", no_argument, 0, 'q'}, - {"preference", required_argument, 0, 'p'}, - {"src-link-opt", required_argument, 0, 'E'}, - {"add-slla-opt", no_argument, 0, 'e'}, - {"prefix-opt", required_argument, 0, 'P'}, - {"route-opt", required_argument, 0, 'R'}, - {"mtu-opt", required_argument, 0, 'M'}, - {"rdnss-opt", required_argument, 0, 'N'}, - {"link-src-addr", required_argument, 0, 'S'}, - {"link-dst-addr", required_argument, 0, 'D'}, - {"flood-prefixes", required_argument, 0, 'f'}, - {"flood-sources", required_argument, 0, 'F'}, - {"flood-routes", required_argument, 0, 'w'}, - {"flood-dns", required_argument, 0, 'W'}, - {"block-src-addr", required_argument, 0, 'j'}, - {"block-dst-addr", required_argument, 0, 'k'}, - {"block-link-src-addr", required_argument, 0, 'J'}, - {"block-link-dst-addr", required_argument, 0, 'K'}, - {"accept-src-addr", required_argument, 0, 'b'}, - {"accept-dst-addr", required_argument, 0, 'g'}, - {"accept-link-src-addr", required_argument, 0, 'B'}, - {"accept-link-dst-addr", required_argument, 0, 'G'}, - {"loop", no_argument, 0, 'l'}, - {"sleep", required_argument, 0, 'z'}, - {"listen", no_argument, 0, 'L'}, - {"verbose", no_argument, 0, 'v'}, - {"help", no_argument, 0, 'h'}, - {0, 0, 0, 0 } - }; - - const char shortopts[]= "i:s:d:A:u:U:H:y:c:t:r:x:moaqp:E:eP:R:M:N:S:D:f:F:w:W:lz:Lj:k:J:K:b:g:B:G:vh"; - char option; - - if(argc<=1){ - usage(); - exit(EXIT_FAILURE); - } - - hoplimit=255; - curhop=255; - prefbits= DEFAULT_ROUTER_PREFERENCE; - preference= prefbits>>3; - lifetime= DEFAULT_ROUTER_LIFETIME; - reachable= DEFAULT_ROUTER_REACHABLE; - retrans= DEFAULT_ROUTER_RETRANS; - srandom(time(NULL)); - - /* Initialize filters structure */ - if(init_filters(&filters) == -1){ - puts("Error initializing internal data structure"); - exit(EXIT_FAILURE); - } - - if(init_iface_data(&idata) == FAILURE){ - puts("Error initializing internal data structure"); - exit(EXIT_FAILURE); - } - - while((r=getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { - option= r; - - switch(option) { - - case 'i': /* Interface */ - strncpy(idata.iface, optarg, IFACE_LENGTH); - idata.iface[IFACE_LENGTH-1]=0; - idata.ifindex= if_nametoindex(idata.iface); - idata.iface_f=TRUE; - break; - - case 's': /* IPv6 Source Address */ - if((charptr = strtok_r(optarg, "/", &lasts)) == NULL){ - puts("Error in '-s' (IPv6 Source Address) option"); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, charptr, &(idata.srcaddr)) <= 0){ - puts("inet_pton(): address not valid"); - exit(EXIT_FAILURE); - } - - idata.srcaddr_f = 1; - - if((charptr = strtok_r(NULL, " ", &lasts)) != NULL){ - idata.srcpreflen = atoi(charptr); - - if(idata.srcpreflen>128){ - puts("Prefix length error in IPv6 Source Address"); - exit(EXIT_FAILURE); - } - - sanitize_ipv6_prefix(&(idata.srcaddr), idata.srcpreflen); - idata.srcprefix_f=1; - } - - break; - - case 'd': /* IPv6 Destination Address */ - strncpy( targetipv6.name, optarg, NI_MAXHOST); - targetipv6.name[NI_MAXHOST-1]= 0; - targetipv6.flags= AI_CANONNAME; - - if( (r=get_ipv6_target(&targetipv6)) != 0){ - - if(r < 0){ - printf("Unknown Destination: %s\n", gai_strerror(targetipv6.res)); - } - else{ - puts("Unknown Destination: No IPv6 address found for specified destination"); - } - - exit(EXIT_FAILURE); - } - - idata.dstaddr= targetipv6.ip6; - idata.dstaddr_f = 1; - break; - - case 'A': /* Hop Limit */ - hoplimit= atoi(optarg); - hoplimit_f=1; - break; - - case 'y': /* Fragment header */ - nfrags= atoi(optarg); - - if(nfrags < 8){ - puts("Error in Fragmentation option: Fragment Size must be at least 8 bytes"); - exit(EXIT_FAILURE); - } - - idata.fragh_f= 1; - break; - - case 'u': /* Destinations Options Header */ - if(ndstopthdr >= MAX_DST_OPT_HDR){ - puts("Too many Destination Options Headers"); - exit(EXIT_FAILURE); - } - - hdrlen= atoi(optarg); - - if(hdrlen < 8){ - puts("Bad length in Destination Options Header"); - exit(EXIT_FAILURE); - } - - hdrlen = ((hdrlen+7)/8) * 8; - dstopthdrlen[ndstopthdr]= hdrlen; - - if( (dstopthdr[ndstopthdr]= malloc(hdrlen)) == NULL){ - puts("Not enough memory for Destination Options Header"); - exit(EXIT_FAILURE); - } - - ptrhdr= dstopthdr[ndstopthdr] + 2; - ptrhdrend= dstopthdr[ndstopthdr] + hdrlen; - - while( ptrhdr < ptrhdrend){ - - if( (ptrhdrend-ptrhdr)>257) - pad= 257; - else - pad= ptrhdrend-ptrhdr; - - if(!insert_pad_opt(ptrhdr, ptrhdrend, pad)){ - puts("Destination Options Header Too Big"); - exit(EXIT_FAILURE); - } - - ptrhdr= ptrhdr + pad; - } - - *(dstopthdr[ndstopthdr]+1)= (hdrlen/8)-1; - ndstopthdr++; - dstopthdr_f=1; - break; - - - case 'U': /* Destination Options Header (Unfragmentable Part) */ - if(ndstoptuhdr >= MAX_DST_OPT_U_HDR){ - puts("Too many Destination Options Headers (Unfragmentable Part)"); - exit(EXIT_FAILURE); - } - - hdrlen= atoi(optarg); - - if(hdrlen < 8){ - puts("Bad length in Destination Options Header (Unfragmentable Part)"); - exit(EXIT_FAILURE); - } - - hdrlen = ((hdrlen+7)/8) * 8; - dstoptuhdrlen[ndstoptuhdr]= hdrlen; - - if( (dstoptuhdr[ndstoptuhdr]= malloc(hdrlen)) == NULL){ - puts("Not enough memory for Destination Options Header (Unfragmentable Part)"); - exit(EXIT_FAILURE); - } - - ptrhdr= dstoptuhdr[ndstoptuhdr]+2; - ptrhdrend= dstoptuhdr[ndstoptuhdr] + hdrlen; - - while( ptrhdr < ptrhdrend){ - - if( (ptrhdrend-ptrhdr)>257) - pad= 257; - else - pad= ptrhdrend-ptrhdr; - - if(!insert_pad_opt(ptrhdr, ptrhdrend, pad)){ - puts("Destination Options Header (Unfragmentable Part) Too Big"); - exit(EXIT_FAILURE); - } - - ptrhdr = ptrhdr + pad; - } - - *(dstoptuhdr[ndstoptuhdr]+1)= (hdrlen/8) - 1; - ndstoptuhdr++; - dstoptuhdr_f=1; - break; - - case 'H': /* Hop-by-Hop Options Header */ - if(nhbhopthdr >= MAX_HBH_OPT_HDR){ - puts("Too many Hop-by-Hop Options Headers"); - exit(EXIT_FAILURE); - } - - hdrlen= atoi(optarg); - - if(hdrlen < 8){ - puts("Bad length in Hop-by-Hop Options Header"); - exit(EXIT_FAILURE); - } - - hdrlen = ((hdrlen+7)/8) * 8; - hbhopthdrlen[nhbhopthdr]= hdrlen; - - if( (hbhopthdr[nhbhopthdr]= malloc(hdrlen)) == NULL){ - puts("Not enough memory for Hop-by-Hop Options Header"); - exit(EXIT_FAILURE); - } - - ptrhdr= hbhopthdr[nhbhopthdr] + 2; - ptrhdrend= hbhopthdr[nhbhopthdr] + hdrlen; - - - while( ptrhdr < ptrhdrend){ - - if( (ptrhdrend-ptrhdr)>257) - pad= 257; - else - pad= ptrhdrend-ptrhdr; - - if(!insert_pad_opt(ptrhdr, ptrhdrend, pad)){ - puts("Hop-by-Hop Options Header Too Big"); - exit(EXIT_FAILURE); - } - - ptrhdr = ptrhdr + pad; - } - - *(hbhopthdr[nhbhopthdr]+1)= (hdrlen/8) - 1; - nhbhopthdr++; - hbhopthdr_f=1; - break; - - case 'S': /* Source Ethernet address */ - idata.hsrcaddr_f = 1; - - if(ether_pton(optarg, &(idata.hsrcaddr), sizeof(idata.hsrcaddr)) == 0){ - puts("Error in Source link-layer address."); - exit(EXIT_FAILURE); - } - break; - - case 'D': /* Destination Ethernet Address */ - idata.hdstaddr_f = 1; - - if(ether_pton(optarg, &(idata.hdstaddr), sizeof(idata.hdstaddr)) == 0){ - puts("Error in Destination link-layer address."); - exit(EXIT_FAILURE); - } - break; - - case 'c': /* CurHop value */ - curhop = abs(atoi(optarg)); - break; - - case 'm': /* "Managed" bit */ - managed_f = ND_RA_FLAG_MANAGED; - break; - - case 'o': /* "Other" bit */ - other_f = ND_RA_FLAG_OTHER; - break; - - case 'a': /* "Home Agent" bit */ - home_f = ND_RA_FLAG_HOME_AGENT; - break; - - case 'q': /* ND Proxy bit */ - proxy_f= ND_RA_FLAG_ND_PROXY; - break; - - case 'p': /* "Preference" bits */ - if(strncmp(optarg, "high", strlen("high")) == 0 || strncmp(optarg, "h", strlen("h")) == 0){ - prefbits= RTR_PREF_HIGH; - } - else if(strncmp(optarg, "low", strlen("low")) == 0 || strncmp(optarg, "l", strlen("l")) == 0){ - prefbits= RTR_PREF_LOW; - } - else if(strncmp(optarg, "med", strlen("med")) == 0 || strncmp(optarg, "medium", strlen("medium")) == 0 || \ - strncmp(optarg, "m", strlen("m")) == 0){ - prefbits= RTR_PREF_MED; - } - else if(strncmp(optarg, "resvd", strlen("resvd")) == 0 || strncmp(optarg, "reserved", strlen("reserved")) == 0 || \ - strncmp(optarg, "r", strlen("r")) == 0){ - prefbits= RTR_PREF_RSVD; - } - else{ - preference= atoi(optarg); - - switch(preference){ - case -2: - prefbits= RTR_PREF_RSVD; - break; - - case -1: - prefbits= RTR_PREF_LOW; - break; - - case 0: - prefbits= RTR_PREF_MED; - break; - - case 1: - prefbits= RTR_PREF_HIGH; - break; - - default: - puts("Error in 'preference' parameter"); - exit(EXIT_FAILURE); - break; - } - } - - /* Need to shift the Preference bits to be able to binary-OR them to the RA flags */ - preference= prefbits; - prefbits = prefbits << 3; - break; - - case 't': /* Router Lifetime */ - if((ul_res = strtoul(optarg, &endptr, 0)) == ULONG_MAX){ - perror("Error in 'lifetime' parameter"); - exit(EXIT_FAILURE); - } - - if(endptr != optarg) - lifetime = ul_res; - - break; - - case 'r': /* Reachable Time */ - if((ul_res = strtoul(optarg, &endptr, 0)) == ULONG_MAX){ - perror("Error in 'reachable' parameter"); - exit(EXIT_FAILURE); - } - - if(endptr != optarg) - reachable = ul_res; - - break; - - case 'x': /* Retrans Time */ - if((ul_res = strtoul(optarg, &endptr, 0)) == ULONG_MAX){ - perror("Error in 'retransmit' parameter"); - exit(EXIT_FAILURE); - } - - if(endptr != optarg) - retrans = ul_res; - - break; - - case 'E': /* Source link-layer option */ - sllopt_f = 1; - - if(ether_pton(optarg, &linkaddr[nlinkaddr], sizeof(struct ether_addr)) == 0){ - puts("Error in Source link-layer address option."); - exit(EXIT_FAILURE); - } - - sllopta_f=1; - nlinkaddr++; - break; - - case 'e': /* Add Source link-layer option */ - sllopt_f = 1; - break; - - case 'P': /* Prefix Information option */ - if(nprefixes >= MAX_PREFIX_OPTION){ - puts("Too many Prefix Options"); - exit(EXIT_FAILURE); - } - - if((pref = strtok_r(optarg, "/", &lasts)) == NULL){ - printf("Error in prefix option number %u. \n", nprefixes+1); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, pref, &prefix[nprefixes]) <= 0){ - printf("Error in prefix option number %u. ", nprefixes+1); - perror("inet_pton():"); - exit(EXIT_FAILURE); - } - - if((preflen= strtok_r(NULL, "#", &lasts)) == NULL){ - printf("Length error in prefix option number %u.\n", nprefixes+1); - exit(EXIT_FAILURE); - } - - prefixlen[nprefixes] = atoi(preflen); - - if(prefixlen[nprefixes]>128){ - printf("Length error in prefix option number %u.\n", nprefixes+1); - exit(EXIT_FAILURE); - } - - prefixflags[nprefixes]=0; - prefixpref[nprefixes] = DEFAULT_PREFIX_PREFERRED; - prefixvalid[nprefixes] = DEFAULT_PREFIX_VALID; - - if((prefflags= strtok_r(NULL, "#", &lasts)) == NULL){ - nprefixes++; - prefopt_f=1; - break; - } - - - while(*prefflags){ - if(*prefflags == 'L') - prefixflags[nprefixes] = prefixflags[nprefixes] | ND_OPT_PI_FLAG_ONLINK; - else if(*prefflags == 'A') - prefixflags[nprefixes] = prefixflags[nprefixes] | ND_OPT_PI_FLAG_AUTO; - else if(*prefflags == 'R') - prefixflags[nprefixes] = prefixflags[nprefixes] | ND_OPT_PI_FLAG_RADDR; - else if(*prefflags == '-') - break; - else{ - printf("Flags error in prefix option number %u\n", nprefixes+1); - exit(EXIT_FAILURE); - } - - prefflags++; - } - - if((prefvalid= strtok_r(NULL, "#", &lasts)) == NULL){ - nprefixes++; - prefopt_f=1; - break; - } - - if((ul_res = strtoul(prefvalid, &endptr, 0)) == ULONG_MAX){ - printf("Error in prefix option number %u. ", nprefixes+1); - perror("strtoul()"); - exit(EXIT_FAILURE); - } - - if(endptr != optarg){ - prefixvalid[nprefixes] = ul_res; - } - else{ - nprefixes++; - prefopt_f=1; - break; - } - - if((prefpref= strtok_r(NULL, "#", &lasts)) == NULL){ - nprefixes++; - prefopt_f=1; - break; - } - - if((ul_res = strtoul(prefpref, &endptr, 0)) == ULONG_MAX){ - printf("Error in prefix option number %u. ", nprefixes+1); - perror("strtoul()"); - exit(EXIT_FAILURE); - } - - if(endptr != prefpref) - prefixpref[nprefixes] = ul_res; - - nprefixes++; - prefopt_f=1; - break; - - - case 'R': /* Route Information option */ - if(nroutes >= MAX_ROUTE_OPTION){ - puts("Too many Route Information Options"); - exit(EXIT_FAILURE); - } - - if((pref = strtok_r(optarg, "/", &lasts)) == NULL){ - printf("Error in Route Information option number %u. \n", nroutes+1); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, pref, &route[nroutes]) <= 0){ - printf("Error in Route Information option number %u.\n", nroutes+1); - perror("inet_pton():"); - exit(EXIT_FAILURE); - } - - if((preflen= strtok_r(NULL, "#", &lasts)) == NULL){ - printf("Length error in Route Information option number %u.\n", nroutes+1); - exit(EXIT_FAILURE); - } - - routelen[nroutes] = atoi(preflen); - - if(routelen[nroutes]>128){ - printf("Length error in Route Information option number %u.\n", nroutes+1); - exit(EXIT_FAILURE); - } - - routepref[nroutes] = DEFAULT_ROUTE_OPT_PREF; - routelife[nroutes]= DEFAULT_ROUTE_OPT_LIFE; - - if((rpref = strtok_r(NULL, "#", &lasts)) == NULL){ - nroutes++; - break; - } - - if(strncmp(rpref, "high", strlen("high")) == 0 || strncmp(rpref, "h", strlen("h")) == 0){ - routepref[nroutes]= RTR_PREF_HIGH; - } - else if(strncmp(rpref, "low", strlen("low")) == 0 || strncmp(rpref, "l", strlen("l")) == 0){ - routepref[nroutes]= RTR_PREF_LOW; - } - else if(strncmp(rpref, "med", strlen("med")) == 0 || strncmp(rpref, "medium", strlen("medium")) == 0 || \ - strncmp(rpref, "m", strlen("m")) == 0){ - routepref[nroutes]= RTR_PREF_MED; - } - else if(strncmp(rpref, "resvd", strlen("resvd")) == 0 || strncmp(rpref, "reserved", strlen("reserved")) == 0 || \ - strncmp(rpref, "r", strlen("r")) == 0){ - routepref[nroutes]= RTR_PREF_RSVD; - } - else{ - rtepref= atoi(rpref); - - switch(rtepref){ - case -2: - routepref[nroutes]= RTR_PREF_RSVD; - break; - - case -1: - routepref[nroutes]= RTR_PREF_LOW; - break; - - case 0: - routepref[nroutes]= RTR_PREF_MED; - break; - - case 1: - routepref[nroutes]= RTR_PREF_HIGH; - break; - - default: - puts("Error in 'preference' parameter"); - exit(EXIT_FAILURE); - break; - } - } - - /* Need to shift the "Preference" bits to be able to binary-OR them to the reserved bits */ - routepref[nroutes] = (routepref[nroutes]<<3); - - if((ul_res = strtoul(lasts, &endptr, 0)) == ULONG_MAX){ - printf("Error in 'lifetime' parameter of Route Information option number %u\n", \ - nroutes+1); - exit(EXIT_FAILURE); - } - - if(endptr != lasts) - routelife[nroutes]= ul_res; - - nroutes++; - break; - - case 'N': /* Recursive DNS Server option */ - if(nrdnss >= MAX_RDNSS_OPTION){ - puts("Too many Recursive DNS Server"); - exit(EXIT_FAILURE); - } - - if((charptr = strtok_r(optarg, "#", &lasts)) == NULL){ - printf("Error in Recursive DNS Server option number %u. \n", nrdnss+1); - exit(EXIT_FAILURE); - } - - if((ul_val = strtoul(charptr, &endptr, 0)) == ULONG_MAX){ - printf("Error in 'lifetime' parameter of Recursive DNS Server option number %u\n",\ - nrdnss+1); - exit(EXIT_FAILURE); - } - - if(endptr == charptr){ - printf("Error in Recursive DNS Server option number %u. \n", nrdnss+1); - exit(EXIT_FAILURE); - } - - rdnsslife[nrdnss]= ul_val; - nrdnssopt[nrdnss]= 0; - - while(nrdnssopt[nrdnss]< MAX_RDNSS_OPT_ADDRS && (charptr = strtok_r(NULL, "#", &lasts)) != NULL){ - if ( inet_pton(AF_INET6, charptr, &rdnss[nrdnss][nrdnssopt[nrdnss]]) <= 0){ - printf("Error in address #%u of Recursive DNS Server option number %u.\n", \ - nrdnssopt[nrdnss]+1, nrdnss+1); - perror("inet_pton():"); - exit(EXIT_FAILURE); - } - - nrdnssopt[nrdnss]++; - } - - nrdnss++; - break; - - case 'M': /* MTU option */ - mtu[nmtu]= atoi(optarg); - nmtu++; - break; - - case 'w': /* Flood Routes */ - nfloodr= atoi(optarg); - floodr_f= 1; - break; - - case 'f': /* Flood prefixes */ - nfloodp= atoi(optarg); - floodp_f= 1; - break; - - case 'F': /* Flood sources */ - nsources= atoi(optarg); - if(nsources == 0){ - puts("Invalid number of sources in option -F"); - exit(EXIT_FAILURE); - } - - floods_f= 1; - break; - - case 'W': /* Flood DNS */ - if((charptr = strtok_r(optarg, "#", &lasts)) == NULL){ - puts("Error in option '-k'"); - exit(EXIT_FAILURE); - } - - nfloodda = atoi(charptr); - - if((charptr = strtok_r(NULL, "#", &lasts)) == NULL){ - nflooddoa=127; - } - else{ - nflooddoa=atoi(charptr); - if(nfloodda>MAX_RDNSS_OPT_ADDRS){ - puts("Error in '-k' option: Number of addresses per option exceeds 127"); - exit(EXIT_FAILURE); - } - } - - floodd_f= 1; - break; - - case 'L': /* "Listen mode */ - listen_f = 1; - break; - - case 'j': /* IPv6 Source Address (block) filter */ - if(filters.nblocksrc >= MAX_BLOCK_SRC){ - puts("Too many IPv6 Source Address (block) filters."); - exit(EXIT_FAILURE); - } - - if((pref = strtok_r(optarg, "/", &lasts)) == NULL){ - printf("Error in IPv6 Source Address (block) filter number %u.\n", \ - filters.nblocksrc+1); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, pref, &(filters.blocksrc[filters.nblocksrc])) <= 0){ - printf("Error in IPv6 Source Address (block) filter number %u.", \ - filters.nblocksrc+1); - exit(EXIT_FAILURE); - } - - if((charptr = strtok_r(NULL, " ", &lasts)) == NULL){ - filters.blocksrclen[filters.nblocksrc] = 128; - } - else{ - filters.blocksrclen[filters.nblocksrc] = atoi(charptr); - - if(filters.blocksrclen[filters.nblocksrc]>128){ - printf("Length error in IPv6 Source Address (block) filter number %u.\n", \ - filters.nblocksrc+1); - exit(EXIT_FAILURE); - } - } - - sanitize_ipv6_prefix(&(filters.blocksrc[filters.nblocksrc]), filters.blocksrclen[filters.nblocksrc]); - (filters.nblocksrc)++; - break; - - case 'k': /* IPv6 Destination Address (block) filter */ - if(filters.nblockdst >= MAX_BLOCK_DST){ - puts("Too many IPv6 Destination Address (block) filters."); - exit(EXIT_FAILURE); - } - - if((pref = strtok_r(optarg, "/", &lasts)) == NULL){ - printf("Error in IPv6 Destination Address (block) filter number %u.\n", \ - filters.nblockdst+1); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, pref, &(filters.blockdst[filters.nblockdst])) <= 0){ - printf("Error in IPv6 Source Address (block) filter number %u.", \ - filters.nblockdst+1); - exit(EXIT_FAILURE); - } - - if((charptr = strtok_r(NULL, " ", &lasts)) == NULL){ - filters.blockdstlen[filters.nblockdst] = 128; - } - else{ - filters.blockdstlen[filters.nblockdst] = atoi(charptr); - - if(filters.blockdstlen[filters.nblockdst]>128){ - printf("Length error in IPv6 Source Address (block) filter number %u.\n", \ - filters.nblockdst+1); - exit(EXIT_FAILURE); - } - } - - sanitize_ipv6_prefix(&(filters.blockdst[filters.nblockdst]), filters.blockdstlen[filters.nblockdst]); - (filters.nblockdst)++; - break; - - case 'J': /* Link Source Address (block) filter */ - if(filters.nblocklinksrc > MAX_BLOCK_LINK_SRC){ - puts("Too many link-layer Source Address (accept) filters."); - exit(EXIT_FAILURE); - } - - if(ether_pton(optarg, &(filters.blocklinksrc[filters.nblocklinksrc]), sizeof(struct ether_addr)) == 0){ - printf("Error in link-layer Source Address (blick) filter number %u.\n", \ - filters.nblocklinksrc+1); - exit(EXIT_FAILURE); - } - - (filters.nblocklinksrc)++; - break; - - case 'K': /* Link Destination Address (block) filter */ - if(filters.nblocklinkdst > MAX_BLOCK_LINK_DST){ - puts("Too many link-layer Destination Address (block) filters."); - exit(EXIT_FAILURE); - } - - if(ether_pton(optarg, &(filters.blocklinkdst[filters.nblocklinkdst]), sizeof(struct ether_addr)) == 0){ - printf("Error in link-layer Destination Address (blick) filter number %u.\n", \ - filters.nblocklinkdst+1); - exit(EXIT_FAILURE); - } - - filters.nblocklinkdst++; - break; - - case 'b': /* IPv6 Source Address (accept) filter */ - if(filters.nacceptsrc > MAX_ACCEPT_SRC){ - puts("Too many IPv6 Source Address (accept) filters."); - exit(EXIT_FAILURE); - } - - if((pref = strtok_r(optarg, "/", &lasts)) == NULL){ - printf("Error in IPv6 Source Address (accept) filter number %u.\n", \ - filters.nacceptsrc+1); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, pref, &(filters.acceptsrc[filters.nacceptsrc])) <= 0){ - printf("Error in IPv6 Source Address (accept) filter number %u.\n", \ - filters.nacceptsrc+1); - exit(EXIT_FAILURE); - } - - if((charptr = strtok_r(NULL, " ", &lasts)) == NULL){ - filters.acceptsrclen[filters.nacceptsrc] = 128; - } - else{ - filters.acceptsrclen[filters.nacceptsrc] = atoi(charptr); - - if(filters.acceptsrclen[filters.nacceptsrc]>128){ - printf("Length error in IPv6 Source Address (accept) filter number %u.\n", \ - filters.nacceptsrc+1); - exit(EXIT_FAILURE); - } - } - - sanitize_ipv6_prefix(&(filters.acceptsrc[filters.nacceptsrc]), filters.acceptsrclen[filters.nacceptsrc]); - (filters.nacceptsrc)++; - filters.acceptfilters_f=1; - break; - - - case 'g': /* IPv6 Destination Address (accept) filter */ - if(filters.nacceptdst > MAX_ACCEPT_DST){ - puts("Too many IPv6 Destination Address (accept) filters."); - exit(EXIT_FAILURE); - } - - if((pref = strtok_r(optarg, "/", &lasts)) == NULL){ - printf("Error in IPv6 Destination Address (accept) filter number %u.\n", \ - filters.nacceptdst+1); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, pref, &(filters.acceptdst[filters.nacceptdst])) <= 0){ - printf("Error in IPv6 Source Address (accept) filter number %u.\n", \ - filters.nacceptdst+1); - exit(EXIT_FAILURE); - } - - if((charptr = strtok_r(NULL, " ", &lasts)) == NULL){ - filters.acceptdstlen[filters.nacceptdst] = 128; - } - else{ - filters.acceptdstlen[filters.nacceptdst] = atoi(charptr); - - if(filters.acceptdstlen[filters.nacceptdst] > 128){ - printf("Length error in IPv6 Source Address (accept) filter number %u.\n", \ - filters.nacceptdst+1); - exit(EXIT_FAILURE); - } - } - - sanitize_ipv6_prefix(&(filters.acceptdst[filters.nacceptdst]), filters.acceptdstlen[filters.nacceptdst]); - (filters.nacceptdst)++; - filters.acceptfilters_f=1; - break; - - case 'B': /* Link-layer Source Address (accept) filter */ - if(filters.nacceptlinksrc > MAX_ACCEPT_LINK_SRC){ - puts("Too many link-later Source Address (accept) filters."); - exit(EXIT_FAILURE); - } - - if(ether_pton(optarg, &(filters.acceptlinksrc[filters.nacceptlinksrc]), sizeof(struct ether_addr)) == 0){ - printf("Error in link-layer Source Address (accept) filter number %u.\n", \ - filters.nacceptlinksrc+1); - exit(EXIT_FAILURE); - } - - (filters.nacceptlinksrc)++; - filters.acceptfilters_f=1; - break; - - case 'G': /* Link Destination Address (accept) filter */ - if(filters.nacceptlinkdst > MAX_ACCEPT_LINK_DST){ - puts("Too many link-layer Destination Address (accept) filters."); - exit(EXIT_FAILURE); - } - - if(ether_pton(optarg, &(filters.acceptlinkdst[filters.nacceptlinkdst]), sizeof(struct ether_addr)) == 0){ - printf("Error in link-layer Destination Address (accept) filter number %u.\n",\ - filters.nacceptlinkdst+1); - exit(EXIT_FAILURE); - } - - (filters.nacceptlinkdst)++; - filters.acceptfilters_f=1; - break; - - case 'l': /* "Loop mode */ - loop_f = 1; - break; - - case 'z': /* Sleep option */ - nsleep=atoi(optarg); - if(nsleep==0){ - puts("Invalid number of seconds in '-z' option"); - exit(EXIT_FAILURE); - } - - sleep_f=1; - break; - - case 'v': /* Be verbose */ - idata.verbose_f++; - break; - - case 'h': /* Help */ - print_help(); - - exit(EXIT_FAILURE); - break; - - default: - usage(); - exit(EXIT_FAILURE); - break; - - } /* switch */ - } /* while(getopt) */ - - if(geteuid()) { - puts("ra6 needs root privileges to run."); - exit(EXIT_FAILURE); - } - - if(!idata.iface_f){ - puts("Must specify the network interface with the -i option"); - exit(EXIT_FAILURE); - } - - if(load_dst_and_pcap(&idata, LOAD_PCAP_ONLY) == FAILURE){ - puts("Error while learning Source Address and Next Hop"); - exit(EXIT_FAILURE); - } - - release_privileges(); - - if( pcap_datalink(idata.pfd) != DLT_EN10MB){ - printf("Error: Interface %s is not an Ethernet interface", idata.iface); - exit(EXIT_FAILURE); - } - - if(pcap_compile(idata.pfd, &pcap_filter, PCAP_ICMPV6_RS_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1){ - printf("pcap_compile(): %s", pcap_geterr(idata.pfd)); - exit(EXIT_FAILURE); - } - - if(pcap_setfilter(idata.pfd, &pcap_filter) == -1){ - printf("pcap_setfilter(): %s", pcap_geterr(idata.pfd)); - exit(EXIT_FAILURE); - } - - pcap_freecode(&pcap_filter); - - /* - If the IPv6 Source Address has not been specified, and the "-F" (flood) option has - not been specified, select a random link-local unicast address. - */ - - if(!(idata.srcaddr_f) && !floods_f){ - /* When randomizing a link-local IPv6 address, select addresses that belong to the - prefix fe80::/64 (that's what a link-local address looks-like in legitimate cases). - The KAME implementation discards addresses in which the second high-order 16 bits - (srcaddr.s6_addr16[1] in our case) are not zero. - */ - - if(idata.ip6_local_flag){ - idata.srcaddr= idata.ip6_local; - } - else{ - if ( inet_pton(AF_INET6, "fe80::", &(idata.srcaddr)) <= 0){ - puts("inet_pton(): Error when converting address"); - exit(EXIT_FAILURE); - } - - randomize_ipv6_addr(&(idata.srcaddr), &(idata.srcaddr), 64); - } - } - - /* - If the flood option ("-F") has been specified, but no prefix has been specified, - select the random Source Addresses from the link-local unicast prefix (fe80::/64). - */ - if(floods_f && !idata.srcprefix_f){ - if ( inet_pton(AF_INET6, "fe80::", &(idata.srcaddr)) <= 0){ - puts("inet_pton(): Error when converting address"); - exit(EXIT_FAILURE); - } - - randomize_ipv6_addr(&(idata.srcaddr), &(idata.srcaddr), 64); - idata.srcpreflen=64; - } - - if(!idata.dstaddr_f) /* Destination Address defaults to all-nodes (ff02::1) */ - if( inet_pton(AF_INET6, ALL_NODES_MULTICAST_ADDR, &(idata.dstaddr)) <= 0){ - puts("inet_pton(): address not valid"); - exit(EXIT_FAILURE); - } - - if(!idata.hdstaddr_f) /* Destination link-layer address defaults to all-nodes */ - if(ether_pton(ETHER_ALLNODES_LINK_ADDR, &(idata.hdstaddr), sizeof(idata.hdstaddr)) == 0){ - puts("ether_pton(): Error converting all-nodes multicast address"); - exit(EXIT_FAILURE); - } - - if(sllopt_f && !sllopta_f){ /* The value of the source link-layer address option */ - linkaddr[0]= idata.hsrcaddr; /* defaults to the source Ethernet address */ - nlinkaddr++; - } - - if(floodp_f){ - if(nfloodp == 0){ - puts("Invalid number of prefix options in option -f"); - exit(EXIT_FAILURE); - } - - if(!nprefixes){ - prefixlen[0] = 64; - prefixflags[0]= ND_OPT_PI_FLAG_ONLINK | ND_OPT_PI_FLAG_AUTO; - prefixpref[0] = DEFAULT_PREFIX_PREFERRED; - prefixvalid[0] = DEFAULT_PREFIX_VALID; - } - - nprefixes=nfloodp; - } - - if(floodr_f){ - if(nfloodr == 0){ - puts("Invalid number of route options in option -f"); - exit(EXIT_FAILURE); - } - - if(!nroutes){ - routelen[0] = 64; /* By default, flood with /64s */ - routepref[0]= DEFAULT_ROUTE_OPT_PREF; - routelife[0] = DEFAULT_ROUTE_OPT_LIFE; - } - - nroutes=nfloodr; - } - - if(!floods_f) - nsources=1; - - if(floodd_f){ - if(!nrdnss) - rdnsslife[0]= DEFAULT_RDNSS_LIFETIME; - - nrdnss=nfloodda; - } - - if(!sleep_f) - nsleep=1; - - if( !idata.fragh_f && dstoptuhdr_f){ - puts("Dst. Options Header (Unfragmentable Part) set, but Fragmentation not specified"); - exit(EXIT_FAILURE); - } - - if(idata.verbose_f){ - print_attack_info(&idata); - } - - /* Set initial contents of the attack packet */ - init_packet_data(&idata); - - /* Fire an unsolicited Router Advertisement if a target IPv6 address or a target Ethernet - * address were specified - */ - if(idata.dstaddr_f || idata.hdstaddr_f){ - send_packet(&idata, NULL); - if(idata.verbose_f) - puts("Initial attack packet(s) sent successfully."); - - if(loop_f){ - if(idata.verbose_f) - printf("Now sending Router Advertisements every %u second%s...\n", nsleep, ((nsleep>1)?"s":"")); - - while(loop_f){ - sleep(nsleep); - send_packet(&idata, NULL); - } - - exit(EXIT_SUCCESS); - } - } - - if(listen_f){ - if(idata.verbose_f) - puts("Listening to incoming ICMPv6 Router Solicitation messages..."); - - FD_ZERO(&sset); - FD_SET(idata.fd, &sset); - - while(listen_f){ - rset= sset; + switch (option) { + + case 'i': /* Interface */ + strncpy(idata.iface, optarg, IFACE_LENGTH); + idata.iface[IFACE_LENGTH - 1] = 0; + idata.ifindex = if_nametoindex(idata.iface); + idata.iface_f = TRUE; + break; + + case 's': /* IPv6 Source Address */ + if ((charptr = strtok_r(optarg, "/", &lasts)) == NULL) { + puts("Error in '-s' (IPv6 Source Address) option"); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, charptr, &(idata.srcaddr)) <= 0) { + puts("inet_pton(): address not valid"); + exit(EXIT_FAILURE); + } + + idata.srcaddr_f = 1; + + if ((charptr = strtok_r(NULL, " ", &lasts)) != NULL) { + idata.srcpreflen = atoi(charptr); + + if (idata.srcpreflen > 128) { + puts("Prefix length error in IPv6 Source Address"); + exit(EXIT_FAILURE); + } + + sanitize_ipv6_prefix(&(idata.srcaddr), idata.srcpreflen); + idata.srcprefix_f = 1; + } + + break; + + case 'd': /* IPv6 Destination Address */ + strncpy(targetipv6.name, optarg, NI_MAXHOST); + targetipv6.name[NI_MAXHOST - 1] = 0; + targetipv6.flags = AI_CANONNAME; + + if ((r = get_ipv6_target(&targetipv6)) != 0) { + + if (r < 0) { + printf("Unknown Destination: %s\n", gai_strerror(targetipv6.res)); + } + else { + puts("Unknown Destination: No IPv6 address found for specified destination"); + } + + exit(EXIT_FAILURE); + } + + idata.dstaddr = targetipv6.ip6; + idata.dstaddr_f = 1; + break; + + case 'A': /* Hop Limit */ + hoplimit = atoi(optarg); + hoplimit_f = 1; + break; + + case 'y': /* Fragment header */ + nfrags = atoi(optarg); + + if (nfrags < 8) { + puts("Error in Fragmentation option: Fragment Size must be at least 8 bytes"); + exit(EXIT_FAILURE); + } + + idata.fragh_f = 1; + break; + + case 'u': /* Destinations Options Header */ + if (ndstopthdr >= MAX_DST_OPT_HDR) { + puts("Too many Destination Options Headers"); + exit(EXIT_FAILURE); + } + + hdrlen = atoi(optarg); + + if (hdrlen < 8) { + puts("Bad length in Destination Options Header"); + exit(EXIT_FAILURE); + } + + hdrlen = ((hdrlen + 7) / 8) * 8; + dstopthdrlen[ndstopthdr] = hdrlen; + + if ((dstopthdr[ndstopthdr] = malloc(hdrlen)) == NULL) { + puts("Not enough memory for Destination Options Header"); + exit(EXIT_FAILURE); + } + + ptrhdr = dstopthdr[ndstopthdr] + 2; + ptrhdrend = dstopthdr[ndstopthdr] + hdrlen; + + while (ptrhdr < ptrhdrend) { + + if ((ptrhdrend - ptrhdr) > 257) + pad = 257; + else + pad = ptrhdrend - ptrhdr; + + if (!insert_pad_opt(ptrhdr, ptrhdrend, pad)) { + puts("Destination Options Header Too Big"); + exit(EXIT_FAILURE); + } + + ptrhdr = ptrhdr + pad; + } + + *(dstopthdr[ndstopthdr] + 1) = (hdrlen / 8) - 1; + ndstopthdr++; + dstopthdr_f = 1; + break; + + case 'U': /* Destination Options Header (Unfragmentable Part) */ + if (ndstoptuhdr >= MAX_DST_OPT_U_HDR) { + puts("Too many Destination Options Headers (Unfragmentable Part)"); + exit(EXIT_FAILURE); + } + + hdrlen = atoi(optarg); + + if (hdrlen < 8) { + puts("Bad length in Destination Options Header (Unfragmentable Part)"); + exit(EXIT_FAILURE); + } + + hdrlen = ((hdrlen + 7) / 8) * 8; + dstoptuhdrlen[ndstoptuhdr] = hdrlen; + + if ((dstoptuhdr[ndstoptuhdr] = malloc(hdrlen)) == NULL) { + puts("Not enough memory for Destination Options Header (Unfragmentable Part)"); + exit(EXIT_FAILURE); + } + + ptrhdr = dstoptuhdr[ndstoptuhdr] + 2; + ptrhdrend = dstoptuhdr[ndstoptuhdr] + hdrlen; + + while (ptrhdr < ptrhdrend) { + + if ((ptrhdrend - ptrhdr) > 257) + pad = 257; + else + pad = ptrhdrend - ptrhdr; + + if (!insert_pad_opt(ptrhdr, ptrhdrend, pad)) { + puts("Destination Options Header (Unfragmentable Part) Too Big"); + exit(EXIT_FAILURE); + } + + ptrhdr = ptrhdr + pad; + } + + *(dstoptuhdr[ndstoptuhdr] + 1) = (hdrlen / 8) - 1; + ndstoptuhdr++; + dstoptuhdr_f = 1; + break; + + case 'H': /* Hop-by-Hop Options Header */ + if (nhbhopthdr >= MAX_HBH_OPT_HDR) { + puts("Too many Hop-by-Hop Options Headers"); + exit(EXIT_FAILURE); + } + + hdrlen = atoi(optarg); + + if (hdrlen < 8) { + puts("Bad length in Hop-by-Hop Options Header"); + exit(EXIT_FAILURE); + } + + hdrlen = ((hdrlen + 7) / 8) * 8; + hbhopthdrlen[nhbhopthdr] = hdrlen; + + if ((hbhopthdr[nhbhopthdr] = malloc(hdrlen)) == NULL) { + puts("Not enough memory for Hop-by-Hop Options Header"); + exit(EXIT_FAILURE); + } + + ptrhdr = hbhopthdr[nhbhopthdr] + 2; + ptrhdrend = hbhopthdr[nhbhopthdr] + hdrlen; + + while (ptrhdr < ptrhdrend) { + + if ((ptrhdrend - ptrhdr) > 257) + pad = 257; + else + pad = ptrhdrend - ptrhdr; + + if (!insert_pad_opt(ptrhdr, ptrhdrend, pad)) { + puts("Hop-by-Hop Options Header Too Big"); + exit(EXIT_FAILURE); + } + + ptrhdr = ptrhdr + pad; + } + + *(hbhopthdr[nhbhopthdr] + 1) = (hdrlen / 8) - 1; + nhbhopthdr++; + hbhopthdr_f = 1; + break; + + case 'S': /* Source Ethernet address */ + idata.hsrcaddr_f = 1; + + if (ether_pton(optarg, &(idata.hsrcaddr), sizeof(idata.hsrcaddr)) == 0) { + puts("Error in Source link-layer address."); + exit(EXIT_FAILURE); + } + break; + + case 'D': /* Destination Ethernet Address */ + idata.hdstaddr_f = 1; + + if (ether_pton(optarg, &(idata.hdstaddr), sizeof(idata.hdstaddr)) == 0) { + puts("Error in Destination link-layer address."); + exit(EXIT_FAILURE); + } + break; + + case 'c': /* CurHop value */ + curhop = abs(atoi(optarg)); + break; + + case 'm': /* "Managed" bit */ + managed_f = ND_RA_FLAG_MANAGED; + break; + + case 'o': /* "Other" bit */ + other_f = ND_RA_FLAG_OTHER; + break; + + case 'a': /* "Home Agent" bit */ + home_f = ND_RA_FLAG_HOME_AGENT; + break; + + case 'q': /* ND Proxy bit */ + proxy_f = ND_RA_FLAG_ND_PROXY; + break; + + case 'p': /* "Preference" bits */ + if (strncmp(optarg, "high", strlen("high")) == 0 || strncmp(optarg, "h", strlen("h")) == 0) { + prefbits = RTR_PREF_HIGH; + } + else if (strncmp(optarg, "low", strlen("low")) == 0 || strncmp(optarg, "l", strlen("l")) == 0) { + prefbits = RTR_PREF_LOW; + } + else if (strncmp(optarg, "med", strlen("med")) == 0 || strncmp(optarg, "medium", strlen("medium")) == 0 || + strncmp(optarg, "m", strlen("m")) == 0) { + prefbits = RTR_PREF_MED; + } + else if (strncmp(optarg, "resvd", strlen("resvd")) == 0 || + strncmp(optarg, "reserved", strlen("reserved")) == 0 || strncmp(optarg, "r", strlen("r")) == 0) { + prefbits = RTR_PREF_RSVD; + } + else { + preference = atoi(optarg); + + switch (preference) { + case -2: + prefbits = RTR_PREF_RSVD; + break; + + case -1: + prefbits = RTR_PREF_LOW; + break; + + case 0: + prefbits = RTR_PREF_MED; + break; + + case 1: + prefbits = RTR_PREF_HIGH; + break; + + default: + puts("Error in 'preference' parameter"); + exit(EXIT_FAILURE); + break; + } + } + + /* Need to shift the Preference bits to be able to binary-OR them to the RA flags */ + preference = prefbits; + prefbits = prefbits << 3; + break; + + case 't': /* Router Lifetime */ + if ((ul_res = strtoul(optarg, &endptr, 0)) == ULONG_MAX) { + perror("Error in 'lifetime' parameter"); + exit(EXIT_FAILURE); + } + + if (endptr != optarg) + lifetime = ul_res; + + break; + + case 'r': /* Reachable Time */ + if ((ul_res = strtoul(optarg, &endptr, 0)) == ULONG_MAX) { + perror("Error in 'reachable' parameter"); + exit(EXIT_FAILURE); + } + + if (endptr != optarg) + reachable = ul_res; + + break; + + case 'x': /* Retrans Time */ + if ((ul_res = strtoul(optarg, &endptr, 0)) == ULONG_MAX) { + perror("Error in 'retransmit' parameter"); + exit(EXIT_FAILURE); + } + + if (endptr != optarg) + retrans = ul_res; + + break; + + case 'E': /* Source link-layer option */ + sllopt_f = 1; + + if (ether_pton(optarg, &linkaddr[nlinkaddr], sizeof(struct ether_addr)) == 0) { + puts("Error in Source link-layer address option."); + exit(EXIT_FAILURE); + } + + sllopta_f = 1; + nlinkaddr++; + break; + + case 'e': /* Add Source link-layer option */ + sllopt_f = 1; + break; + + case 'P': /* Prefix Information option */ + if (nprefixes >= MAX_PREFIX_OPTION) { + puts("Too many Prefix Options"); + exit(EXIT_FAILURE); + } + + if ((pref = strtok_r(optarg, "/", &lasts)) == NULL) { + printf("Error in prefix option number %u. \n", nprefixes + 1); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, pref, &prefix[nprefixes]) <= 0) { + printf("Error in prefix option number %u. ", nprefixes + 1); + perror("inet_pton():"); + exit(EXIT_FAILURE); + } + + if ((preflen = strtok_r(NULL, "#", &lasts)) == NULL) { + printf("Length error in prefix option number %u.\n", nprefixes + 1); + exit(EXIT_FAILURE); + } + + prefixlen[nprefixes] = atoi(preflen); + + if (prefixlen[nprefixes] > 128) { + printf("Length error in prefix option number %u.\n", nprefixes + 1); + exit(EXIT_FAILURE); + } + + prefixflags[nprefixes] = 0; + prefixpref[nprefixes] = DEFAULT_PREFIX_PREFERRED; + prefixvalid[nprefixes] = DEFAULT_PREFIX_VALID; + + if ((prefflags = strtok_r(NULL, "#", &lasts)) == NULL) { + nprefixes++; + prefopt_f = 1; + break; + } + + while (*prefflags) { + if (*prefflags == 'L') + prefixflags[nprefixes] = prefixflags[nprefixes] | ND_OPT_PI_FLAG_ONLINK; + else if (*prefflags == 'A') + prefixflags[nprefixes] = prefixflags[nprefixes] | ND_OPT_PI_FLAG_AUTO; + else if (*prefflags == 'R') + prefixflags[nprefixes] = prefixflags[nprefixes] | ND_OPT_PI_FLAG_RADDR; + else if (*prefflags == '-') + break; + else { + printf("Flags error in prefix option number %u\n", nprefixes + 1); + exit(EXIT_FAILURE); + } + + prefflags++; + } + + if ((prefvalid = strtok_r(NULL, "#", &lasts)) == NULL) { + nprefixes++; + prefopt_f = 1; + break; + } + + if ((ul_res = strtoul(prefvalid, &endptr, 0)) == ULONG_MAX) { + printf("Error in prefix option number %u. ", nprefixes + 1); + perror("strtoul()"); + exit(EXIT_FAILURE); + } + + if (endptr != optarg) { + prefixvalid[nprefixes] = ul_res; + } + else { + nprefixes++; + prefopt_f = 1; + break; + } + + if ((prefpref = strtok_r(NULL, "#", &lasts)) == NULL) { + nprefixes++; + prefopt_f = 1; + break; + } + + if ((ul_res = strtoul(prefpref, &endptr, 0)) == ULONG_MAX) { + printf("Error in prefix option number %u. ", nprefixes + 1); + perror("strtoul()"); + exit(EXIT_FAILURE); + } + + if (endptr != prefpref) + prefixpref[nprefixes] = ul_res; + + nprefixes++; + prefopt_f = 1; + break; + + case 'R': /* Route Information option */ + if (nroutes >= MAX_ROUTE_OPTION) { + puts("Too many Route Information Options"); + exit(EXIT_FAILURE); + } + + if ((pref = strtok_r(optarg, "/", &lasts)) == NULL) { + printf("Error in Route Information option number %u. \n", nroutes + 1); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, pref, &route[nroutes]) <= 0) { + printf("Error in Route Information option number %u.\n", nroutes + 1); + perror("inet_pton():"); + exit(EXIT_FAILURE); + } + + if ((preflen = strtok_r(NULL, "#", &lasts)) == NULL) { + printf("Length error in Route Information option number %u.\n", nroutes + 1); + exit(EXIT_FAILURE); + } + + routelen[nroutes] = atoi(preflen); + + if (routelen[nroutes] > 128) { + printf("Length error in Route Information option number %u.\n", nroutes + 1); + exit(EXIT_FAILURE); + } + + routepref[nroutes] = DEFAULT_ROUTE_OPT_PREF; + routelife[nroutes] = DEFAULT_ROUTE_OPT_LIFE; + + if ((rpref = strtok_r(NULL, "#", &lasts)) == NULL) { + nroutes++; + break; + } + + if (strncmp(rpref, "high", strlen("high")) == 0 || strncmp(rpref, "h", strlen("h")) == 0) { + routepref[nroutes] = RTR_PREF_HIGH; + } + else if (strncmp(rpref, "low", strlen("low")) == 0 || strncmp(rpref, "l", strlen("l")) == 0) { + routepref[nroutes] = RTR_PREF_LOW; + } + else if (strncmp(rpref, "med", strlen("med")) == 0 || strncmp(rpref, "medium", strlen("medium")) == 0 || + strncmp(rpref, "m", strlen("m")) == 0) { + routepref[nroutes] = RTR_PREF_MED; + } + else if (strncmp(rpref, "resvd", strlen("resvd")) == 0 || + strncmp(rpref, "reserved", strlen("reserved")) == 0 || strncmp(rpref, "r", strlen("r")) == 0) { + routepref[nroutes] = RTR_PREF_RSVD; + } + else { + rtepref = atoi(rpref); + + switch (rtepref) { + case -2: + routepref[nroutes] = RTR_PREF_RSVD; + break; + + case -1: + routepref[nroutes] = RTR_PREF_LOW; + break; + + case 0: + routepref[nroutes] = RTR_PREF_MED; + break; + + case 1: + routepref[nroutes] = RTR_PREF_HIGH; + break; + + default: + puts("Error in 'preference' parameter"); + exit(EXIT_FAILURE); + break; + } + } + + /* Need to shift the "Preference" bits to be able to binary-OR them to the reserved bits */ + routepref[nroutes] = (routepref[nroutes] << 3); + + if ((ul_res = strtoul(lasts, &endptr, 0)) == ULONG_MAX) { + printf("Error in 'lifetime' parameter of Route Information option number %u\n", nroutes + 1); + exit(EXIT_FAILURE); + } + + if (endptr != lasts) + routelife[nroutes] = ul_res; + + nroutes++; + break; + + case 'N': /* Recursive DNS Server option */ + if (nrdnss >= MAX_RDNSS_OPTION) { + puts("Too many Recursive DNS Server"); + exit(EXIT_FAILURE); + } + + if ((charptr = strtok_r(optarg, "#", &lasts)) == NULL) { + printf("Error in Recursive DNS Server option number %u. \n", nrdnss + 1); + exit(EXIT_FAILURE); + } + + if ((ul_val = strtoul(charptr, &endptr, 0)) == ULONG_MAX) { + printf("Error in 'lifetime' parameter of Recursive DNS Server option number %u\n", nrdnss + 1); + exit(EXIT_FAILURE); + } + + if (endptr == charptr) { + printf("Error in Recursive DNS Server option number %u. \n", nrdnss + 1); + exit(EXIT_FAILURE); + } + + rdnsslife[nrdnss] = ul_val; + nrdnssopt[nrdnss] = 0; + + while (nrdnssopt[nrdnss] < MAX_RDNSS_OPT_ADDRS && (charptr = strtok_r(NULL, "#", &lasts)) != NULL) { + if (inet_pton(AF_INET6, charptr, &rdnss[nrdnss][nrdnssopt[nrdnss]]) <= 0) { + printf("Error in address #%u of Recursive DNS Server option number %u.\n", nrdnssopt[nrdnss] + 1, + nrdnss + 1); + perror("inet_pton():"); + exit(EXIT_FAILURE); + } + + nrdnssopt[nrdnss]++; + } + + nrdnss++; + break; + + case 'M': /* MTU option */ + mtu[nmtu] = atoi(optarg); + nmtu++; + break; + + case 'w': /* Flood Routes */ + nfloodr = atoi(optarg); + floodr_f = 1; + break; + + case 'f': /* Flood prefixes */ + nfloodp = atoi(optarg); + floodp_f = 1; + break; + + case 'F': /* Flood sources */ + nsources = atoi(optarg); + if (nsources == 0) { + puts("Invalid number of sources in option -F"); + exit(EXIT_FAILURE); + } + + floods_f = 1; + break; + + case 'W': /* Flood DNS */ + if ((charptr = strtok_r(optarg, "#", &lasts)) == NULL) { + puts("Error in option '-k'"); + exit(EXIT_FAILURE); + } + + nfloodda = atoi(charptr); + + if ((charptr = strtok_r(NULL, "#", &lasts)) == NULL) { + nflooddoa = 127; + } + else { + nflooddoa = atoi(charptr); + if (nfloodda > MAX_RDNSS_OPT_ADDRS) { + puts("Error in '-k' option: Number of addresses per option exceeds 127"); + exit(EXIT_FAILURE); + } + } + + floodd_f = 1; + break; + + case 'L': /* "Listen mode */ + listen_f = 1; + break; + + case 'j': /* IPv6 Source Address (block) filter */ + if (filters.nblocksrc >= MAX_BLOCK_SRC) { + puts("Too many IPv6 Source Address (block) filters."); + exit(EXIT_FAILURE); + } + + if ((pref = strtok_r(optarg, "/", &lasts)) == NULL) { + printf("Error in IPv6 Source Address (block) filter number %u.\n", filters.nblocksrc + 1); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, pref, &(filters.blocksrc[filters.nblocksrc])) <= 0) { + printf("Error in IPv6 Source Address (block) filter number %u.", filters.nblocksrc + 1); + exit(EXIT_FAILURE); + } + + if ((charptr = strtok_r(NULL, " ", &lasts)) == NULL) { + filters.blocksrclen[filters.nblocksrc] = 128; + } + else { + filters.blocksrclen[filters.nblocksrc] = atoi(charptr); + + if (filters.blocksrclen[filters.nblocksrc] > 128) { + printf("Length error in IPv6 Source Address (block) filter number %u.\n", filters.nblocksrc + 1); + exit(EXIT_FAILURE); + } + } + + sanitize_ipv6_prefix(&(filters.blocksrc[filters.nblocksrc]), filters.blocksrclen[filters.nblocksrc]); + (filters.nblocksrc)++; + break; + + case 'k': /* IPv6 Destination Address (block) filter */ + if (filters.nblockdst >= MAX_BLOCK_DST) { + puts("Too many IPv6 Destination Address (block) filters."); + exit(EXIT_FAILURE); + } + + if ((pref = strtok_r(optarg, "/", &lasts)) == NULL) { + printf("Error in IPv6 Destination Address (block) filter number %u.\n", filters.nblockdst + 1); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, pref, &(filters.blockdst[filters.nblockdst])) <= 0) { + printf("Error in IPv6 Source Address (block) filter number %u.", filters.nblockdst + 1); + exit(EXIT_FAILURE); + } + + if ((charptr = strtok_r(NULL, " ", &lasts)) == NULL) { + filters.blockdstlen[filters.nblockdst] = 128; + } + else { + filters.blockdstlen[filters.nblockdst] = atoi(charptr); + + if (filters.blockdstlen[filters.nblockdst] > 128) { + printf("Length error in IPv6 Source Address (block) filter number %u.\n", filters.nblockdst + 1); + exit(EXIT_FAILURE); + } + } + + sanitize_ipv6_prefix(&(filters.blockdst[filters.nblockdst]), filters.blockdstlen[filters.nblockdst]); + (filters.nblockdst)++; + break; + + case 'J': /* Link Source Address (block) filter */ + if (filters.nblocklinksrc > MAX_BLOCK_LINK_SRC) { + puts("Too many link-layer Source Address (accept) filters."); + exit(EXIT_FAILURE); + } + + if (ether_pton(optarg, &(filters.blocklinksrc[filters.nblocklinksrc]), sizeof(struct ether_addr)) == 0) { + printf("Error in link-layer Source Address (blick) filter number %u.\n", filters.nblocklinksrc + 1); + exit(EXIT_FAILURE); + } + + (filters.nblocklinksrc)++; + break; + + case 'K': /* Link Destination Address (block) filter */ + if (filters.nblocklinkdst > MAX_BLOCK_LINK_DST) { + puts("Too many link-layer Destination Address (block) filters."); + exit(EXIT_FAILURE); + } + + if (ether_pton(optarg, &(filters.blocklinkdst[filters.nblocklinkdst]), sizeof(struct ether_addr)) == 0) { + printf("Error in link-layer Destination Address (blick) filter number %u.\n", + filters.nblocklinkdst + 1); + exit(EXIT_FAILURE); + } + + filters.nblocklinkdst++; + break; + + case 'b': /* IPv6 Source Address (accept) filter */ + if (filters.nacceptsrc > MAX_ACCEPT_SRC) { + puts("Too many IPv6 Source Address (accept) filters."); + exit(EXIT_FAILURE); + } + + if ((pref = strtok_r(optarg, "/", &lasts)) == NULL) { + printf("Error in IPv6 Source Address (accept) filter number %u.\n", filters.nacceptsrc + 1); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, pref, &(filters.acceptsrc[filters.nacceptsrc])) <= 0) { + printf("Error in IPv6 Source Address (accept) filter number %u.\n", filters.nacceptsrc + 1); + exit(EXIT_FAILURE); + } + + if ((charptr = strtok_r(NULL, " ", &lasts)) == NULL) { + filters.acceptsrclen[filters.nacceptsrc] = 128; + } + else { + filters.acceptsrclen[filters.nacceptsrc] = atoi(charptr); + + if (filters.acceptsrclen[filters.nacceptsrc] > 128) { + printf("Length error in IPv6 Source Address (accept) filter number %u.\n", filters.nacceptsrc + 1); + exit(EXIT_FAILURE); + } + } + + sanitize_ipv6_prefix(&(filters.acceptsrc[filters.nacceptsrc]), filters.acceptsrclen[filters.nacceptsrc]); + (filters.nacceptsrc)++; + filters.acceptfilters_f = 1; + break; + + case 'g': /* IPv6 Destination Address (accept) filter */ + if (filters.nacceptdst > MAX_ACCEPT_DST) { + puts("Too many IPv6 Destination Address (accept) filters."); + exit(EXIT_FAILURE); + } + + if ((pref = strtok_r(optarg, "/", &lasts)) == NULL) { + printf("Error in IPv6 Destination Address (accept) filter number %u.\n", filters.nacceptdst + 1); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, pref, &(filters.acceptdst[filters.nacceptdst])) <= 0) { + printf("Error in IPv6 Source Address (accept) filter number %u.\n", filters.nacceptdst + 1); + exit(EXIT_FAILURE); + } + + if ((charptr = strtok_r(NULL, " ", &lasts)) == NULL) { + filters.acceptdstlen[filters.nacceptdst] = 128; + } + else { + filters.acceptdstlen[filters.nacceptdst] = atoi(charptr); + + if (filters.acceptdstlen[filters.nacceptdst] > 128) { + printf("Length error in IPv6 Source Address (accept) filter number %u.\n", filters.nacceptdst + 1); + exit(EXIT_FAILURE); + } + } + + sanitize_ipv6_prefix(&(filters.acceptdst[filters.nacceptdst]), filters.acceptdstlen[filters.nacceptdst]); + (filters.nacceptdst)++; + filters.acceptfilters_f = 1; + break; + + case 'B': /* Link-layer Source Address (accept) filter */ + if (filters.nacceptlinksrc > MAX_ACCEPT_LINK_SRC) { + puts("Too many link-later Source Address (accept) filters."); + exit(EXIT_FAILURE); + } + + if (ether_pton(optarg, &(filters.acceptlinksrc[filters.nacceptlinksrc]), sizeof(struct ether_addr)) == 0) { + printf("Error in link-layer Source Address (accept) filter number %u.\n", filters.nacceptlinksrc + 1); + exit(EXIT_FAILURE); + } + + (filters.nacceptlinksrc)++; + filters.acceptfilters_f = 1; + break; + + case 'G': /* Link Destination Address (accept) filter */ + if (filters.nacceptlinkdst > MAX_ACCEPT_LINK_DST) { + puts("Too many link-layer Destination Address (accept) filters."); + exit(EXIT_FAILURE); + } + + if (ether_pton(optarg, &(filters.acceptlinkdst[filters.nacceptlinkdst]), sizeof(struct ether_addr)) == 0) { + printf("Error in link-layer Destination Address (accept) filter number %u.\n", + filters.nacceptlinkdst + 1); + exit(EXIT_FAILURE); + } + + (filters.nacceptlinkdst)++; + filters.acceptfilters_f = 1; + break; + + case 'l': /* "Loop mode */ + loop_f = 1; + break; + + case 'z': /* Sleep option */ + nsleep = atoi(optarg); + if (nsleep == 0) { + puts("Invalid number of seconds in '-z' option"); + exit(EXIT_FAILURE); + } + + sleep_f = 1; + break; + + case 'v': /* Be verbose */ + idata.verbose_f++; + break; + + case 'h': /* Help */ + print_help(); + + exit(EXIT_FAILURE); + break; + + default: + usage(); + exit(EXIT_FAILURE); + break; + + } /* switch */ + } /* while(getopt) */ + + if (geteuid()) { + puts("ra6 needs root privileges to run."); + exit(EXIT_FAILURE); + } + + if (!idata.iface_f) { + puts("Must specify the network interface with the -i option"); + exit(EXIT_FAILURE); + } + + if (load_dst_and_pcap(&idata, LOAD_PCAP_ONLY) == FAILURE) { + puts("Error while learning Source Address and Next Hop"); + exit(EXIT_FAILURE); + } + + release_privileges(); + + if (pcap_datalink(idata.pfd) != DLT_EN10MB) { + printf("Error: Interface %s is not an Ethernet interface", idata.iface); + exit(EXIT_FAILURE); + } + + if (pcap_compile(idata.pfd, &pcap_filter, PCAP_ICMPV6_RS_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1) { + printf("pcap_compile(): %s", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } + + if (pcap_setfilter(idata.pfd, &pcap_filter) == -1) { + printf("pcap_setfilter(): %s", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } + + pcap_freecode(&pcap_filter); + + /* + If the IPv6 Source Address has not been specified, and the "-F" (flood) option has + not been specified, select a random link-local unicast address. + */ + + if (!(idata.srcaddr_f) && !floods_f) { + /* When randomizing a link-local IPv6 address, select addresses that belong to the + prefix fe80::/64 (that's what a link-local address looks-like in legitimate cases). + The KAME implementation discards addresses in which the second high-order 16 bits + (srcaddr.s6_addr16[1] in our case) are not zero. + */ + + if (idata.ip6_local_flag) { + idata.srcaddr = idata.ip6_local; + } + else { + if (inet_pton(AF_INET6, "fe80::", &(idata.srcaddr)) <= 0) { + puts("inet_pton(): Error when converting address"); + exit(EXIT_FAILURE); + } + + randomize_ipv6_addr(&(idata.srcaddr), &(idata.srcaddr), 64); + } + } + + /* + If the flood option ("-F") has been specified, but no prefix has been specified, + select the random Source Addresses from the link-local unicast prefix (fe80::/64). + */ + if (floods_f && !idata.srcprefix_f) { + if (inet_pton(AF_INET6, "fe80::", &(idata.srcaddr)) <= 0) { + puts("inet_pton(): Error when converting address"); + exit(EXIT_FAILURE); + } + + randomize_ipv6_addr(&(idata.srcaddr), &(idata.srcaddr), 64); + idata.srcpreflen = 64; + } + + if (!idata.dstaddr_f) /* Destination Address defaults to all-nodes (ff02::1) */ + if (inet_pton(AF_INET6, ALL_NODES_MULTICAST_ADDR, &(idata.dstaddr)) <= 0) { + puts("inet_pton(): address not valid"); + exit(EXIT_FAILURE); + } + + if (!idata.hdstaddr_f) /* Destination link-layer address defaults to all-nodes */ + if (ether_pton(ETHER_ALLNODES_LINK_ADDR, &(idata.hdstaddr), sizeof(idata.hdstaddr)) == 0) { + puts("ether_pton(): Error converting all-nodes multicast address"); + exit(EXIT_FAILURE); + } + + if (sllopt_f && !sllopta_f) { /* The value of the source link-layer address option */ + linkaddr[0] = idata.hsrcaddr; /* defaults to the source Ethernet address */ + nlinkaddr++; + } + + if (floodp_f) { + if (nfloodp == 0) { + puts("Invalid number of prefix options in option -f"); + exit(EXIT_FAILURE); + } + + if (!nprefixes) { + prefixlen[0] = 64; + prefixflags[0] = ND_OPT_PI_FLAG_ONLINK | ND_OPT_PI_FLAG_AUTO; + prefixpref[0] = DEFAULT_PREFIX_PREFERRED; + prefixvalid[0] = DEFAULT_PREFIX_VALID; + } + + nprefixes = nfloodp; + } + + if (floodr_f) { + if (nfloodr == 0) { + puts("Invalid number of route options in option -f"); + exit(EXIT_FAILURE); + } + + if (!nroutes) { + routelen[0] = 64; /* By default, flood with /64s */ + routepref[0] = DEFAULT_ROUTE_OPT_PREF; + routelife[0] = DEFAULT_ROUTE_OPT_LIFE; + } + + nroutes = nfloodr; + } + + if (!floods_f) + nsources = 1; + + if (floodd_f) { + if (!nrdnss) + rdnsslife[0] = DEFAULT_RDNSS_LIFETIME; + + nrdnss = nfloodda; + } + + if (!sleep_f) + nsleep = 1; + + if (!idata.fragh_f && dstoptuhdr_f) { + puts("Dst. Options Header (Unfragmentable Part) set, but Fragmentation not specified"); + exit(EXIT_FAILURE); + } + + if (idata.verbose_f) { + print_attack_info(&idata); + } + + /* Set initial contents of the attack packet */ + init_packet_data(&idata); + + /* Fire an unsolicited Router Advertisement if a target IPv6 address or a target Ethernet + * address were specified + */ + if (idata.dstaddr_f || idata.hdstaddr_f) { + send_packet(&idata, NULL); + if (idata.verbose_f) + puts("Initial attack packet(s) sent successfully."); + + if (loop_f) { + if (idata.verbose_f) + printf("Now sending Router Advertisements every %u second%s...\n", nsleep, ((nsleep > 1) ? "s" : "")); + + while (loop_f) { + sleep(nsleep); + send_packet(&idata, NULL); + } + + exit(EXIT_SUCCESS); + } + } + + if (listen_f) { + if (idata.verbose_f) + puts("Listening to incoming ICMPv6 Router Solicitation messages..."); + + FD_ZERO(&sset); + FD_SET(idata.fd, &sset); + + while (listen_f) { + rset = sset; #if defined(sun) || defined(__sun) || defined(__linux__) - timeout.tv_usec=10000; - timeout.tv_sec= 0; - if((sel=select(idata.fd+1, &rset, NULL, NULL, &timeout)) == -1){ + timeout.tv_usec = 10000; + timeout.tv_sec = 0; + if ((sel = select(idata.fd + 1, &rset, NULL, NULL, &timeout)) == -1) { #else - if((sel=select(idata.fd+1, &rset, NULL, NULL, NULL)) == -1){ + if ((sel = select(idata.fd + 1, &rset, NULL, NULL, NULL)) == -1) { #endif - if(errno == EINTR){ - continue; - } - else{ - puts("Error in select()"); - exit(EXIT_FAILURE); - } - } + if (errno == EINTR) { + continue; + } + else { + puts("Error in select()"); + exit(EXIT_FAILURE); + } + } #if defined(sun) || defined(__sun) || defined(__linux__) - if(TRUE){ + if (TRUE) { #else - if(FD_ISSET(idata.fd, &rset)){ + if (FD_ISSET(idata.fd, &rset)) { #endif - /* Read a Router Solicitation message */ - if((r=pcap_next_ex(idata.pfd, &pkthdr, &pktdata)) == -1){ - printf("pcap_next_ex(): %s", pcap_geterr(idata.pfd)); - exit(EXIT_FAILURE); - } - else if(r == 1 && pktdata != NULL){ - pkt_ether = (struct ether_header *) pktdata; - pkt_ipv6 = (struct ip6_hdr *)((char *) pkt_ether + ETHER_HDR_LEN); - pkt_rs = (struct nd_router_solicit *) ((char *) pkt_ipv6 + MIN_IPV6_HLEN); - - accepted_f=0; - - if(idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK)){ - if(filters.nblocklinksrc){ - if(match_ether(filters.blocklinksrc, filters.nblocklinksrc, &(pkt_ether->src))){ - if(idata.verbose_f>1) - print_filter_result(&idata, pktdata, BLOCKED); - - continue; - } - } - - if(filters.nblocklinkdst){ - if(match_ether(filters.blocklinkdst, filters.nblocklinkdst, &(pkt_ether->dst))){ - if(idata.verbose_f>1) - print_filter_result(&idata, pktdata, BLOCKED); - - continue; - } - } - } - - if(filters.nblocksrc){ - if(match_ipv6(filters.blocksrc, filters.blocksrclen, filters.nblocksrc, &(pkt_ipv6->ip6_src))){ - if(idata.verbose_f>1) - print_filter_result(&idata, pktdata, BLOCKED); - - continue; - } - } - - if(filters.nblockdst){ - if(match_ipv6(filters.blockdst, filters.blockdstlen, filters.nblockdst, &(pkt_ipv6->ip6_dst))){ - if(idata.verbose_f>1) - print_filter_result(&idata, pktdata, BLOCKED); - - continue; - } - } - - if(idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK)){ - if(filters.nacceptlinksrc){ - if(match_ether(filters.acceptlinksrc, filters.nacceptlinksrc, &(pkt_ether->src))) - accepted_f=1; - } - - if(filters.nacceptlinkdst && !accepted_f){ - if(match_ether(filters.acceptlinkdst, filters.nacceptlinkdst, &(pkt_ether->dst))) - accepted_f= 1; - } - } - - if(filters.nacceptsrc && !accepted_f){ - if(match_ipv6(filters.acceptsrc, filters.acceptsrclen, filters.nacceptsrc, &(pkt_ipv6->ip6_src))) - accepted_f= 1; - } - - if(filters.nacceptdst && !accepted_f){ - if(match_ipv6(filters.acceptdst, filters.acceptdstlen, filters.nacceptdst, &(pkt_ipv6->ip6_dst))) - accepted_f=1; - } - - if(filters.acceptfilters_f && !accepted_f){ - if(idata.verbose_f>1) - print_filter_result(&idata, pktdata, BLOCKED); - - continue; - } - - if(idata.verbose_f>1) - print_filter_result(&idata, pktdata, ACCEPTED); - - - /* Send a Router Advertisement */ - send_packet(&idata, pktdata); - } - } - } - } - - if(!(idata.dstaddr_f || idata.hdstaddr_f) && !listen_f){ - puts("Error: Nothing to send!"); - exit(EXIT_FAILURE); - } - - exit(EXIT_SUCCESS); -} + /* Read a Router Solicitation message */ + if ((r = pcap_next_ex(idata.pfd, &pkthdr, &pktdata)) == -1) { + printf("pcap_next_ex(): %s", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } + else if (r == 1 && pktdata != NULL) { + pkt_ether = (struct ether_header *)pktdata; + pkt_ipv6 = (struct ip6_hdr *)((char *)pkt_ether + ETHER_HDR_LEN); + pkt_rs = (struct nd_router_solicit *)((char *)pkt_ipv6 + MIN_IPV6_HLEN); + + accepted_f = 0; + + if (idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK)) { + if (filters.nblocklinksrc) { + if (match_ether(filters.blocklinksrc, filters.nblocklinksrc, &(pkt_ether->src))) { + if (idata.verbose_f > 1) + print_filter_result(&idata, pktdata, BLOCKED); + + continue; + } + } + + if (filters.nblocklinkdst) { + if (match_ether(filters.blocklinkdst, filters.nblocklinkdst, &(pkt_ether->dst))) { + if (idata.verbose_f > 1) + print_filter_result(&idata, pktdata, BLOCKED); + + continue; + } + } + } + + if (filters.nblocksrc) { + if (match_ipv6(filters.blocksrc, filters.blocksrclen, filters.nblocksrc, + &(pkt_ipv6->ip6_src))) { + if (idata.verbose_f > 1) + print_filter_result(&idata, pktdata, BLOCKED); + + continue; + } + } + + if (filters.nblockdst) { + if (match_ipv6(filters.blockdst, filters.blockdstlen, filters.nblockdst, + &(pkt_ipv6->ip6_dst))) { + if (idata.verbose_f > 1) + print_filter_result(&idata, pktdata, BLOCKED); + + continue; + } + } + + if (idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK)) { + if (filters.nacceptlinksrc) { + if (match_ether(filters.acceptlinksrc, filters.nacceptlinksrc, &(pkt_ether->src))) + accepted_f = 1; + } + + if (filters.nacceptlinkdst && !accepted_f) { + if (match_ether(filters.acceptlinkdst, filters.nacceptlinkdst, &(pkt_ether->dst))) + accepted_f = 1; + } + } + + if (filters.nacceptsrc && !accepted_f) { + if (match_ipv6(filters.acceptsrc, filters.acceptsrclen, filters.nacceptsrc, + &(pkt_ipv6->ip6_src))) + accepted_f = 1; + } + + if (filters.nacceptdst && !accepted_f) { + if (match_ipv6(filters.acceptdst, filters.acceptdstlen, filters.nacceptdst, + &(pkt_ipv6->ip6_dst))) + accepted_f = 1; + } + + if (filters.acceptfilters_f && !accepted_f) { + if (idata.verbose_f > 1) + print_filter_result(&idata, pktdata, BLOCKED); + + continue; + } + + if (idata.verbose_f > 1) + print_filter_result(&idata, pktdata, ACCEPTED); + + /* Send a Router Advertisement */ + send_packet(&idata, pktdata); + } + } + } + } + if (!(idata.dstaddr_f || idata.hdstaddr_f) && !listen_f) { + puts("Error: Nothing to send!"); + exit(EXIT_FAILURE); + } + exit(EXIT_SUCCESS); +} /* * Function: init_packet_data() @@ -1400,150 +1375,148 @@ int main(int argc, char **argv){ * Initialize the contents of the attack packet (Ethernet header, IPv6 Header, and ICMPv6 header) * that are expected to remain constant for the specified attack. */ -void init_packet_data(struct iface_data *idata){ - struct dlt_null *dlt_null; - ethernet= (struct ether_header *) buffer; - dlt_null= (struct dlt_null *) buffer; - v6buffer = buffer + idata->linkhsize; - ipv6 = (struct ip6_hdr *) v6buffer; - - if(idata->type == DLT_EN10MB){ - ethernet->ether_type = htons(ETHERTYPE_IPV6); - - if(!(idata->flags & IFACE_LOOPBACK)){ - ethernet->src = idata->hsrcaddr; - ethernet->dst = idata->hdstaddr; - } - } - else if(idata->type == DLT_NULL){ - dlt_null->family= PF_INET6; - } -#if defined (__OpenBSD__) - else if(idata->type == DLT_LOOP){ - dlt_null->family= htonl(PF_INET6); - } +void init_packet_data(struct iface_data *idata) { + struct dlt_null *dlt_null; + ethernet = (struct ether_header *)buffer; + dlt_null = (struct dlt_null *)buffer; + v6buffer = buffer + idata->linkhsize; + ipv6 = (struct ip6_hdr *)v6buffer; + + if (idata->type == DLT_EN10MB) { + ethernet->ether_type = htons(ETHERTYPE_IPV6); + + if (!(idata->flags & IFACE_LOOPBACK)) { + ethernet->src = idata->hsrcaddr; + ethernet->dst = idata->hdstaddr; + } + } + else if (idata->type == DLT_NULL) { + dlt_null->family = PF_INET6; + } +#if defined(__OpenBSD__) + else if (idata->type == DLT_LOOP) { + dlt_null->family = htonl(PF_INET6); + } #endif - ipv6->ip6_flow=0; - ipv6->ip6_vfc= 0x60; - ipv6->ip6_hlim= hoplimit; - ipv6->ip6_src= idata->srcaddr; - ipv6->ip6_dst= idata->dstaddr; - prev_nh = (unsigned char *) &(ipv6->ip6_nxt); - - ptr = (unsigned char *) v6buffer + MIN_IPV6_HLEN; - - if(hbhopthdr_f){ - hbhopthdrs=0; - - while(hbhopthdrs < nhbhopthdr){ - if((ptr+ hbhopthdrlen[hbhopthdrs]) > (v6buffer+ idata->mtu)){ - puts("Packet too large while processing HBH Opt. Header"); - exit(EXIT_FAILURE); - } - - *prev_nh = IPPROTO_HOPOPTS; - prev_nh = ptr; - memcpy(ptr, hbhopthdr[hbhopthdrs], hbhopthdrlen[hbhopthdrs]); - ptr = ptr + hbhopthdrlen[hbhopthdrs]; - hbhopthdrs++; - } - } - - if(dstoptuhdr_f){ - dstoptuhdrs=0; - - while(dstoptuhdrs < ndstoptuhdr){ - if((ptr+ dstoptuhdrlen[dstoptuhdrs]) > (v6buffer+ idata->mtu)){ - puts("Packet too large while processing Dest. Opt. Header (Unfrag. Part)"); - exit(EXIT_FAILURE); - } - - *prev_nh = IPPROTO_DSTOPTS; - prev_nh = ptr; - memcpy(ptr, dstoptuhdr[dstoptuhdrs], dstoptuhdrlen[dstoptuhdrs]); - ptr = ptr + dstoptuhdrlen[dstoptuhdrs]; - dstoptuhdrs++; - } - } - - /* Everything that follows is the Fragmentable Part of the packet */ - fragpart = ptr; - - if(idata->fragh_f){ - /* - Check that we are able to send the Unfragmentable Part, together with a - Fragment Header and a chunk data over our link layer - */ - if( (fragpart+sizeof(fraghdr)+nfrags) > (v6buffer+idata->mtu)){ - printf("Unfragmentable part too large for current MTU (%u bytes)\n", idata->mtu); - exit(EXIT_FAILURE); - } - - /* We prepare a separete Fragment Header, but we do not include it in the packet to be sent. - This Fragment Header will be used (an assembled with the rest of the packet by the - send_packet() function. - */ - memset(&fraghdr, 0, FRAG_HDR_SIZE); - *prev_nh = IPPROTO_FRAGMENT; - prev_nh = (unsigned char *) &fraghdr; - } - - if(dstopthdr_f){ - dstopthdrs=0; - - while(dstopthdrs < ndstopthdr){ - if((ptr+ dstopthdrlen[dstopthdrs]) > (v6buffer+idata->max_packet_size)){ - puts("Packet too large while processing Dest. Opt. Header (should be using the Frag. option?)"); - exit(EXIT_FAILURE); - } - - *prev_nh = IPPROTO_DSTOPTS; - prev_nh = ptr; - memcpy(ptr, dstopthdr[dstopthdrs], dstopthdrlen[dstopthdrs]); - ptr = ptr + dstopthdrlen[dstopthdrs]; - dstopthdrs++; - } - } - - *prev_nh = IPPROTO_ICMPV6; - - if( (ptr+sizeof(struct nd_router_advert)) > (v6buffer+idata->max_packet_size)){ - puts("Packet too large while inserting Router Advertisement header (should be using Frag. option?)"); - exit(EXIT_FAILURE); - } - - ra= (struct nd_router_advert *) (ptr); - ra->nd_ra_type = ND_ROUTER_ADVERT; - ra->nd_ra_code = 0; - - ra->nd_ra_curhoplimit = curhop; - ra->nd_ra_flags_reserved = managed_f | other_f | home_f | proxy_f | prefbits; - ra->nd_ra_router_lifetime = htons(lifetime); - ra->nd_ra_reachable = htonl(reachable); - ra->nd_ra_retransmit = htonl(retrans); - - ptr += sizeof(struct nd_router_advert); - - /* If a single source link-layer address is specified, it is included in all packets */ - if(sllopt_f && nlinkaddr==1){ - if( (ptr+sizeof(struct nd_opt_slla)) <= (v6buffer+idata->max_packet_size)){ - sllaopt = (struct nd_opt_slla *) ptr; - sllaopt->type= ND_OPT_SOURCE_LINKADDR; - sllaopt->length= SLLA_OPT_LEN; - memcpy(sllaopt->address, linkaddr[0].a, ETH_ALEN); - ptr += sizeof(struct nd_opt_slla); - } - else{ - puts("Packet too large while processing source link-layer address opt. (should be using Frag. option?)"); - exit(EXIT_FAILURE); - } - } - - startofprefixes = ptr; -} + ipv6->ip6_flow = 0; + ipv6->ip6_vfc = 0x60; + ipv6->ip6_hlim = hoplimit; + ipv6->ip6_src = idata->srcaddr; + ipv6->ip6_dst = idata->dstaddr; + prev_nh = (unsigned char *)&(ipv6->ip6_nxt); + + ptr = (unsigned char *)v6buffer + MIN_IPV6_HLEN; + + if (hbhopthdr_f) { + hbhopthdrs = 0; + + while (hbhopthdrs < nhbhopthdr) { + if ((ptr + hbhopthdrlen[hbhopthdrs]) > (v6buffer + idata->mtu)) { + puts("Packet too large while processing HBH Opt. Header"); + exit(EXIT_FAILURE); + } + + *prev_nh = IPPROTO_HOPOPTS; + prev_nh = ptr; + memcpy(ptr, hbhopthdr[hbhopthdrs], hbhopthdrlen[hbhopthdrs]); + ptr = ptr + hbhopthdrlen[hbhopthdrs]; + hbhopthdrs++; + } + } + + if (dstoptuhdr_f) { + dstoptuhdrs = 0; + + while (dstoptuhdrs < ndstoptuhdr) { + if ((ptr + dstoptuhdrlen[dstoptuhdrs]) > (v6buffer + idata->mtu)) { + puts("Packet too large while processing Dest. Opt. Header (Unfrag. Part)"); + exit(EXIT_FAILURE); + } + + *prev_nh = IPPROTO_DSTOPTS; + prev_nh = ptr; + memcpy(ptr, dstoptuhdr[dstoptuhdrs], dstoptuhdrlen[dstoptuhdrs]); + ptr = ptr + dstoptuhdrlen[dstoptuhdrs]; + dstoptuhdrs++; + } + } + /* Everything that follows is the Fragmentable Part of the packet */ + fragpart = ptr; + + if (idata->fragh_f) { + /* + Check that we are able to send the Unfragmentable Part, together with a + Fragment Header and a chunk data over our link layer + */ + if ((fragpart + sizeof(fraghdr) + nfrags) > (v6buffer + idata->mtu)) { + printf("Unfragmentable part too large for current MTU (%u bytes)\n", idata->mtu); + exit(EXIT_FAILURE); + } + + /* We prepare a separete Fragment Header, but we do not include it in the packet to be sent. + This Fragment Header will be used (an assembled with the rest of the packet by the + send_packet() function. + */ + memset(&fraghdr, 0, FRAG_HDR_SIZE); + *prev_nh = IPPROTO_FRAGMENT; + prev_nh = (unsigned char *)&fraghdr; + } + if (dstopthdr_f) { + dstopthdrs = 0; + + while (dstopthdrs < ndstopthdr) { + if ((ptr + dstopthdrlen[dstopthdrs]) > (v6buffer + idata->max_packet_size)) { + puts("Packet too large while processing Dest. Opt. Header (should be using the Frag. option?)"); + exit(EXIT_FAILURE); + } + + *prev_nh = IPPROTO_DSTOPTS; + prev_nh = ptr; + memcpy(ptr, dstopthdr[dstopthdrs], dstopthdrlen[dstopthdrs]); + ptr = ptr + dstopthdrlen[dstopthdrs]; + dstopthdrs++; + } + } + + *prev_nh = IPPROTO_ICMPV6; + + if ((ptr + sizeof(struct nd_router_advert)) > (v6buffer + idata->max_packet_size)) { + puts("Packet too large while inserting Router Advertisement header (should be using Frag. option?)"); + exit(EXIT_FAILURE); + } + + ra = (struct nd_router_advert *)(ptr); + ra->nd_ra_type = ND_ROUTER_ADVERT; + ra->nd_ra_code = 0; + + ra->nd_ra_curhoplimit = curhop; + ra->nd_ra_flags_reserved = managed_f | other_f | home_f | proxy_f | prefbits; + ra->nd_ra_router_lifetime = htons(lifetime); + ra->nd_ra_reachable = htonl(reachable); + ra->nd_ra_retransmit = htonl(retrans); + + ptr += sizeof(struct nd_router_advert); + + /* If a single source link-layer address is specified, it is included in all packets */ + if (sllopt_f && nlinkaddr == 1) { + if ((ptr + sizeof(struct nd_opt_slla)) <= (v6buffer + idata->max_packet_size)) { + sllaopt = (struct nd_opt_slla *)ptr; + sllaopt->type = ND_OPT_SOURCE_LINKADDR; + sllaopt->length = SLLA_OPT_LEN; + memcpy(sllaopt->address, linkaddr[0].a, ETH_ALEN); + ptr += sizeof(struct nd_opt_slla); + } + else { + puts("Packet too large while processing source link-layer address opt. (should be using Frag. option?)"); + exit(EXIT_FAILURE); + } + } + + startofprefixes = ptr; +} /* * Function: send_packet() @@ -1551,596 +1524,581 @@ void init_packet_data(struct iface_data *idata){ * Initialize the remaining fields of the Router Advertisement Message, and * send the attack packet(s). */ -void send_packet(struct iface_data *idata, const u_char *pktdata){ - if(pktdata==NULL){ - sources=0; - } - else{ /* Sending a response to a Router Solicitation message */ - pkt_ether = (struct ether_header *) pktdata; - pkt_ipv6 = (struct ip6_hdr *)((char *) pkt_ether + idata->linkhsize); - pkt_ipv6addr = &(pkt_ipv6->ip6_src); - - /* If the IPv6 Source Address of the incoming Router Solicitation is the unspecified - address (::), the Router Advertisement must be directed to the IPv6 all-nodes multicast - address (and the Ethernet Destination address should be 33:33:33:00:00:01). Otherwise, - the Router Advertisement is directed to the IPv6 Source Address (and Ethernet Source - Address) of the incoming Router Solicitation message - */ - if(IN6_IS_ADDR_UNSPECIFIED(pkt_ipv6addr)){ - if ( inet_pton(AF_INET6, ALL_NODES_MULTICAST_ADDR, &(ipv6->ip6_dst)) <= 0){ - perror("inet_pton():"); - exit(EXIT_FAILURE); - } - - if(ether_pton(ETHER_ALLNODES_LINK_ADDR, &(ethernet->dst), ETHER_ADDR_LEN) == 0){ - puts("ether_pton(): Error converting all-nodes link-local address"); - exit(EXIT_FAILURE); - } - } - else{ - ipv6->ip6_dst = pkt_ipv6->ip6_src; - ethernet->dst = pkt_ether->src; - } - - pkt_ipv6addr = &(pkt_ipv6->ip6_dst); - - /* If the Router Solicitation message was directed to a unicast address (unlikely), the - IPv6 Source Address and the Ethernet Source Address of the Router Advertisement are set - to the IPv6 Destination Address and the Ethernet Destination Address of the incoming - Router Solicitation, respectively. Otherwise, the IPv6 Source Address and the Ethernet - Source Address are set as specified by the command-line (or randomized). - */ - if(IN6_IS_ADDR_MULTICAST(pkt_ipv6addr)){ - ipv6->ip6_src = idata->srcaddr; - ethernet->src = idata->hsrcaddr; - sources=0; - multicastdst_f=1; - } - else{ - ipv6->ip6_src = pkt_ipv6->ip6_dst; - ethernet->src = pkt_ether->dst; - sources=nsources; - multicastdst_f=0; - } +void send_packet(struct iface_data *idata, const u_char *pktdata) { + if (pktdata == NULL) { + sources = 0; + } + else { /* Sending a response to a Router Solicitation message */ + pkt_ether = (struct ether_header *)pktdata; + pkt_ipv6 = (struct ip6_hdr *)((char *)pkt_ether + idata->linkhsize); + pkt_ipv6addr = &(pkt_ipv6->ip6_src); + + /* If the IPv6 Source Address of the incoming Router Solicitation is the unspecified + address (::), the Router Advertisement must be directed to the IPv6 all-nodes multicast + address (and the Ethernet Destination address should be 33:33:33:00:00:01). Otherwise, + the Router Advertisement is directed to the IPv6 Source Address (and Ethernet Source + Address) of the incoming Router Solicitation message + */ + if (IN6_IS_ADDR_UNSPECIFIED(pkt_ipv6addr)) { + if (inet_pton(AF_INET6, ALL_NODES_MULTICAST_ADDR, &(ipv6->ip6_dst)) <= 0) { + perror("inet_pton():"); + exit(EXIT_FAILURE); + } + + if (ether_pton(ETHER_ALLNODES_LINK_ADDR, &(ethernet->dst), ETHER_ADDR_LEN) == 0) { + puts("ether_pton(): Error converting all-nodes link-local address"); + exit(EXIT_FAILURE); + } + } + else { + ipv6->ip6_dst = pkt_ipv6->ip6_src; + ethernet->dst = pkt_ether->src; + } + + pkt_ipv6addr = &(pkt_ipv6->ip6_dst); + + /* If the Router Solicitation message was directed to a unicast address (unlikely), the + IPv6 Source Address and the Ethernet Source Address of the Router Advertisement are set + to the IPv6 Destination Address and the Ethernet Destination Address of the incoming + Router Solicitation, respectively. Otherwise, the IPv6 Source Address and the Ethernet + Source Address are set as specified by the command-line (or randomized). + */ + if (IN6_IS_ADDR_MULTICAST(pkt_ipv6addr)) { + ipv6->ip6_src = idata->srcaddr; + ethernet->src = idata->hsrcaddr; + sources = 0; + multicastdst_f = 1; + } + else { + ipv6->ip6_src = pkt_ipv6->ip6_dst; + ethernet->src = pkt_ether->dst; + sources = nsources; + multicastdst_f = 0; + } } - - do{ - if(floods_f && (pktdata==NULL || (pktdata != NULL && multicastdst_f))){ - /* - Randomize the IPv6 Source address based on the specified prefix and prefix length - (defaults to fe80::/64). - */ - randomize_ipv6_addr(&(ipv6->ip6_src), &(idata->srcaddr), idata->srcpreflen); - - if(!idata->hsrcaddr_f){ - randomize_ether_addr(&(ethernet->src)); - - /* - If the source-link layer address must be included, but no value was - specified we set it to the randomized Ethernet Source Address - */ - if(sllopt_f && !sllopta_f){ - memcpy(sllaopt->address, ethernet->src.a, ETH_ALEN); - } - } - } - - prefixes= 0; - routes= 0; - dnsopts= 0; - mtus=0; - - if(nlinkaddr==1) - linkaddrs=1; - else - linkaddrs=0; - - do{ - /* - newdata_f handles the case where it is impossible for the packet to incorporate options, - and hence this would result in and endless loop - */ - newdata_f=0; - ptr = startofprefixes; - - while(linkaddrsmax_packet_size){ - sllaopt = (struct nd_opt_slla *) ptr; - sllaopt->type= ND_OPT_SOURCE_LINKADDR; - sllaopt->length= SLLA_OPT_LEN; - memcpy(sllaopt->address, linkaddr[linkaddrs].a, ETH_ALEN); - ptr += sizeof(struct nd_opt_slla); - linkaddrs++; - newdata_f=1; - } - - while(mtusmax_packet_size){ - mtuopt= (struct nd_opt_mtu *) ptr; - mtuopt->nd_opt_mtu_type = ND_OPT_MTU; - mtuopt->nd_opt_mtu_len = MTU_OPT_LEN; - mtuopt->nd_opt_mtu_reserved = 0; - mtuopt->nd_opt_mtu_mtu = htonl(mtu[mtus]); - ptr += sizeof(struct nd_opt_mtu); - mtus++; - newdata_f=1; - } - - while(prefixesmax_packet_size)){ - prefixopt = (struct nd_opt_prefix_info *) ptr; - prefixopt->nd_opt_pi_type= ND_OPT_PREFIX_INFORMATION; - prefixopt->nd_opt_pi_len= PREFIX_OPT_LEN; - - if(!floodp_f){ - prefixopt->nd_opt_pi_flags_reserved= prefixflags[prefixes]; - prefixopt->nd_opt_pi_prefix_len= prefixlen[prefixes]; - prefixopt->nd_opt_pi_valid_time = htonl(prefixvalid[prefixes]); - prefixopt->nd_opt_pi_preferred_time = htonl(prefixpref[prefixes]); - prefixopt->nd_opt_pi_reserved2 = 0; - prefixopt->nd_opt_pi_prefix = prefix[prefixes]; - } - else{ - prefixopt->nd_opt_pi_flags_reserved= prefixflags[0]; - prefixopt->nd_opt_pi_prefix_len= prefixlen[0]; - prefixopt->nd_opt_pi_valid_time = htonl(prefixvalid[0]); - prefixopt->nd_opt_pi_preferred_time = htonl(prefixpref[0]); - prefixopt->nd_opt_pi_reserved2 = 0; - - endrand= (prefixlen[0]+31)/32; - - for(i=0; ind_opt_pi_prefix.s6_addr32[i]=random(); - - if(prefixlen[0]%32){ - mask=0; - - for(i=0; i<(prefixlen[0]%32); i++) - mask= (mask>>1) | 0x80000000; - - prefixopt->nd_opt_pi_prefix.s6_addr32[endrand-1]= \ - prefixopt->nd_opt_pi_prefix.s6_addr32[endrand-1] & htonl(mask); - } - - for(i=endrand;i<4;i++) - prefixopt->nd_opt_pi_prefix.s6_addr32[i]=0; - } - - ptr += sizeof(struct nd_opt_prefix_info); - prefixes++; - newdata_f=1; - } - - - while(routes < nroutes && (((ptr+ sizeof(struct nd_opt_route_info_l)) - v6buffer) \ - <= idata->max_packet_size)){ - - routeopt = (struct nd_opt_route_info_l *) ptr; - routeopt->nd_opt_ri_type=ND_OPT_ROUTE_INFORMATION; - routeopt->nd_opt_ri_len= MAX_ROUTE_OPT_LEN; - - if(!floodr_f){ - routeopt->nd_opt_ri_rsvd_pref_rsvd= routepref[routes]; - routeopt->nd_opt_ri_prefix = route[routes]; - routeopt->nd_opt_ri_prefix_len= routelen[routes]; - routeopt->nd_opt_ri_lifetime = htonl(routelife[routes]); - } - else{ - routeopt->nd_opt_ri_rsvd_pref_rsvd= routepref[0]; - routeopt->nd_opt_ri_prefix_len= routelen[0]; - routeopt->nd_opt_ri_lifetime = htonl(routelife[0]); - - endrand= (routelen[0]+31)/32; - - for(i=0; ind_opt_ri_prefix.s6_addr32[i]=random(); - - if(routelen[0]%32){ - mask=0; - - for(i=0; i<(routelen[0]%32); i++) - mask= (mask>>1) | 0x80000000; - - routeopt->nd_opt_ri_prefix.s6_addr32[endrand-1]= \ - routeopt->nd_opt_ri_prefix.s6_addr32[endrand-1] & htonl(mask); - } - - for(i=endrand;i<4;i++) - routeopt->nd_opt_ri_prefix.s6_addr32[i]=0; - } - - ptr += sizeof(struct nd_opt_route_info_l); - routes++; - newdata_f=1; - } - - - if(!floodd_f){ - while(dnsopts < nrdnss && (((ptr+ sizeof(struct nd_opt_rdnss_l)\ - + nrdnssopt[dnsopts] * sizeof(struct in6_addr) ) - v6buffer) <= idata->max_packet_size)){ - - dnsopt = (struct nd_opt_rdnss_l *) ptr; - dnsopt->nd_opt_rdnss_type= ND_OPT_RDNSS; - dnsopt->nd_opt_rdnss_len= (sizeof(struct nd_opt_rdnss_l) + nrdnssopt[dnsopts] \ - * sizeof(struct in6_addr))/8; - - dnsopt->nd_opt_rdnss_lifetime= htonl(rdnsslife[dnsopts]); - - for(i=0; i< nrdnssopt[dnsopts]; i++) - dnsopt->nd_opt_rdnss_addr[i] = rdnss[dnsopts][i]; - - ptr+= sizeof(struct nd_opt_rdnss_l) + sizeof(struct in6_addr) * nrdnssopt[dnsopts]; - dnsopts++; - newdata_f=1; - } - } - else{ - while(dnsopts < nrdnss){ - smaxaddrs = (idata->max_packet_size - (ptr-v6buffer) - sizeof(struct nd_opt_rdnss_l))\ - / sizeof(struct in6_addr); - if(smaxaddrs>0){ - dnsopt = (struct nd_opt_rdnss_l *) ptr; - dnsopt->nd_opt_rdnss_type= ND_OPT_RDNSS; - dnsopt->nd_opt_rdnss_lifetime= htonl(rdnsslife[0]); - - for(i=0; ind_opt_rdnss_addr[i].s6_addr[j]=random(); - - dnsopt->nd_opt_rdnss_len= (sizeof(struct nd_opt_rdnss_l) + \ - i * sizeof(struct in6_addr))/8; - - ptr+= sizeof(struct nd_opt_rdnss_l) + sizeof(struct in6_addr) * i; - newdata_f=1; - } - } - } - - ra->nd_ra_cksum = 0; - ra->nd_ra_cksum = in_chksum(v6buffer, ra, ptr-((unsigned char *)ra), IPPROTO_ICMPV6); - - if(!idata->fragh_f){ - ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); - - if((nw=pcap_inject(idata->pfd, buffer, ptr - buffer)) == -1){ - printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); - exit(EXIT_FAILURE); - } - - if(nw != (ptr-buffer)){ - printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, (LUI) (ptr-buffer)); - exit(EXIT_FAILURE); - } - } - else{ - ptrend= ptr; - ptr= fragpart; - fptr = fragbuffer; - fipv6 = (struct ip6_hdr *) (fragbuffer + ETHER_HDR_LEN); - fptrend = fptr + ETHER_HDR_LEN+MIN_IPV6_HLEN+MAX_IPV6_PAYLOAD; - memcpy(fptr, buffer, fragpart-buffer); - fptr = fptr + (fragpart-buffer); - - if( (fptr+FRAG_HDR_SIZE)> fptrend){ - puts("Unfragmentable Part is Too Large"); - exit(EXIT_FAILURE); - } - - memcpy(fptr, (char *) &fraghdr, FRAG_HDR_SIZE); - fh= (struct ip6_frag *) fptr; - fh->ip6f_ident=random(); - startoffragment = fptr + FRAG_HDR_SIZE; - /* - * Check that the selected fragment size is not larger than the largest fragment size - that can be sent - */ - - if(nfrags > (fptrend - fptr)) - nfrags= (fptrend-fptr); - - m=IP6F_MORE_FRAG; - - while((ptr< ptrend) && m==IP6F_MORE_FRAG){ - fptr= startoffragment; - - if( (ptrend-ptr) <= nfrags){ - fragsize= ptrend-ptr; - m=0; - } - else{ - fragsize = (nfrags +7) & ntohs(IP6F_OFF_MASK); - } - - memcpy(fptr, ptr, fragsize); - fh->ip6f_offlg = (htons(ptr-fragpart) & IP6F_OFF_MASK) | m; - ptr+=fragsize; - fptr+=fragsize; - - fipv6->ip6_plen = htons((fptr - fragbuffer) - MIN_IPV6_HLEN - ETHER_HDR_LEN); - - if((nw=pcap_inject(idata->pfd, fragbuffer, fptr - fragbuffer)) == -1){ - printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); - exit(EXIT_FAILURE); - } - - if(nw != (fptr- fragbuffer)){ - printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, (LUI) (ptr-buffer)); - exit(EXIT_FAILURE); - } - } - } - }while( (linkaddrs>nlinkaddr || mtusip6_src), &(idata->srcaddr), idata->srcpreflen); + + if (!idata->hsrcaddr_f) { + randomize_ether_addr(&(ethernet->src)); + + /* + If the source-link layer address must be included, but no value was + specified we set it to the randomized Ethernet Source Address + */ + if (sllopt_f && !sllopta_f) { + memcpy(sllaopt->address, ethernet->src.a, ETH_ALEN); + } + } + } + + prefixes = 0; + routes = 0; + dnsopts = 0; + mtus = 0; + + if (nlinkaddr == 1) + linkaddrs = 1; + else + linkaddrs = 0; + + do { + /* + newdata_f handles the case where it is impossible for the packet to incorporate options, + and hence this would result in and endless loop + */ + newdata_f = 0; + ptr = startofprefixes; + + while (linkaddrs < nlinkaddr && (ptr + sizeof(struct nd_opt_slla) - v6buffer) <= idata->max_packet_size) { + sllaopt = (struct nd_opt_slla *)ptr; + sllaopt->type = ND_OPT_SOURCE_LINKADDR; + sllaopt->length = SLLA_OPT_LEN; + memcpy(sllaopt->address, linkaddr[linkaddrs].a, ETH_ALEN); + ptr += sizeof(struct nd_opt_slla); + linkaddrs++; + newdata_f = 1; + } + + while (mtus < nmtu && (ptr + sizeof(struct nd_opt_mtu) - v6buffer) <= idata->max_packet_size) { + mtuopt = (struct nd_opt_mtu *)ptr; + mtuopt->nd_opt_mtu_type = ND_OPT_MTU; + mtuopt->nd_opt_mtu_len = MTU_OPT_LEN; + mtuopt->nd_opt_mtu_reserved = 0; + mtuopt->nd_opt_mtu_mtu = htonl(mtu[mtus]); + ptr += sizeof(struct nd_opt_mtu); + mtus++; + newdata_f = 1; + } + + while (prefixes < nprefixes && + (((ptr + sizeof(struct nd_opt_prefix_info)) - v6buffer) <= idata->max_packet_size)) { + prefixopt = (struct nd_opt_prefix_info *)ptr; + prefixopt->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION; + prefixopt->nd_opt_pi_len = PREFIX_OPT_LEN; + + if (!floodp_f) { + prefixopt->nd_opt_pi_flags_reserved = prefixflags[prefixes]; + prefixopt->nd_opt_pi_prefix_len = prefixlen[prefixes]; + prefixopt->nd_opt_pi_valid_time = htonl(prefixvalid[prefixes]); + prefixopt->nd_opt_pi_preferred_time = htonl(prefixpref[prefixes]); + prefixopt->nd_opt_pi_reserved2 = 0; + prefixopt->nd_opt_pi_prefix = prefix[prefixes]; + } + else { + prefixopt->nd_opt_pi_flags_reserved = prefixflags[0]; + prefixopt->nd_opt_pi_prefix_len = prefixlen[0]; + prefixopt->nd_opt_pi_valid_time = htonl(prefixvalid[0]); + prefixopt->nd_opt_pi_preferred_time = htonl(prefixpref[0]); + prefixopt->nd_opt_pi_reserved2 = 0; + + endrand = (prefixlen[0] + 31) / 32; + + for (i = 0; i < endrand; i++) + prefixopt->nd_opt_pi_prefix.s6_addr32[i] = random(); + + if (prefixlen[0] % 32) { + mask = 0; + + for (i = 0; i < (prefixlen[0] % 32); i++) + mask = (mask >> 1) | 0x80000000; + + prefixopt->nd_opt_pi_prefix.s6_addr32[endrand - 1] = + prefixopt->nd_opt_pi_prefix.s6_addr32[endrand - 1] & htonl(mask); + } + + for (i = endrand; i < 4; i++) + prefixopt->nd_opt_pi_prefix.s6_addr32[i] = 0; + } + + ptr += sizeof(struct nd_opt_prefix_info); + prefixes++; + newdata_f = 1; + } + + while (routes < nroutes && + (((ptr + sizeof(struct nd_opt_route_info_l)) - v6buffer) <= idata->max_packet_size)) { + + routeopt = (struct nd_opt_route_info_l *)ptr; + routeopt->nd_opt_ri_type = ND_OPT_ROUTE_INFORMATION; + routeopt->nd_opt_ri_len = MAX_ROUTE_OPT_LEN; + + if (!floodr_f) { + routeopt->nd_opt_ri_rsvd_pref_rsvd = routepref[routes]; + routeopt->nd_opt_ri_prefix = route[routes]; + routeopt->nd_opt_ri_prefix_len = routelen[routes]; + routeopt->nd_opt_ri_lifetime = htonl(routelife[routes]); + } + else { + routeopt->nd_opt_ri_rsvd_pref_rsvd = routepref[0]; + routeopt->nd_opt_ri_prefix_len = routelen[0]; + routeopt->nd_opt_ri_lifetime = htonl(routelife[0]); + + endrand = (routelen[0] + 31) / 32; + + for (i = 0; i < endrand; i++) + routeopt->nd_opt_ri_prefix.s6_addr32[i] = random(); + + if (routelen[0] % 32) { + mask = 0; + + for (i = 0; i < (routelen[0] % 32); i++) + mask = (mask >> 1) | 0x80000000; + + routeopt->nd_opt_ri_prefix.s6_addr32[endrand - 1] = + routeopt->nd_opt_ri_prefix.s6_addr32[endrand - 1] & htonl(mask); + } + + for (i = endrand; i < 4; i++) + routeopt->nd_opt_ri_prefix.s6_addr32[i] = 0; + } + + ptr += sizeof(struct nd_opt_route_info_l); + routes++; + newdata_f = 1; + } + + if (!floodd_f) { + while (dnsopts < nrdnss && + (((ptr + sizeof(struct nd_opt_rdnss_l) + nrdnssopt[dnsopts] * sizeof(struct in6_addr)) - + v6buffer) <= idata->max_packet_size)) { + + dnsopt = (struct nd_opt_rdnss_l *)ptr; + dnsopt->nd_opt_rdnss_type = ND_OPT_RDNSS; + dnsopt->nd_opt_rdnss_len = + (sizeof(struct nd_opt_rdnss_l) + nrdnssopt[dnsopts] * sizeof(struct in6_addr)) / 8; + + dnsopt->nd_opt_rdnss_lifetime = htonl(rdnsslife[dnsopts]); + + for (i = 0; i < nrdnssopt[dnsopts]; i++) + dnsopt->nd_opt_rdnss_addr[i] = rdnss[dnsopts][i]; + + ptr += sizeof(struct nd_opt_rdnss_l) + sizeof(struct in6_addr) * nrdnssopt[dnsopts]; + dnsopts++; + newdata_f = 1; + } + } + else { + while (dnsopts < nrdnss) { + smaxaddrs = (idata->max_packet_size - (ptr - v6buffer) - sizeof(struct nd_opt_rdnss_l)) / + sizeof(struct in6_addr); + if (smaxaddrs > 0) { + dnsopt = (struct nd_opt_rdnss_l *)ptr; + dnsopt->nd_opt_rdnss_type = ND_OPT_RDNSS; + dnsopt->nd_opt_rdnss_lifetime = htonl(rdnsslife[0]); + + for (i = 0; i < smaxaddrs && i < nflooddoa && dnsopts < nrdnss; i++, dnsopts++) + for (j = 0; j < 16; j++) + dnsopt->nd_opt_rdnss_addr[i].s6_addr[j] = random(); + + dnsopt->nd_opt_rdnss_len = (sizeof(struct nd_opt_rdnss_l) + i * sizeof(struct in6_addr)) / 8; + + ptr += sizeof(struct nd_opt_rdnss_l) + sizeof(struct in6_addr) * i; + newdata_f = 1; + } + } + } + + ra->nd_ra_cksum = 0; + ra->nd_ra_cksum = in_chksum(v6buffer, ra, ptr - ((unsigned char *)ra), IPPROTO_ICMPV6); + + if (!idata->fragh_f) { + ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); + + if ((nw = pcap_inject(idata->pfd, buffer, ptr - buffer)) == -1) { + printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); + exit(EXIT_FAILURE); + } + + if (nw != (ptr - buffer)) { + printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, (LUI)(ptr - buffer)); + exit(EXIT_FAILURE); + } + } + else { + ptrend = ptr; + ptr = fragpart; + fptr = fragbuffer; + fipv6 = (struct ip6_hdr *)(fragbuffer + ETHER_HDR_LEN); + fptrend = fptr + ETHER_HDR_LEN + MIN_IPV6_HLEN + MAX_IPV6_PAYLOAD; + memcpy(fptr, buffer, fragpart - buffer); + fptr = fptr + (fragpart - buffer); + + if ((fptr + FRAG_HDR_SIZE) > fptrend) { + puts("Unfragmentable Part is Too Large"); + exit(EXIT_FAILURE); + } + + memcpy(fptr, (char *)&fraghdr, FRAG_HDR_SIZE); + fh = (struct ip6_frag *)fptr; + fh->ip6f_ident = random(); + startoffragment = fptr + FRAG_HDR_SIZE; + /* + * Check that the selected fragment size is not larger than the largest fragment size + that can be sent + */ + + if (nfrags > (fptrend - fptr)) + nfrags = (fptrend - fptr); + + m = IP6F_MORE_FRAG; + + while ((ptr < ptrend) && m == IP6F_MORE_FRAG) { + fptr = startoffragment; + + if ((ptrend - ptr) <= nfrags) { + fragsize = ptrend - ptr; + m = 0; + } + else { + fragsize = (nfrags + 7) & ntohs(IP6F_OFF_MASK); + } + + memcpy(fptr, ptr, fragsize); + fh->ip6f_offlg = (htons(ptr - fragpart) & IP6F_OFF_MASK) | m; + ptr += fragsize; + fptr += fragsize; + + fipv6->ip6_plen = htons((fptr - fragbuffer) - MIN_IPV6_HLEN - ETHER_HDR_LEN); + + if ((nw = pcap_inject(idata->pfd, fragbuffer, fptr - fragbuffer)) == -1) { + printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); + exit(EXIT_FAILURE); + } + + if (nw != (fptr - fragbuffer)) { + printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, (LUI)(ptr - buffer)); + exit(EXIT_FAILURE); + } + } + } + } while ( + (linkaddrs > nlinkaddr || mtus < nmtu || prefixes < nprefixes || routes < nroutes || dnsopts < nrdnss) && + newdata_f); + sources++; + } while (sources < nsources); } - - /* * Function: usage() * * Print the syntax of the ra6 tool */ -void usage(void){ +void usage(void) { puts("usage: ra6 -i INTERFACE [-s SRC_ADDR[/LEN]] [-d DST_ADDR] [-y FRAG_SIZE] " - "[-u DST_OPT_HDR_SIZE] [-U DST_OPT_U_HDR_SIZE] [-H HBH_OPT_HDR_SIZE] [-S LINK_SRC_ADDR] " - "[-D LINK_DST_ADDR] [-c CUR_HOP] [-t ROUTER_LIFETIME] [-r REACHABLE_TIME] " - "[-x RETRANS_TIMER] [-m] [-o] [-a] [-q] [-p PREFERENCE] [-E LINK_ADDR] [-e] " - "[-P PREFIX/LEN[#FLAGS[#VALID[#PREFERRED]]]] [-M MTU] [-N [LIFETIME[#DNS_ADDR]]] " - "[-R PREFIX/LEN[#PREF[#LIFETIME]]] [-f N_PREFIXES] [-F N_SOURCES] [-w N_ROUTES] " - "[-W N_ADDRS[#ADDRSPEROPT]] [-j PREFIX[/LEN]] [-k PREFIX[/LEN]] [-J LINK_ADDR] " - "[-K LINK_ADDR] [-b PREFIX[/LEN]] [-g PREFIX[/LEN]] [-B LINK_ADDR] [-G LINK_ADDR] " - " [-L] [-v] [-h]"); - + "[-u DST_OPT_HDR_SIZE] [-U DST_OPT_U_HDR_SIZE] [-H HBH_OPT_HDR_SIZE] [-S LINK_SRC_ADDR] " + "[-D LINK_DST_ADDR] [-c CUR_HOP] [-t ROUTER_LIFETIME] [-r REACHABLE_TIME] " + "[-x RETRANS_TIMER] [-m] [-o] [-a] [-q] [-p PREFERENCE] [-E LINK_ADDR] [-e] " + "[-P PREFIX/LEN[#FLAGS[#VALID[#PREFERRED]]]] [-M MTU] [-N [LIFETIME[#DNS_ADDR]]] " + "[-R PREFIX/LEN[#PREF[#LIFETIME]]] [-f N_PREFIXES] [-F N_SOURCES] [-w N_ROUTES] " + "[-W N_ADDRS[#ADDRSPEROPT]] [-j PREFIX[/LEN]] [-k PREFIX[/LEN]] [-J LINK_ADDR] " + "[-K LINK_ADDR] [-b PREFIX[/LEN]] [-g PREFIX[/LEN]] [-B LINK_ADDR] [-G LINK_ADDR] " + " [-L] [-v] [-h]"); } - - /* * Function: print_help() * * Print help information for the ra6 tool */ -void print_help(void){ - puts(SI6_TOOLKIT); - puts("ra6: Security assessment tool for attack vectors based on RA messages\n"); - usage(); - - puts("\nOPTIONS:\n" - " --interface, -i Network interface\n" - " --src-addr, -s IPv6 Source Address\n" - " --dst-addr, -d IPv6 Destination Address (or IPv6 prefix when flooding)\n" - " --frag-hdr. -y Fragment Header\n" - " --dst-opt-hdr, -u Destination Options Header (Fragmentable Part)\n" - " --dst-opt-u-hdr, -U Destination Options Header (Unfragmentable Part)\n" - " --hbh-opt-hdr, -H Hop by Hop Options Header\n" - " --managed, -m Set de Managed bit\n" - " --other, -o Set the Other bit\n" - " --home-agent, -a Set the Home Agent bit\n" - " --nd-proxy, -q Set the ND Proxy bit\n" - " --lifetime, -t Router Lifetime\n" - " --reachable, -r Reachable time\n" - " --preference, -p Preference\n" - " --retrans, -x Retrans Timer\n" - " --curhop, -c CurHop (advised Hop Limit)\n" - " --prefix-opt, -P Prefix option (Prefix/Len#flags#valid#preferred)\n" - " --mtu-opt, -M MTU option\n" - " --src-link-opt, -E Source link-layer address option\n" - " --add-slla-opt, -e Add Source link-layer address option\n" - " --link-src-addr, -S Link-layer Source Address\n" - " --link-dst-addr, -D Link-layer Destination Address\n" - " --route-opt, -R Route Information option (Prefix/Len#pref#lifetime)\n" - " --rdnss-opt, -N Recursive DNS Server option (lifetime#IPv6addr)\n" - " --flood-sources, -F Number of Source Addresses to forge randomly\n" - " --flood-prefixes, -f Number of Prefix options to forge randomly\n" - " --flood-routes, -w Number of Route Info options to forge randomly\n" - " --flood-dns, -W Number of RDNSS options to forge randomly\n" - " --loop, -l Send periodic Router Advertisements\n" - " --sleep, -z Pause between sending RA messages\n" - " --listen, -L Listen to Router Solicitation messagres\n" - " --block-src, -j Block IPv6 Source Address prefix\n" - " --block-dst, -k Block IPv6 Destination Address prefix\n" - " --block-link-src, -J Block Ethernet Source Address\n" - " --block-link-dst, -K Block Ethernet Destination Address\n" - " --accept-src, -b Accept IPv6 Source Address prefix\n" - " --accept-dst, -g Accept IPv6 Destination Address prefix\n" - " --accept-link-src, -B Accept Ethernet Source Address\n" - " --accept-link-dst, -G Accept Ethernet Destination Address\n" - " --verbose, -v Be verbose\n" - " --help, -h Print help for the ra6 tool\n" - "\n" - "Programmed by Fernando Gont for SI6 Networks \n" - "Please send any bug reports to " - ); +void print_help(void) { + puts(SI6_TOOLKIT); + puts("ra6: Security assessment tool for attack vectors based on RA messages\n"); + usage(); + + puts("\nOPTIONS:\n" + " --interface, -i Network interface\n" + " --src-addr, -s IPv6 Source Address\n" + " --dst-addr, -d IPv6 Destination Address (or IPv6 prefix when flooding)\n" + " --frag-hdr. -y Fragment Header\n" + " --dst-opt-hdr, -u Destination Options Header (Fragmentable Part)\n" + " --dst-opt-u-hdr, -U Destination Options Header (Unfragmentable Part)\n" + " --hbh-opt-hdr, -H Hop by Hop Options Header\n" + " --managed, -m Set de Managed bit\n" + " --other, -o Set the Other bit\n" + " --home-agent, -a Set the Home Agent bit\n" + " --nd-proxy, -q Set the ND Proxy bit\n" + " --lifetime, -t Router Lifetime\n" + " --reachable, -r Reachable time\n" + " --preference, -p Preference\n" + " --retrans, -x Retrans Timer\n" + " --curhop, -c CurHop (advised Hop Limit)\n" + " --prefix-opt, -P Prefix option (Prefix/Len#flags#valid#preferred)\n" + " --mtu-opt, -M MTU option\n" + " --src-link-opt, -E Source link-layer address option\n" + " --add-slla-opt, -e Add Source link-layer address option\n" + " --link-src-addr, -S Link-layer Source Address\n" + " --link-dst-addr, -D Link-layer Destination Address\n" + " --route-opt, -R Route Information option (Prefix/Len#pref#lifetime)\n" + " --rdnss-opt, -N Recursive DNS Server option (lifetime#IPv6addr)\n" + " --flood-sources, -F Number of Source Addresses to forge randomly\n" + " --flood-prefixes, -f Number of Prefix options to forge randomly\n" + " --flood-routes, -w Number of Route Info options to forge randomly\n" + " --flood-dns, -W Number of RDNSS options to forge randomly\n" + " --loop, -l Send periodic Router Advertisements\n" + " --sleep, -z Pause between sending RA messages\n" + " --listen, -L Listen to Router Solicitation messagres\n" + " --block-src, -j Block IPv6 Source Address prefix\n" + " --block-dst, -k Block IPv6 Destination Address prefix\n" + " --block-link-src, -J Block Ethernet Source Address\n" + " --block-link-dst, -K Block Ethernet Destination Address\n" + " --accept-src, -b Accept IPv6 Source Address prefix\n" + " --accept-dst, -g Accept IPv6 Destination Address prefix\n" + " --accept-link-src, -B Accept Ethernet Source Address\n" + " --accept-link-dst, -G Accept Ethernet Destination Address\n" + " --verbose, -v Be verbose\n" + " --help, -h Print help for the ra6 tool\n" + "\n" + "Programmed by Fernando Gont for SI6 Networks \n" + "Please send any bug reports to "); } - - /* * Function: print_attack_info() * * Print attack details (when the verbose ("-v") option is specified). */ -void print_attack_info(struct iface_data *idata){ - char *routestr[]={"medium", "high", "resvd", "low"}; +void print_attack_info(struct iface_data *idata) { + char *routestr[] = {"medium", "high", "resvd", "low"}; + if (!floods_f) { + if (ether_ntop(&(idata->hsrcaddr), plinkaddr, sizeof(plinkaddr)) == 0) { + puts("ether_ntop(): Error converting address"); + exit(EXIT_FAILURE); + } - if(!floods_f){ - if(ether_ntop(&(idata->hsrcaddr), plinkaddr, sizeof(plinkaddr)) == 0){ - puts("ether_ntop(): Error converting address"); - exit(EXIT_FAILURE); - } - - printf("Ethernet Source Address: %s%s\n", plinkaddr, ((!idata->hsrcaddr_f)?" (automatically-selected)":"")); - } - else{ - if(idata->hsrcaddr_f){ - if(ether_ntop(&(idata->hsrcaddr), plinkaddr, sizeof(plinkaddr)) == 0){ - puts("ether_ntop(): Error converting address"); - exit(EXIT_FAILURE); - } - - printf("Ethernet Source Address: %s\n", plinkaddr); - } - else - puts("Ethernet Source Address: automatically-selected"); - } + printf("Ethernet Source Address: %s%s\n", plinkaddr, ((!idata->hsrcaddr_f) ? " (automatically-selected)" : "")); + } + else { + if (idata->hsrcaddr_f) { + if (ether_ntop(&(idata->hsrcaddr), plinkaddr, sizeof(plinkaddr)) == 0) { + puts("ether_ntop(): Error converting address"); + exit(EXIT_FAILURE); + } + + printf("Ethernet Source Address: %s\n", plinkaddr); + } + else + puts("Ethernet Source Address: automatically-selected"); + } /* Ethernet Destination Address only used if a target IPv6 address or a target Ethernet * address were specified */ - if(idata->dstaddr_f || idata->hdstaddr_f){ - if(ether_ntop(&(idata->hdstaddr), phdstaddr, sizeof(phdstaddr)) == 0){ - puts("ether_ntop(): Error converting address"); - exit(EXIT_FAILURE); - } - - printf("Ethernet Destination Address: %s%s\n", phdstaddr, \ - ((!idata->hdstaddr_f)?" (all-nodes multicast)":"")); + if (idata->dstaddr_f || idata->hdstaddr_f) { + if (ether_ntop(&(idata->hdstaddr), phdstaddr, sizeof(phdstaddr)) == 0) { + puts("ether_ntop(): Error converting address"); + exit(EXIT_FAILURE); + } + + printf("Ethernet Destination Address: %s%s\n", phdstaddr, + ((!idata->hdstaddr_f) ? " (all-nodes multicast)" : "")); } - if(inet_ntop(AF_INET6, &(idata->srcaddr), psrcaddr, sizeof(psrcaddr)) == NULL){ - puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); - exit(EXIT_FAILURE); - } + if (inet_ntop(AF_INET6, &(idata->srcaddr), psrcaddr, sizeof(psrcaddr)) == NULL) { + puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); + exit(EXIT_FAILURE); + } - if(!floods_f && !(idata->srcprefix_f)){ - printf("IPv6 Source Address: %s%s\n", psrcaddr, ((!idata->srcaddr_f)?" (automatically-selected)":"")); + if (!floods_f && !(idata->srcprefix_f)) { + printf("IPv6 Source Address: %s%s\n", psrcaddr, ((!idata->srcaddr_f) ? " (automatically-selected)" : "")); } - else{ - printf("IPv6 Source Address: randomized, from the %s/%u prefix%s\n", psrcaddr, idata->srcpreflen, \ - (!idata->srcprefix_f)?" (default)":""); + else { + printf("IPv6 Source Address: randomized, from the %s/%u prefix%s\n", psrcaddr, idata->srcpreflen, + (!idata->srcprefix_f) ? " (default)" : ""); } - /* IPv6 Destination Address is only used if a target IPv6 address or a target Ethernet * address were specified */ - if(idata->dstaddr_f || idata->hdstaddr_f){ - if(inet_ntop(AF_INET6, &(idata->dstaddr), pdstaddr, sizeof(pdstaddr)) == NULL){ - perror("inet_ntop()"); - exit(EXIT_FAILURE); - } - - printf("IPv6 Destination Address: %s%s\n", pdstaddr, \ - ((!idata->dstaddr_f)?" (all-nodes link-local multicast)":"")); + if (idata->dstaddr_f || idata->hdstaddr_f) { + if (inet_ntop(AF_INET6, &(idata->dstaddr), pdstaddr, sizeof(pdstaddr)) == NULL) { + perror("inet_ntop()"); + exit(EXIT_FAILURE); + } + + printf("IPv6 Destination Address: %s%s\n", pdstaddr, + ((!idata->dstaddr_f) ? " (all-nodes link-local multicast)" : "")); } - printf("IPv6 Hop Limit: %u%s\n", hoplimit, (hoplimit_f)?"":" (default)"); + printf("IPv6 Hop Limit: %u%s\n", hoplimit, (hoplimit_f) ? "" : " (default)"); - for(i=0; ifragh_f) - printf("Sending each packet in fragments of %u bytes (plus the Unfragmentable part)\n", nfrags); + if (idata->fragh_f) + printf("Sending each packet in fragments of %u bytes (plus the Unfragmentable part)\n", nfrags); - /* Should never happen, since we set this one */ - if(preference > 3){ - puts("print_attack_info(): peference value out of range"); - exit(EXIT_FAILURE); - } + /* Should never happen, since we set this one */ + if (preference > 3) { + puts("print_attack_info(): peference value out of range"); + exit(EXIT_FAILURE); + } + + printf("Cur Hop Limit: %u Preference: %s Flags: %s%s%s%s%s Router Lifetime: %u\n", curhop, + routestr[preference], ((managed_f) ? "M" : ""), ((other_f) ? "O" : ""), ((home_f) ? "H" : ""), + ((proxy_f) ? "P" : ""), ((!managed_f && !other_f && !home_f && !proxy_f) ? "none" : ""), lifetime); - printf("Cur Hop Limit: %u Preference: %s Flags: %s%s%s%s%s Router Lifetime: %u\n", \ - curhop, routestr[preference], ((managed_f)?"M":""), ((other_f)?"O":""), ((home_f)?"H":""), \ - ((proxy_f)?"P":""), ((!managed_f && !other_f && !home_f && !proxy_f)?"none":""), \ - lifetime); - printf("Reachable Time: %u Retrans Timer: %u\n", reachable, retrans); - for(i=0;i Address: %s\n", \ - ((floods_f && !sllopta_f)?"(randomized for each packet)":plinkaddr)); + printf("Source Link-layer Address option -> Address: %s\n", + ((floods_f && !sllopta_f) ? "(randomized for each packet)" : plinkaddr)); } - for(i=0;i MTU: %u\n", mtu[i]); - - if(!floodp_f){ - for(i=0; i"); - - if(inet_ntop(AF_INET6, &prefix[i], pprefix, sizeof(pprefix)) == NULL){ - perror("inet_ntop()"); - exit(EXIT_FAILURE); - } - - printf("Prefix: %s/%u\tFlags: %s%s%s%s ", pprefix, prefixlen[i], \ - ((prefixflags[i] & ND_OPT_PI_FLAG_ONLINK)?"L":""),\ - ((prefixflags[i] & ND_OPT_PI_FLAG_AUTO)?"A":""), \ - ((prefixflags[i] & ND_OPT_PI_FLAG_RADDR)?"R":""), \ - ((!prefixflags[i])?"none":"")); - - printf("Valid Lifetime: %u Preferred Lifetime: %u\n", prefixvalid[i], prefixpref[i]); - } + for (i = 0; i < nmtu; i++) + printf("MTU option -> MTU: %u\n", mtu[i]); + + if (!floodp_f) { + for (i = 0; i < nprefixes; i++) { + puts("Prefix Information option ->"); + + if (inet_ntop(AF_INET6, &prefix[i], pprefix, sizeof(pprefix)) == NULL) { + perror("inet_ntop()"); + exit(EXIT_FAILURE); + } + + printf("Prefix: %s/%u\tFlags: %s%s%s%s ", pprefix, prefixlen[i], + ((prefixflags[i] & ND_OPT_PI_FLAG_ONLINK) ? "L" : ""), + ((prefixflags[i] & ND_OPT_PI_FLAG_AUTO) ? "A" : ""), + ((prefixflags[i] & ND_OPT_PI_FLAG_RADDR) ? "R" : ""), ((!prefixflags[i]) ? "none" : "")); + + printf("Valid Lifetime: %u Preferred Lifetime: %u\n", prefixvalid[i], prefixpref[i]); + } } - else{ - printf("Flooding the target with %u prefixes\n", nprefixes); - printf("Prefix: (randomized)/%u%s Flags: %s%s%s%s ", prefixlen[0], (prefopt_f?"":" (default)"),\ - ((prefixflags[0] & ND_OPT_PI_FLAG_ONLINK)?"L":""),\ - ((prefixflags[0] & ND_OPT_PI_FLAG_AUTO)?"A":""), \ - ((prefixflags[0] & ND_OPT_PI_FLAG_RADDR)?"R":""), \ - ((!prefixflags[0])?"none":"")); - printf("Valid Lifetime: %u Preferred Lifetime: %u\n", prefixvalid[0], prefixpref[0]); + else { + printf("Flooding the target with %u prefixes\n", nprefixes); + printf("Prefix: (randomized)/%u%s Flags: %s%s%s%s ", prefixlen[0], (prefopt_f ? "" : " (default)"), + ((prefixflags[0] & ND_OPT_PI_FLAG_ONLINK) ? "L" : ""), + ((prefixflags[0] & ND_OPT_PI_FLAG_AUTO) ? "A" : ""), + ((prefixflags[0] & ND_OPT_PI_FLAG_RADDR) ? "R" : ""), ((!prefixflags[0]) ? "none" : "")); + printf("Valid Lifetime: %u Preferred Lifetime: %u\n", prefixvalid[0], prefixpref[0]); } - if(!floodr_f){ - for(i=0; i"); + if (!floodr_f) { + for (i = 0; i < nroutes; i++) { + puts("Route Information option ->"); - if(inet_ntop(AF_INET6, &route[i], pprefix, sizeof(pprefix)) == NULL){ - perror("inet_ntop()"); - exit(EXIT_FAILURE); - } + if (inet_ntop(AF_INET6, &route[i], pprefix, sizeof(pprefix)) == NULL) { + perror("inet_ntop()"); + exit(EXIT_FAILURE); + } - /* SHould never happen, since we set this one */ - if( (routepref[i]>>3) > 3){ - puts("print_attack_info(): peference value out of range"); - exit(EXIT_FAILURE); - } + /* SHould never happen, since we set this one */ + if ((routepref[i] >> 3) > 3) { + puts("print_attack_info(): peference value out of range"); + exit(EXIT_FAILURE); + } - printf("Prefix: %s/%u Preference: %s Lifetime: %u\n", pprefix, routelen[i], \ - (routestr[routepref[i]>>3]), routelife[i]); - } + printf("Prefix: %s/%u Preference: %s Lifetime: %u\n", pprefix, routelen[i], + (routestr[routepref[i] >> 3]), routelife[i]); + } } - else{ - printf("Flooding the target with %u Route Information options\n", nroutes); - printf("Prefix: (randomized)/%u Preference: %u Lifetime: %u\n", routelen[0], \ - (routepref[0]>>3), routelife[i]); + else { + printf("Flooding the target with %u Route Information options\n", nroutes); + printf("Prefix: (randomized)/%u Preference: %u Lifetime: %u\n", routelen[0], (routepref[0] >> 3), + routelife[i]); } - if(!floodd_f){ - for(i=0;i"); - printf("Lifetime: %u Addresses: ", rdnsslife[i]); - - for(j=0;j"); + printf("Lifetime: %u Addresses: ", rdnsslife[i]); + + for (j = 0; j < nrdnssopt[i]; j++) { + if (inet_ntop(AF_INET6, &rdnss[i][j], pprefix, sizeof(pprefix)) == NULL) { + perror("inet_ntop()"); + exit(EXIT_FAILURE); + } + printf("%s ", pprefix); + } + + printf("%s", (nrdnssopt[i] ? "\n" : "(empty)\n")); + } } - else{ - printf("Flooding with %u Recursive DNS Addresses, with a maximum of %u addresses per option. " - "Lifetime: %u\n", nrdnss, nflooddoa, rdnsslife[0]); + else { + printf("Flooding with %u Recursive DNS Addresses, with a maximum of %u addresses per option. " + "Lifetime: %u\n", + nrdnss, nflooddoa, rdnsslife[0]); } } - diff --git a/tools/ra6.h b/tools/ra6.h index d4d7c30..0f1412c 100644 --- a/tools/ra6.h +++ b/tools/ra6.h @@ -3,31 +3,29 @@ * */ - -#define MAX_IPV6_PAYLOAD 65535 -#define MTU_OPT_LEN 1 -#define SLLA_OPT_LEN 1 -#define PREFIX_OPT_LEN 4 +#define MAX_IPV6_PAYLOAD 65535 +#define MTU_OPT_LEN 1 +#define SLLA_OPT_LEN 1 +#define PREFIX_OPT_LEN 4 #ifndef ND_OPT_ROUTE_INFORMATION #define ND_OPT_ROUTE_INFORMATION 24 #endif #ifndef ND_OPT_RDNSS -#define ND_OPT_RDNSS 25 +#define ND_OPT_RDNSS 25 #endif #ifndef ND_OPT_PI_FLAG_RADDR -#define ND_OPT_PI_FLAG_RADDR 0x20 +#define ND_OPT_PI_FLAG_RADDR 0x20 #endif #define MAX_ROUTE_OPT_LEN 0x03 #ifndef ND_RA_FLAG_ND_PROXY -#define ND_RA_FLAG_ND_PROXY 0x04 +#define ND_RA_FLAG_ND_PROXY 0x04 #endif #ifndef ND_RA_FLAG_HOME_AGENT -#define ND_RA_FLAG_HOME_AGENT 0x20 +#define ND_RA_FLAG_HOME_AGENT 0x20 #endif - diff --git a/tools/rd6.c b/tools/rd6.c index 1a07430..06e18d9 100644 --- a/tools/rd6.c +++ b/tools/rd6.c @@ -18,2121 +18,2082 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . - * + * * Build with: make rd6 - * + * * The libpcap library must be previously installed on your system. * * Please send any bug reports to Fernando Gont */ -#include -#include #include #include +#include +#include -#include #include -#include +#include #include +#include +#include #include #include -#include -#include #include +#include #include -#include +#include #include +#include +#include #include -#include #include -#include -#include "rd6.h" -#include "libipv6.h" #include "ipv6toolkit.h" - +#include "libipv6.h" +#include "rd6.h" /* Function prototypes */ -void init_packet_data(struct iface_data *); -void send_packet(struct iface_data *, const u_char *, struct pcap_pkthdr *); -void print_attack_info(struct iface_data *); -void usage(void); -void print_help(void); - -/* Flags used for the ICMPv6 Redirect (specifically) */ -unsigned int rediraddr_f=0, redirprefix_f=0, redirport_f=0, peeraddr_f=0, peerport_f=0; -unsigned int rhtcp_f=0, rhudp_f=0, rhicmp6_f=0, norheader_f=0, rheader_f=0; -unsigned int tcpseq_f=0, tcpack_f=0, tcpurg_f=0, tcpflags_f=0, tcpwin_f=0; -unsigned int icmp6id_f=0, icmp6seq_f=0; -unsigned int rhlength_f=0, floodr_f=0, respmcast_f=0, makeonlink_f=0; -unsigned int ip6hoplimit_f=0, ip6length_f=0, rhdefault_f=0; -unsigned int learnrouter_f=0, sanityfilters_f=0; +void init_packet_data(struct iface_data *); +void send_packet(struct iface_data *, const u_char *, struct pcap_pkthdr *); +void print_attack_info(struct iface_data *); +void usage(void); +void print_help(void); + +/* Flags used for the ICMPv6 Redirect (specifically) */ +unsigned int rediraddr_f = 0, redirprefix_f = 0, redirport_f = 0, peeraddr_f = 0, peerport_f = 0; +unsigned int rhtcp_f = 0, rhudp_f = 0, rhicmp6_f = 0, norheader_f = 0, rheader_f = 0; +unsigned int tcpseq_f = 0, tcpack_f = 0, tcpurg_f = 0, tcpflags_f = 0, tcpwin_f = 0; +unsigned int icmp6id_f = 0, icmp6seq_f = 0; +unsigned int rhlength_f = 0, floodr_f = 0, respmcast_f = 0, makeonlink_f = 0; +unsigned int ip6hoplimit_f = 0, ip6length_f = 0, rhdefault_f = 0; +unsigned int learnrouter_f = 0, sanityfilters_f = 0; /* Variables used for ICMPv6 Redirect (specifically) */ -uint16_t ip6length; -struct in6_addr rediraddr, peeraddr; -unsigned char redirpreflen, targetpreflen; -uint16_t redirport, peerport, tcpurg, tcpwin, icmp6id, icmp6seq; -uint32_t tcpseq, tcpack; -uint8_t tcpflags=0, ip6hoplimit; -struct ip6_hdr *rhipv6; -struct udp_hdr *rhudp; -struct tcp_hdr *rhtcp; -struct icmp6_hdr *rhicmp6; -unsigned int nredirs, redirs; -unsigned int rhbytes, rhlength, currentsize; -unsigned char rh_hoplimit; -struct nd_opt_rd_hdr *rh; -unsigned char rhbuff[100]; /* This one must be able to hold the IPv6 header and the upper layer header */ - +uint16_t ip6length; +struct in6_addr rediraddr, peeraddr; +unsigned char redirpreflen, targetpreflen; +uint16_t redirport, peerport, tcpurg, tcpwin, icmp6id, icmp6seq; +uint32_t tcpseq, tcpack; +uint8_t tcpflags = 0, ip6hoplimit; +struct ip6_hdr *rhipv6; +struct udp_hdr *rhudp; +struct tcp_hdr *rhtcp; +struct icmp6_hdr *rhicmp6; +unsigned int nredirs, redirs; +unsigned int rhbytes, rhlength, currentsize; +unsigned char rh_hoplimit; +struct nd_opt_rd_hdr *rh; +unsigned char rhbuff[100]; /* This one must be able to hold the IPv6 header and the upper layer header */ /* Variables used for learning the default router */ -struct ether_addr router_ether, rs_ether; -struct in6_addr router_ipv6, rs_ipv6; - +struct ether_addr router_ether, rs_ether; +struct in6_addr router_ipv6, rs_ipv6; /* Data structures for packets read from the wire */ -struct pcap_pkthdr *pkthdr; -const u_char *pktdata; -unsigned char *pkt_end; -struct ether_header *pkt_ether; -struct ip6_hdr *pkt_ipv6; -struct in6_addr *pkt_ipv6addr; -unsigned int pktbytes; - - -bpf_u_int32 my_netmask; -bpf_u_int32 my_ip; -struct bpf_program pcap_filter; -char dev[64], errbuf[PCAP_ERRBUF_SIZE]; -unsigned char buffer[65556], buffrh[MIN_IPV6_HLEN + MIN_TCP_HLEN]; -unsigned char *v6buffer, *ptr, *startofprefixes; -char *pref; -struct ip6_hdr *ipv6; -struct nd_redirect *rd; -struct ether_header *ethernet; -struct nd_opt_tlla *tllaopt; -struct in6_addr targetaddr; -struct ether_addr linkaddr[MAX_TLLA_OPTION]; -unsigned int nlinkaddr=0, linkaddrs; - -char *lasts, *rpref; -char *charptr; -int nw; -unsigned long ul_res, ul_val; -unsigned int i, j, startrand; -unsigned int skip; -unsigned int ntargets, sources, nsources, targets, nsleep; - -uint16_t mask; -uint8_t hoplimit; - -char plinkaddr[ETHER_ADDR_PLEN]; -char psrcaddr[INET6_ADDRSTRLEN], pdstaddr[INET6_ADDRSTRLEN], pv6addr[INET6_ADDRSTRLEN]; -unsigned char floodt_f=0, targetaddr_f=0, useaddrkey_f=0; -unsigned char multicastdst_f=0, accepted_f=0, loop_f=0, sleep_f=0; -unsigned char tllaopt_f=0, tllaopta_f=0, targetprefix_f=0, hoplimit_f=0; -unsigned char newdata_f=0, floods_f=0; +struct pcap_pkthdr *pkthdr; +const u_char *pktdata; +unsigned char *pkt_end; +struct ether_header *pkt_ether; +struct ip6_hdr *pkt_ipv6; +struct in6_addr *pkt_ipv6addr; +unsigned int pktbytes; + +bpf_u_int32 my_netmask; +bpf_u_int32 my_ip; +struct bpf_program pcap_filter; +char dev[64], errbuf[PCAP_ERRBUF_SIZE]; +unsigned char buffer[65556], buffrh[MIN_IPV6_HLEN + MIN_TCP_HLEN]; +unsigned char *v6buffer, *ptr, *startofprefixes; +char *pref; +struct ip6_hdr *ipv6; +struct nd_redirect *rd; +struct ether_header *ethernet; +struct nd_opt_tlla *tllaopt; +struct in6_addr targetaddr; +struct ether_addr linkaddr[MAX_TLLA_OPTION]; +unsigned int nlinkaddr = 0, linkaddrs; + +char *lasts, *rpref; +char *charptr; +int nw; +unsigned long ul_res, ul_val; +unsigned int i, j, startrand; +unsigned int skip; +unsigned int ntargets, sources, nsources, targets, nsleep; + +uint16_t mask; +uint8_t hoplimit; + +char plinkaddr[ETHER_ADDR_PLEN]; +char psrcaddr[INET6_ADDRSTRLEN], pdstaddr[INET6_ADDRSTRLEN], pv6addr[INET6_ADDRSTRLEN]; +unsigned char floodt_f = 0, targetaddr_f = 0, useaddrkey_f = 0; +unsigned char multicastdst_f = 0, accepted_f = 0, loop_f = 0, sleep_f = 0; +unsigned char tllaopt_f = 0, tllaopta_f = 0, targetprefix_f = 0, hoplimit_f = 0; +unsigned char newdata_f = 0, floods_f = 0; /* Support for Extension Headers */ -unsigned int dstopthdrs, dstoptuhdrs, hbhopthdrs; -char hbhopthdr_f=0, dstoptuhdr_f=0, dstopthdr_f=0; -unsigned char *dstopthdr[MAX_DST_OPT_HDR], *dstoptuhdr[MAX_DST_OPT_U_HDR]; -unsigned char *hbhopthdr[MAX_HBH_OPT_HDR]; -unsigned int dstopthdrlen[MAX_DST_OPT_HDR], dstoptuhdrlen[MAX_DST_OPT_U_HDR]; -unsigned int hbhopthdrlen[MAX_HBH_OPT_HDR], m, pad; - -struct ip6_frag fraghdr, *fh; -struct ip6_hdr *fipv6; - -unsigned char fragbuffer[ETHER_HDR_LEN+MIN_IPV6_HLEN+MAX_IPV6_PAYLOAD]; -unsigned char *fragpart, *fptr, *fptrend, *ptrend, *ptrhdr, *ptrhdrend; -unsigned int hdrlen, ndstopthdr=0, nhbhopthdr=0, ndstoptuhdr=0; -unsigned int nfrags, fragsize; -unsigned char *prev_nh, *startoffragment; - -struct iface_data idata; -struct filters filters; - -int main(int argc, char **argv){ - extern char *optarg; - char *endptr; /* Used by strtoul() */ - int r, sel; - fd_set sset, rset; +unsigned int dstopthdrs, dstoptuhdrs, hbhopthdrs; +char hbhopthdr_f = 0, dstoptuhdr_f = 0, dstopthdr_f = 0; +unsigned char *dstopthdr[MAX_DST_OPT_HDR], *dstoptuhdr[MAX_DST_OPT_U_HDR]; +unsigned char *hbhopthdr[MAX_HBH_OPT_HDR]; +unsigned int dstopthdrlen[MAX_DST_OPT_HDR], dstoptuhdrlen[MAX_DST_OPT_U_HDR]; +unsigned int hbhopthdrlen[MAX_HBH_OPT_HDR], m, pad; + +struct ip6_frag fraghdr, *fh; +struct ip6_hdr *fipv6; + +unsigned char fragbuffer[ETHER_HDR_LEN + MIN_IPV6_HLEN + MAX_IPV6_PAYLOAD]; +unsigned char *fragpart, *fptr, *fptrend, *ptrend, *ptrhdr, *ptrhdrend; +unsigned int hdrlen, ndstopthdr = 0, nhbhopthdr = 0, ndstoptuhdr = 0; +unsigned int nfrags, fragsize; +unsigned char *prev_nh, *startoffragment; + +struct iface_data idata; +struct filters filters; + +int main(int argc, char **argv) { + extern char *optarg; + char *endptr; /* Used by strtoul() */ + int r, sel; + fd_set sset, rset; #if defined(sun) || defined(__sun) || defined(__linux__) - struct timeval timeout; + struct timeval timeout; #endif - struct target_ipv6 targetipv6; - - static struct option longopts[] = { - {"interface", required_argument, 0, 'i'}, - {"src-addr", required_argument, 0, 's'}, - {"dst-addr", required_argument, 0, 'd'}, - {"hop-limit", required_argument, 0, 'A'}, - {"dst-opt-hdr", required_argument, 0, 'u'}, - {"dst-opt-u-hdr", required_argument, 0, 'U'}, - {"hbh-opt-hdr", required_argument, 0, 'H'}, - {"frag-hdr", required_argument, 0, 'y'}, - {"link-src-addr", required_argument, 0, 'S'}, - {"link-dst-addr", required_argument, 0, 'D'}, - {"add-target-opt", no_argument, 0, 'e'}, - {"target-addr-opt", required_argument, 0, 'E'}, - {"redir-dest", required_argument, 0, 'r'}, - {"redir-target", required_argument, 0, 't'}, - {"payload-type", required_argument, 0, 'p'}, - {"payload-size", required_argument, 0, 'P'}, - {"no-payload", no_argument, 0, 'n'}, - {"ipv6-hlim", required_argument, 0, 'c'}, - {"peer-addr", required_argument, 0, 'x'}, - {"redir-port", required_argument, 0, 'o'}, - {"peer-port", required_argument, 0, 'a'}, - {"tcp-flags", required_argument, 0, 'X'}, - {"tcp-seq", required_argument, 0, 'q'}, - {"tcp-ack", required_argument, 0, 'Q'}, - {"tcp-urg", required_argument, 0, 'V'}, - {"tcp-win", required_argument, 0, 'w'}, - {"resp-mcast", no_argument, 0, 'M'}, - {"make-onlink", no_argument, 0, 'O'}, - {"learn-router", no_argument, 0, 'N'}, - {"block-src-addr", required_argument, 0, 'j'}, - {"block-dst-addr", required_argument, 0, 'k'}, - {"block-link-src-addr", required_argument, 0, 'J'}, - {"block-link-dst-addr", required_argument, 0, 'K'}, - {"accept-src-addr", required_argument, 0, 'b'}, - {"accept-dst-addr", required_argument, 0, 'g'}, - {"accept-link-src-addr", required_argument, 0, 'B'}, - {"accept-link-dst-addr", required_argument, 0, 'G'}, - {"sanity-filters", no_argument, 0, 'f'}, - {"flood-dests", required_argument, 0, 'R'}, - {"flood-targets", required_argument, 0, 'T'}, - {"flood-sources", required_argument, 0, 'F'}, - {"loop", no_argument, 0, 'l'}, - {"sleep", required_argument, 0, 'z'}, - {"listen", no_argument, 0, 'L'}, - {"verbose", no_argument, 0, 'v'}, - {"help", no_argument, 0, 'h'}, - {0, 0, 0, 0 } - }; - - const char shortopts[]= "i:s:d:A:u:U:H:y:S:D:eE:r:t:p:P:nc:x:o:a:X:q:Q:V:w:MONj:k:J:K:b:g:B:G:fR:T:F:lz:Lvh"; - - char option; - - if(argc<=1){ - usage(); - exit(EXIT_FAILURE); - } - - hoplimit=255; - - /* Initialize filters structure */ - if(init_filters(&filters) == -1){ - puts("Error initializing internal data structure"); - exit(EXIT_FAILURE); - } - - if(init_iface_data(&idata) == FAILURE){ - puts("Error initializing internal data structure"); - exit(EXIT_FAILURE); - } - - while((r=getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { - option= r; - - switch(option) { - case 'i': /* Interface */ - strncpy(idata.iface, optarg, IFACE_LENGTH); - idata.iface[IFACE_LENGTH-1]=0; - idata.iface_f=1; - break; - - case 's': /* IPv6 Source Address */ - if(idata.srcaddr_f){ - puts("Error: Multiple '-s' options have been specified"); - exit(EXIT_FAILURE); - } - - if((charptr = strtok_r(optarg, "/", &lasts)) == NULL){ - puts("Error in Source Address"); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, charptr, &(idata.srcaddr)) <= 0){ - puts("inet_pton(): Source Address not valid"); - exit(EXIT_FAILURE); - } - - idata.srcaddr_f = 1; - - if((charptr = strtok_r(NULL, " ", &lasts)) != NULL){ - idata.srcpreflen = atoi(charptr); - - if(idata.srcpreflen>128){ - puts("Prefix length error in IPv6 Source Address"); - exit(EXIT_FAILURE); - } - - if(idata.srcpreflen == 64) - useaddrkey_f= 1; - - sanitize_ipv6_prefix(&(idata.srcaddr), idata.srcpreflen); - idata.srcprefix_f=1; - } - - break; - - case 'd': /* IPv6 Destination Address */ - strncpy( targetipv6.name, optarg, NI_MAXHOST); - targetipv6.name[NI_MAXHOST-1]= 0; - targetipv6.flags= AI_CANONNAME; - - if( (r=get_ipv6_target(&targetipv6)) != 0){ - - if(r < 0){ - printf("Unknown Destination: %s\n", gai_strerror(targetipv6.res)); - } - else{ - puts("Unknown Destination: No IPv6 address found for specified destination"); - } - - exit(EXIT_FAILURE); - } - - idata.dstaddr= targetipv6.ip6; - idata.dstaddr_f = 1; - break; - - case 'A': /* Hop Limit */ - hoplimit= atoi(optarg); - hoplimit_f=1; - break; - - case 'u': /* Destinations Options Header */ - if(ndstopthdr >= MAX_DST_OPT_HDR){ - puts("Too many Destination Options Headers"); - exit(EXIT_FAILURE); - } - - hdrlen= atoi(optarg); - - if(hdrlen < 8){ - puts("Bad length in Destination Options Header"); - exit(EXIT_FAILURE); - } - - hdrlen = ((hdrlen+7)/8) * 8; - dstopthdrlen[ndstopthdr]= hdrlen; - - if( (dstopthdr[ndstopthdr]= malloc(hdrlen)) == NULL){ - puts("Not enough memory for Destination Options Header"); - exit(EXIT_FAILURE); - } - - ptrhdr= dstopthdr[ndstopthdr] + 2; - ptrhdrend= dstopthdr[ndstopthdr] + hdrlen; - - while( ptrhdr < ptrhdrend){ - - if( (ptrhdrend-ptrhdr)>257) - pad= 257; - else - pad= ptrhdrend-ptrhdr; - - if(!insert_pad_opt(ptrhdr, ptrhdrend, pad)){ - puts("Destination Options Header Too Big"); - exit(EXIT_FAILURE); - } - - ptrhdr= ptrhdr + pad; - } - - *(dstopthdr[ndstopthdr]+1)= (hdrlen/8)-1; - ndstopthdr++; - dstopthdr_f=1; - break; - - case 'U': /* Destination Options Header (Unfragmentable Part) */ - if(ndstoptuhdr >= MAX_DST_OPT_U_HDR){ - puts("Too many Destination Options Headers (Unfragmentable Part)"); - exit(EXIT_FAILURE); - } - - hdrlen= atoi(optarg); - - if(hdrlen < 8){ - puts("Bad length in Destination Options Header (Unfragmentable Part)"); - exit(EXIT_FAILURE); - } - - hdrlen = ((hdrlen+7)/8) * 8; - dstoptuhdrlen[ndstoptuhdr]= hdrlen; - - if( (dstoptuhdr[ndstoptuhdr]= malloc(hdrlen)) == NULL){ - puts("Not enough memory for Destination Options Header (Unfragmentable Part)"); - exit(EXIT_FAILURE); - } - - ptrhdr= dstoptuhdr[ndstoptuhdr]+2; - ptrhdrend= dstoptuhdr[ndstoptuhdr] + hdrlen; - - while( ptrhdr < ptrhdrend){ - - if( (ptrhdrend-ptrhdr)>257) - pad= 257; - else - pad= ptrhdrend-ptrhdr; - - if(!insert_pad_opt(ptrhdr, ptrhdrend, pad)){ - puts("Destination Options Header (Unfragmentable Part) Too Big"); - exit(EXIT_FAILURE); - } - - ptrhdr = ptrhdr + pad; - } - - *(dstoptuhdr[ndstoptuhdr]+1)= (hdrlen/8) - 1; - ndstoptuhdr++; - dstoptuhdr_f=1; - break; - - case 'H': /* Hop-by-Hop Options Header */ - if(nhbhopthdr >= MAX_HBH_OPT_HDR){ - puts("Too many Hop-by-Hop Options Headers"); - exit(EXIT_FAILURE); - } - - hdrlen= atoi(optarg); - - if(hdrlen < 8){ - puts("Bad length in Hop-by-Hop Options Header"); - exit(EXIT_FAILURE); - } - - hdrlen = ((hdrlen+7)/8) * 8; - hbhopthdrlen[nhbhopthdr]= hdrlen; - - if( (hbhopthdr[nhbhopthdr]= malloc(hdrlen)) == NULL){ - puts("Not enough memory for Hop-by-Hop Options Header"); - exit(EXIT_FAILURE); - } - - ptrhdr= hbhopthdr[nhbhopthdr] + 2; - ptrhdrend= hbhopthdr[nhbhopthdr] + hdrlen; - - - while( ptrhdr < ptrhdrend){ - - if( (ptrhdrend-ptrhdr)>257) - pad= 257; - else - pad= ptrhdrend-ptrhdr; - - if(!insert_pad_opt(ptrhdr, ptrhdrend, pad)){ - puts("Hop-by-Hop Options Header Too Big"); - exit(EXIT_FAILURE); - } - - ptrhdr = ptrhdr + pad; - } - - *(hbhopthdr[nhbhopthdr]+1)= (hdrlen/8) - 1; - nhbhopthdr++; - hbhopthdr_f=1; - break; - - case 'y': /* Fragment header */ - nfrags= atoi(optarg); - if(nfrags < 8){ - puts("Error in Fragmentation option: Fragment Size must be at least 8 bytes"); - exit(EXIT_FAILURE); - } - - idata.fragh_f= 1; - break; - - case 'S': /* Source Ethernet address */ - if(ether_pton(optarg, &idata.hsrcaddr, sizeof(idata.hsrcaddr)) == 0){ - puts("Error in Source link-layer address."); - exit(EXIT_FAILURE); - } - - idata.hsrcaddr_f = 1; - break; - - case 'D': /* Destination Ethernet Address */ - if(ether_pton(optarg, &idata.hdstaddr, sizeof(idata.hdstaddr)) == 0){ - puts("Error in Source link-layer address."); - exit(EXIT_FAILURE); - } - - idata.hdstaddr_f = 1; - break; - - case 'e': /* Add target link-layer option */ - tllaopt_f = 1; - break; - - case 'E': /* Target link-layer option */ - tllaopt_f = 1; - if(ether_pton(optarg, &linkaddr[nlinkaddr], sizeof(struct ether_addr)) == 0){ - puts("Error in Source link-layer address option."); - exit(EXIT_FAILURE); - } - - nlinkaddr++; - tllaopta_f=1; - break; - - case 'r': /* IPv6 Redirected Address */ - - if((charptr = strtok_r(optarg, "/", &lasts)) == NULL){ - puts("Error in Redirected Address"); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, charptr, &rediraddr) <= 0){ - puts("inet_pton(): Redirected Address not valid"); - exit(EXIT_FAILURE); - } - - rediraddr_f = 1; - - if((charptr = strtok_r(NULL, " ", &lasts)) != NULL){ - redirpreflen = atoi(charptr); - - if(redirpreflen>128){ - puts("Prefix length error in IPv6 Source Address"); - exit(EXIT_FAILURE); - } - - sanitize_ipv6_prefix(&rediraddr, redirpreflen); - redirprefix_f=1; - } - - break; - - case 't': /* Target Address to which traffic will be redirected */ - if((charptr = strtok_r(optarg, "/", &lasts)) == NULL){ - puts("Error in Target Address"); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, charptr, &targetaddr) <= 0){ - puts("inet_pton(): Target Address not valid"); - exit(EXIT_FAILURE); - } - - targetaddr_f = 1; - - if((charptr = strtok_r(NULL, " ", &lasts)) != NULL){ - targetpreflen = atoi(charptr); - - if(targetpreflen>128){ - puts("Prefix length error in Target Address"); - exit(EXIT_FAILURE); - } - - sanitize_ipv6_prefix(&targetaddr, targetpreflen); - targetprefix_f=1; - } - - break; - - case 'p': /* Protocol used in the redirected header */ - if(strcmp(optarg, "TCP") == 0) - rhtcp_f = 1; - else if(strcmp(optarg, "ICMP6") == 0) - rhicmp6_f = 1; - else if(strcmp(optarg, "UDP") == 0) - rhudp_f = 1; - else{ - puts("Unsupported protocol in option '-p'"); - exit(EXIT_FAILURE); - } - break; - - case 'P': /* Payload Size*/ - rhlength= atoi(optarg); - rhlength= (rhlength<<3) >> 3; /* The Redirected Header has a granularity of 8 bytes */ - rhlength_f= 1; - break; - - case 'n': /* No Redirected Header */ - norheader_f=1; - break; - - case 'c': /* Hop Limit of the IPv6 Payload */ - ip6hoplimit= atoi(optarg); - ip6hoplimit_f=1; - break; - - case 'x': /* Redirected peer address */ - strncpy( targetipv6.name, optarg, NI_MAXHOST); - targetipv6.name[NI_MAXHOST-1]= 0; - targetipv6.flags= AI_CANONNAME; - - if( (r=get_ipv6_target(&targetipv6)) != 0){ - - if(r < 0){ - printf("Unknown Destination: %s\n", gai_strerror(targetipv6.res)); - } - else{ - puts("Unknown Destination: No IPv6 address found for specified destination"); - } - - exit(EXIT_FAILURE); - } - - peeraddr= targetipv6.ip6; - peeraddr_f = 1; - break; - - case 'o': /* Redir port */ - redirport= atoi(optarg); - redirport_f= 1; - break; - - case 'a': /* Peer port */ - peerport= atoi(optarg); - peerport_f= 1; - break; - - case 'X': - charptr = optarg; - while(*charptr){ - switch(*charptr){ - case 'F': - tcpflags= tcpflags | TH_FIN; - break; - - case 'S': - tcpflags= tcpflags | TH_SYN; - break; - - case 'R': - tcpflags= tcpflags | TH_RST; - break; - - case 'P': - tcpflags= tcpflags | TH_PUSH; - break; - - case 'A': - tcpflags= tcpflags | TH_ACK; - break; - - case 'U': - tcpflags= tcpflags | TH_URG; - break; - - case 'X': /* No TCP flags */ - break; - - default: - printf("Unknown TCP flag '%c'\n", *charptr); - exit(EXIT_FAILURE); - break; - } - - if(*charptr == 'X') - break; - - charptr++; - } - - tcpflags_f=1; - break; - - case 'q': /* TCP Sequence Number */ - if((ul_res = strtoul(optarg, &endptr, 0)) == ULONG_MAX){ - perror("Error in 'TCP Sequence NUmber' parameter"); - exit(EXIT_FAILURE); - } - - if(endptr != optarg){ - tcpseq = ul_res; - tcpseq_f=1; - } - - break; - - case 'Q': /* TCP Acknowledgement Number */ - if((ul_res = strtoul(optarg, &endptr, 0)) == ULONG_MAX){ - perror("Error in 'TCP Sequence NUmber' parameter"); - exit(EXIT_FAILURE); - } - - if(endptr != optarg){ - tcpack = ul_res; - tcpack_f=1; - } - break; - - case 'V': /* TCP Urgent Pointer */ - tcpurg= atoi(optarg); - tcpurg_f= 1; - break; - - case 'w': /* TCP Window */ - tcpwin= atoi(optarg); - tcpwin_f=1; - break; - - case 'M': /* Respond to multicast packets */ - respmcast_f=1; - break; - - case 'O': /* Make Destination On-Link */ - makeonlink_f=1; - break; - - case 'N': /* Learn Router */ - learnrouter_f= 1; - break; - - case 'j': /* IPv6 Source Address (block) filter */ - if(filters.nblocksrc >= MAX_BLOCK_SRC){ - puts("Too many IPv6 Source Address (block) filters."); - exit(EXIT_FAILURE); - } - - if((pref = strtok_r(optarg, "/", &lasts)) == NULL){ - printf("Error in IPv6 Source Address (block) filter number %u.\n", \ - filters.nblocksrc+1); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, pref, &(filters.blocksrc[filters.nblocksrc])) <= 0){ - printf("Error in IPv6 Source Address (block) filter number %u.", \ - filters.nblocksrc+1); - exit(EXIT_FAILURE); - } - - if((charptr = strtok_r(NULL, " ", &lasts)) == NULL){ - filters.blocksrclen[filters.nblocksrc] = 128; - } - else{ - filters.blocksrclen[filters.nblocksrc] = atoi(charptr); - - if(filters.blocksrclen[filters.nblocksrc]>128){ - printf("Length error in IPv6 Source Address (block) filter number %u.\n", \ - filters.nblocksrc+1); - exit(EXIT_FAILURE); - } - } - - sanitize_ipv6_prefix(&(filters.blocksrc[filters.nblocksrc]), filters.blocksrclen[filters.nblocksrc]); - (filters.nblocksrc)++; - break; - - case 'k': /* IPv6 Destination Address (block) filter */ - if(filters.nblockdst >= MAX_BLOCK_DST){ - puts("Too many IPv6 Destination Address (block) filters."); - exit(EXIT_FAILURE); - } - - if((pref = strtok_r(optarg, "/", &lasts)) == NULL){ - printf("Error in IPv6 Destination Address (block) filter number %u.\n", \ - filters.nblockdst+1); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, pref, &(filters.blockdst[filters.nblockdst])) <= 0){ - printf("Error in IPv6 Source Address (block) filter number %u.", \ - filters.nblockdst+1); - exit(EXIT_FAILURE); - } - - if((charptr = strtok_r(NULL, " ", &lasts)) == NULL){ - filters.blockdstlen[filters.nblockdst] = 128; - } - else{ - filters.blockdstlen[filters.nblockdst] = atoi(charptr); - - if(filters.blockdstlen[filters.nblockdst]>128){ - printf("Length error in IPv6 Source Address (block) filter number %u.\n", \ - filters.nblockdst+1); - exit(EXIT_FAILURE); - } - } - - sanitize_ipv6_prefix(&(filters.blockdst[filters.nblockdst]), filters.blockdstlen[filters.nblockdst]); - (filters.nblockdst)++; - break; - - case 'J': /* Link Source Address (block) filter */ - if(filters.nblocklinksrc > MAX_BLOCK_LINK_SRC){ - puts("Too many link-layer Source Address (accept) filters."); - exit(EXIT_FAILURE); - } - - if(ether_pton(optarg, &(filters.blocklinksrc[filters.nblocklinksrc]), sizeof(struct ether_addr)) == 0){ - printf("Error in link-layer Source Address (blick) filter number %u.\n", \ - filters.nblocklinksrc+1); - exit(EXIT_FAILURE); - } - - (filters.nblocklinksrc)++; - break; - - case 'K': /* Link Destination Address (block) filter */ - if(filters.nblocklinkdst > MAX_BLOCK_LINK_DST){ - puts("Too many link-layer Destination Address (block) filters."); - exit(EXIT_FAILURE); - } - - if(ether_pton(optarg, &(filters.blocklinkdst[filters.nblocklinkdst]), sizeof(struct ether_addr)) == 0){ - printf("Error in link-layer Destination Address (blick) filter number %u.\n", \ - filters.nblocklinkdst+1); - exit(EXIT_FAILURE); - } - - filters.nblocklinkdst++; - break; - - case 'b': /* IPv6 Source Address (accept) filter */ - if(filters.nacceptsrc > MAX_ACCEPT_SRC){ - puts("Too many IPv6 Source Address (accept) filters."); - exit(EXIT_FAILURE); - } - - if((pref = strtok_r(optarg, "/", &lasts)) == NULL){ - printf("Error in IPv6 Source Address (accept) filter number %u.\n", \ - filters.nacceptsrc+1); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, pref, &(filters.acceptsrc[filters.nacceptsrc])) <= 0){ - printf("Error in IPv6 Source Address (accept) filter number %u.\n", \ - filters.nacceptsrc+1); - exit(EXIT_FAILURE); - } - - if((charptr = strtok_r(NULL, " ", &lasts)) == NULL){ - filters.acceptsrclen[filters.nacceptsrc] = 128; - } - else{ - filters.acceptsrclen[filters.nacceptsrc] = atoi(charptr); - - if(filters.acceptsrclen[filters.nacceptsrc]>128){ - printf("Length error in IPv6 Source Address (accept) filter number %u.\n", \ - filters.nacceptsrc+1); - exit(EXIT_FAILURE); - } - } - - sanitize_ipv6_prefix(&(filters.acceptsrc[filters.nacceptsrc]), filters.acceptsrclen[filters.nacceptsrc]); - (filters.nacceptsrc)++; - filters.acceptfilters_f=1; - break; - - - case 'g': /* IPv6 Destination Address (accept) filter */ - if(filters.nacceptdst > MAX_ACCEPT_DST){ - puts("Too many IPv6 Destination Address (accept) filters."); - exit(EXIT_FAILURE); - } - - if((pref = strtok_r(optarg, "/", &lasts)) == NULL){ - printf("Error in IPv6 Destination Address (accept) filter number %u.\n", \ - filters.nacceptdst+1); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, pref, &(filters.acceptdst[filters.nacceptdst])) <= 0){ - printf("Error in IPv6 Source Address (accept) filter number %u.\n", \ - filters.nacceptdst+1); - exit(EXIT_FAILURE); - } - - if((charptr = strtok_r(NULL, " ", &lasts)) == NULL){ - filters.acceptdstlen[filters.nacceptdst] = 128; - } - else{ - filters.acceptdstlen[filters.nacceptdst] = atoi(charptr); - - if(filters.acceptdstlen[filters.nacceptdst] > 128){ - printf("Length error in IPv6 Source Address (accept) filter number %u.\n", \ - filters.nacceptdst+1); - exit(EXIT_FAILURE); - } - } - - sanitize_ipv6_prefix(&(filters.acceptdst[filters.nacceptdst]), filters.acceptdstlen[filters.nacceptdst]); - (filters.nacceptdst)++; - filters.acceptfilters_f=1; - break; - - case 'B': /* Link-layer Source Address (accept) filter */ - if(filters.nacceptlinksrc > MAX_ACCEPT_LINK_SRC){ - puts("Too many link-later Source Address (accept) filters."); - exit(EXIT_FAILURE); - } - - if(ether_pton(optarg, &(filters.acceptlinksrc[filters.nacceptlinksrc]), sizeof(struct ether_addr)) == 0){ - printf("Error in link-layer Source Address (accept) filter number %u.\n", \ - filters.nacceptlinksrc+1); - exit(EXIT_FAILURE); - } - - (filters.nacceptlinksrc)++; - filters.acceptfilters_f=1; - break; - - case 'G': /* Link Destination Address (accept) filter */ - if(filters.nacceptlinkdst > MAX_ACCEPT_LINK_DST){ - puts("Too many link-layer Destination Address (accept) filters."); - exit(EXIT_FAILURE); - } - - if(ether_pton(optarg, &(filters.acceptlinkdst[filters.nacceptlinkdst]), sizeof(struct ether_addr)) == 0){ - printf("Error in link-layer Destination Address (accept) filter number %u.\n",\ - filters.nacceptlinkdst+1); - exit(EXIT_FAILURE); - } - - (filters.nacceptlinkdst)++; - filters.acceptfilters_f=1; - break; - - case 'f': /* Sanity filters */ - sanityfilters_f=1; - break; - - case 'R': /* Flood Redirected */ - nredirs= atoi(optarg); - - if(nredirs == 0){ - puts("Invalid number of Redirects in option -R"); - exit(EXIT_FAILURE); - } - - floodr_f= 1; - break; - - case 'T': /* Flood targets */ - ntargets= atoi(optarg); - if(ntargets == 0){ - puts("Invalid number of Target Addresses in option -T"); - exit(EXIT_FAILURE); - } - - floodt_f= 1; - break; - - case 'F': /* Flood sources */ - nsources= atoi(optarg); - if(nsources == 0){ - puts("Invalid number of sources in option -F"); - exit(EXIT_FAILURE); - } - - floods_f= 1; - break; - - case 'l': /* "Loop mode */ - loop_f = 1; - break; - - case 'z': /* Sleep option */ - nsleep=atoi(optarg); - if(nsleep==0){ - puts("Invalid number of seconds in '-z' option"); - exit(EXIT_FAILURE); - } - - sleep_f=1; - break; - - case 'L': /* "Listen mode */ - idata.listen_f = 1; - break; - - case 'v': /* Be verbose */ - idata.verbose_f++; - break; - - case 'h': /* Help */ - print_help(); - - exit(EXIT_FAILURE); - break; - - default: - usage(); - exit(EXIT_FAILURE); - break; - - } /* switch */ - } /* while(getopt) */ - - if(geteuid()) { - puts("rd6 needs root privileges to run."); - exit(EXIT_FAILURE); - } - - if(!idata.iface_f){ - if(idata.dstaddr_f && IN6_IS_ADDR_LINKLOCAL(&(idata.dstaddr))){ - puts("Must specify a network interface for link-local destinations"); - exit(EXIT_FAILURE); - } - else if(idata.listen_f){ - puts("Must specify a network interface when employing the 'listenging' mode"); - exit(EXIT_FAILURE); - } - } - - if(idata.listen_f && loop_f){ - puts("'Error: listen' mode and 'loop' mode are incompatible"); - exit(EXIT_FAILURE); - } - - /* - If the flood option ("-F") has been specified, but no prefix has been specified, - select the random Source Addresses from the link-local unicast prefix (fe80::/64). - */ - if(floods_f && !idata.srcprefix_f){ - if ( inet_pton(AF_INET6, "fe80::", &(idata.srcaddr)) <= 0){ - puts("inet_pton(): Error when converting address"); - exit(EXIT_FAILURE); - } - - randomize_ipv6_addr(&(idata.srcaddr), &(idata.srcaddr), 64); - idata.srcpreflen=64; - } - - if(!floods_f && !idata.srcaddr_f && !learnrouter_f){ - puts("Must specify IPv6 Source Address (usually to that of the current default router)"); - exit(EXIT_FAILURE); - } - - if(!idata.dstaddr_f && !idata.listen_f){ /* Must specify IPv6 Destination Address if listening mode not used */ - puts("IPv6 Destination Address not specified (and listening mode not selected)"); - exit(EXIT_FAILURE); - } - - if(!idata.hsrcaddr_f && !learnrouter_f) /* Source link-layer address is randomized by default */ - randomize_ether_addr(&(idata.hsrcaddr)); - - if(!idata.hdstaddr_f && idata.dstaddr_f){ - if(ether_pton(ETHER_ALLNODES_LINK_ADDR, &idata.hdstaddr, sizeof(idata.hdstaddr)) == 0){ - puts("ether_pton(): Error converting all-nodes multicast address"); - exit(EXIT_FAILURE); - } - } - - if(load_dst_and_pcap(&idata, (idata.dstaddr_f?LOAD_SRC_NXT_HOP:LOAD_PCAP_ONLY)) == FAILURE){ - puts("Error while learning Source Address and Next Hop"); - exit(EXIT_FAILURE); - } - - if(learnrouter_f){ - randomize_ether_addr(&rs_ether); - ether_to_ipv6_linklocal(&rs_ether, &rs_ipv6); - - if(find_ipv6_router(idata.pfd, &rs_ether, &rs_ipv6, &router_ether, &router_ipv6) != 0){ - puts("Failed learning default IPv6 router"); - exit(EXIT_FAILURE); - } - - if(!idata.hsrcaddr_f){ - idata.hsrcaddr= router_ether; - idata.hsrcaddr_f=1; - } - - if(!idata.srcaddr_f){ - idata.srcaddr= router_ipv6; - idata.srcaddr_f= 1; - } - } - - release_privileges(); - srandom(time(NULL)); - - if(tllaopt_f && !tllaopta_f){ - if(idata.hsrcaddr_f){ /* The value of the target link-layer address */ - linkaddr[0] = idata.hsrcaddr; /* option defaults to the Ethernet Source Address */ - nlinkaddr++; - } - else{ - puts("Must specify the link-layer Source Address when the '-e' option is selected"); - exit(EXIT_FAILURE); - } - } - - - /* - If the flood target option ("-T") was specified, but no prefix was specified, - select the random Target Addresses from the link-local unicast prefix (fe80::/64). - */ - if(floodt_f && !targetprefix_f){ - if ( inet_pton(AF_INET6, "fe80::", &targetaddr) <= 0){ - puts("inet_pton(): Error when converting address"); - exit(EXIT_FAILURE); - } - - randomize_ipv6_addr(&targetaddr, &targetaddr, 64); - targetpreflen=64; - } - - if(!floodt_f && !targetaddr_f){ - if(!makeonlink_f){ - puts("Must specify Redirect Target Address"); - exit(EXIT_FAILURE); - } - else if(!floodr_f){ - targetaddr= rediraddr; - targetaddr_f=1; - } - } - - - /* If the "flood destination" option was set, but no prefix was specified for the - "redirected destination", we select random addresses (from ::/0) - */ - if(floodr_f && !redirprefix_f){ - for(i=0;i<16;i++) - rediraddr.s6_addr[i]=0x00; - - redirpreflen=0; - } - - if(!floods_f) - nsources=1; - - if(!floodt_f) - ntargets=1; - - if(!floodr_f) - nredirs=1; - - if(sanityfilters_f){ - if(filters.nacceptlinkdst > MAX_ACCEPT_LINK_DST){ - puts("Too many link-layer Destination Address (accept) filters while adding sanity filters."); - exit(EXIT_FAILURE); - } - - if(learnrouter_f) - filters.acceptlinkdst[filters.nacceptlinkdst]= router_ether; - else - filters.acceptlinkdst[filters.nacceptlinkdst]= idata.hsrcaddr; - - filters.nacceptlinkdst++; - filters.acceptfilters_f=1; - - - if(filters.nblocksrc >= MAX_BLOCK_SRC){ - puts("Too many IPv6 Source Address (block) filters while adding sanity filters."); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, "fe80::", &(filters.blocksrc[filters.nblocksrc])) <= 0){ - puts("Error while adding sanity filter for link-local addresses."); - exit(EXIT_FAILURE); - } - - filters.blocksrclen[filters.nblocksrc] = 16; - filters.nblocksrc++; - } - - if(!sleep_f) - nsleep=1; - - if( !idata.fragh_f && dstoptuhdr_f){ - puts("Dst. Options Header (Unfragmentable Part) set, but Fragmentation not specified"); - exit(EXIT_FAILURE); - } - - if(!norheader_f && !(rhtcp_f || rhudp_f || rhicmp6_f)) - rhdefault_f=1; - - if(!ip6hoplimit_f) - ip6hoplimit=255; - - if(!ip6length_f) - ip6length=1460; - - if(!peeraddr_f) - peeraddr= idata.dstaddr; - - if(rhtcp_f || rhdefault_f){ - if(!tcpflags_f) - tcpflags= tcpflags | TH_ACK; - - if(!tcpack_f) - tcpack= random(); - - if(!tcpseq_f) - tcpseq= random(); - - if(!tcpwin_f) - tcpwin= ((uint16_t) random() + 1500) & (uint16_t)0x7f00; - - if(!peerport_f) - peerport= random(); - - if(!redirport_f) - redirport= random(); - - if(!tcpurg_f) - tcpurg= 0; - } - - if(rhudp_f){ - if(!peerport_f) - peerport= random(); - - if(!redirport_f) - redirport= random(); - } - - if(rhicmp6_f){ - if(!icmp6id_f) - icmp6id= random(); - - if(!icmp6seq_f) - icmp6seq= random(); - } - - if(idata.verbose_f){ - print_attack_info(&idata); - } - - - /* - Set filter for IPv6 packets (find_ipv6_router() set its own filters before receiving RAs) - */ - if(pcap_compile(idata.pfd, &pcap_filter, PCAP_IPV6_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1){ - printf("pcap_compile(): %s", pcap_geterr(idata.pfd)); - exit(EXIT_FAILURE); - } - - if(pcap_setfilter(idata.pfd, &pcap_filter) == -1){ - printf("pcap_setfilter(): %s", pcap_geterr(idata.pfd)); - exit(EXIT_FAILURE); - } - - pcap_freecode(&pcap_filter); - - /* Set initial contents of the attack packet */ - init_packet_data(&idata); - - /* Fire an ICMPv6 Redirect if an IPv6 Destination Address was specified */ - if((idata.dstaddr_f) && (targetaddr_f || floodt_f) && (rediraddr_f || floodr_f)){ - send_packet(&idata, NULL, NULL); - if(idata.verbose_f) - puts("Initial attack packet(s) sent successfully."); - - if(loop_f){ - if(idata.verbose_f) - printf("Now sending Redirect Messages every %u second%s...\n", nsleep, \ - ((nsleep>1)?"s":"")); - while(loop_f){ - sleep(nsleep); - send_packet(&idata, NULL, NULL); - } - } - - exit(EXIT_SUCCESS); - } - - if(idata.listen_f){ - if(idata.verbose_f){ - print_filters(&idata, &filters); - puts("Listening to incoming IPv6 messages..."); - } - - FD_ZERO(&sset); - FD_SET(idata.fd, &sset); - - while(idata.listen_f){ - rset= sset; + struct target_ipv6 targetipv6; + + static struct option longopts[] = {{"interface", required_argument, 0, 'i'}, + {"src-addr", required_argument, 0, 's'}, + {"dst-addr", required_argument, 0, 'd'}, + {"hop-limit", required_argument, 0, 'A'}, + {"dst-opt-hdr", required_argument, 0, 'u'}, + {"dst-opt-u-hdr", required_argument, 0, 'U'}, + {"hbh-opt-hdr", required_argument, 0, 'H'}, + {"frag-hdr", required_argument, 0, 'y'}, + {"link-src-addr", required_argument, 0, 'S'}, + {"link-dst-addr", required_argument, 0, 'D'}, + {"add-target-opt", no_argument, 0, 'e'}, + {"target-addr-opt", required_argument, 0, 'E'}, + {"redir-dest", required_argument, 0, 'r'}, + {"redir-target", required_argument, 0, 't'}, + {"payload-type", required_argument, 0, 'p'}, + {"payload-size", required_argument, 0, 'P'}, + {"no-payload", no_argument, 0, 'n'}, + {"ipv6-hlim", required_argument, 0, 'c'}, + {"peer-addr", required_argument, 0, 'x'}, + {"redir-port", required_argument, 0, 'o'}, + {"peer-port", required_argument, 0, 'a'}, + {"tcp-flags", required_argument, 0, 'X'}, + {"tcp-seq", required_argument, 0, 'q'}, + {"tcp-ack", required_argument, 0, 'Q'}, + {"tcp-urg", required_argument, 0, 'V'}, + {"tcp-win", required_argument, 0, 'w'}, + {"resp-mcast", no_argument, 0, 'M'}, + {"make-onlink", no_argument, 0, 'O'}, + {"learn-router", no_argument, 0, 'N'}, + {"block-src-addr", required_argument, 0, 'j'}, + {"block-dst-addr", required_argument, 0, 'k'}, + {"block-link-src-addr", required_argument, 0, 'J'}, + {"block-link-dst-addr", required_argument, 0, 'K'}, + {"accept-src-addr", required_argument, 0, 'b'}, + {"accept-dst-addr", required_argument, 0, 'g'}, + {"accept-link-src-addr", required_argument, 0, 'B'}, + {"accept-link-dst-addr", required_argument, 0, 'G'}, + {"sanity-filters", no_argument, 0, 'f'}, + {"flood-dests", required_argument, 0, 'R'}, + {"flood-targets", required_argument, 0, 'T'}, + {"flood-sources", required_argument, 0, 'F'}, + {"loop", no_argument, 0, 'l'}, + {"sleep", required_argument, 0, 'z'}, + {"listen", no_argument, 0, 'L'}, + {"verbose", no_argument, 0, 'v'}, + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0}}; + + const char shortopts[] = "i:s:d:A:u:U:H:y:S:D:eE:r:t:p:P:nc:x:o:a:X:q:Q:V:w:MONj:k:J:K:b:g:B:G:fR:T:F:lz:Lvh"; + + char option; + + if (argc <= 1) { + usage(); + exit(EXIT_FAILURE); + } + + hoplimit = 255; + + /* Initialize filters structure */ + if (init_filters(&filters) == -1) { + puts("Error initializing internal data structure"); + exit(EXIT_FAILURE); + } + + if (init_iface_data(&idata) == FAILURE) { + puts("Error initializing internal data structure"); + exit(EXIT_FAILURE); + } + + while ((r = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { + option = r; + + switch (option) { + case 'i': /* Interface */ + strncpy(idata.iface, optarg, IFACE_LENGTH); + idata.iface[IFACE_LENGTH - 1] = 0; + idata.iface_f = 1; + break; + + case 's': /* IPv6 Source Address */ + if (idata.srcaddr_f) { + puts("Error: Multiple '-s' options have been specified"); + exit(EXIT_FAILURE); + } + + if ((charptr = strtok_r(optarg, "/", &lasts)) == NULL) { + puts("Error in Source Address"); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, charptr, &(idata.srcaddr)) <= 0) { + puts("inet_pton(): Source Address not valid"); + exit(EXIT_FAILURE); + } + + idata.srcaddr_f = 1; + + if ((charptr = strtok_r(NULL, " ", &lasts)) != NULL) { + idata.srcpreflen = atoi(charptr); + + if (idata.srcpreflen > 128) { + puts("Prefix length error in IPv6 Source Address"); + exit(EXIT_FAILURE); + } + + if (idata.srcpreflen == 64) + useaddrkey_f = 1; + + sanitize_ipv6_prefix(&(idata.srcaddr), idata.srcpreflen); + idata.srcprefix_f = 1; + } + + break; + + case 'd': /* IPv6 Destination Address */ + strncpy(targetipv6.name, optarg, NI_MAXHOST); + targetipv6.name[NI_MAXHOST - 1] = 0; + targetipv6.flags = AI_CANONNAME; + + if ((r = get_ipv6_target(&targetipv6)) != 0) { + + if (r < 0) { + printf("Unknown Destination: %s\n", gai_strerror(targetipv6.res)); + } + else { + puts("Unknown Destination: No IPv6 address found for specified destination"); + } + + exit(EXIT_FAILURE); + } + + idata.dstaddr = targetipv6.ip6; + idata.dstaddr_f = 1; + break; + + case 'A': /* Hop Limit */ + hoplimit = atoi(optarg); + hoplimit_f = 1; + break; + + case 'u': /* Destinations Options Header */ + if (ndstopthdr >= MAX_DST_OPT_HDR) { + puts("Too many Destination Options Headers"); + exit(EXIT_FAILURE); + } + + hdrlen = atoi(optarg); + + if (hdrlen < 8) { + puts("Bad length in Destination Options Header"); + exit(EXIT_FAILURE); + } + + hdrlen = ((hdrlen + 7) / 8) * 8; + dstopthdrlen[ndstopthdr] = hdrlen; + + if ((dstopthdr[ndstopthdr] = malloc(hdrlen)) == NULL) { + puts("Not enough memory for Destination Options Header"); + exit(EXIT_FAILURE); + } + + ptrhdr = dstopthdr[ndstopthdr] + 2; + ptrhdrend = dstopthdr[ndstopthdr] + hdrlen; + + while (ptrhdr < ptrhdrend) { + + if ((ptrhdrend - ptrhdr) > 257) + pad = 257; + else + pad = ptrhdrend - ptrhdr; + + if (!insert_pad_opt(ptrhdr, ptrhdrend, pad)) { + puts("Destination Options Header Too Big"); + exit(EXIT_FAILURE); + } + + ptrhdr = ptrhdr + pad; + } + + *(dstopthdr[ndstopthdr] + 1) = (hdrlen / 8) - 1; + ndstopthdr++; + dstopthdr_f = 1; + break; + + case 'U': /* Destination Options Header (Unfragmentable Part) */ + if (ndstoptuhdr >= MAX_DST_OPT_U_HDR) { + puts("Too many Destination Options Headers (Unfragmentable Part)"); + exit(EXIT_FAILURE); + } + + hdrlen = atoi(optarg); + + if (hdrlen < 8) { + puts("Bad length in Destination Options Header (Unfragmentable Part)"); + exit(EXIT_FAILURE); + } + + hdrlen = ((hdrlen + 7) / 8) * 8; + dstoptuhdrlen[ndstoptuhdr] = hdrlen; + + if ((dstoptuhdr[ndstoptuhdr] = malloc(hdrlen)) == NULL) { + puts("Not enough memory for Destination Options Header (Unfragmentable Part)"); + exit(EXIT_FAILURE); + } + + ptrhdr = dstoptuhdr[ndstoptuhdr] + 2; + ptrhdrend = dstoptuhdr[ndstoptuhdr] + hdrlen; + + while (ptrhdr < ptrhdrend) { + + if ((ptrhdrend - ptrhdr) > 257) + pad = 257; + else + pad = ptrhdrend - ptrhdr; + + if (!insert_pad_opt(ptrhdr, ptrhdrend, pad)) { + puts("Destination Options Header (Unfragmentable Part) Too Big"); + exit(EXIT_FAILURE); + } + + ptrhdr = ptrhdr + pad; + } + + *(dstoptuhdr[ndstoptuhdr] + 1) = (hdrlen / 8) - 1; + ndstoptuhdr++; + dstoptuhdr_f = 1; + break; + + case 'H': /* Hop-by-Hop Options Header */ + if (nhbhopthdr >= MAX_HBH_OPT_HDR) { + puts("Too many Hop-by-Hop Options Headers"); + exit(EXIT_FAILURE); + } + + hdrlen = atoi(optarg); + + if (hdrlen < 8) { + puts("Bad length in Hop-by-Hop Options Header"); + exit(EXIT_FAILURE); + } + + hdrlen = ((hdrlen + 7) / 8) * 8; + hbhopthdrlen[nhbhopthdr] = hdrlen; + + if ((hbhopthdr[nhbhopthdr] = malloc(hdrlen)) == NULL) { + puts("Not enough memory for Hop-by-Hop Options Header"); + exit(EXIT_FAILURE); + } + + ptrhdr = hbhopthdr[nhbhopthdr] + 2; + ptrhdrend = hbhopthdr[nhbhopthdr] + hdrlen; + + while (ptrhdr < ptrhdrend) { + + if ((ptrhdrend - ptrhdr) > 257) + pad = 257; + else + pad = ptrhdrend - ptrhdr; + + if (!insert_pad_opt(ptrhdr, ptrhdrend, pad)) { + puts("Hop-by-Hop Options Header Too Big"); + exit(EXIT_FAILURE); + } + + ptrhdr = ptrhdr + pad; + } + + *(hbhopthdr[nhbhopthdr] + 1) = (hdrlen / 8) - 1; + nhbhopthdr++; + hbhopthdr_f = 1; + break; + + case 'y': /* Fragment header */ + nfrags = atoi(optarg); + if (nfrags < 8) { + puts("Error in Fragmentation option: Fragment Size must be at least 8 bytes"); + exit(EXIT_FAILURE); + } + + idata.fragh_f = 1; + break; + + case 'S': /* Source Ethernet address */ + if (ether_pton(optarg, &idata.hsrcaddr, sizeof(idata.hsrcaddr)) == 0) { + puts("Error in Source link-layer address."); + exit(EXIT_FAILURE); + } + + idata.hsrcaddr_f = 1; + break; + + case 'D': /* Destination Ethernet Address */ + if (ether_pton(optarg, &idata.hdstaddr, sizeof(idata.hdstaddr)) == 0) { + puts("Error in Source link-layer address."); + exit(EXIT_FAILURE); + } + + idata.hdstaddr_f = 1; + break; + + case 'e': /* Add target link-layer option */ + tllaopt_f = 1; + break; + + case 'E': /* Target link-layer option */ + tllaopt_f = 1; + if (ether_pton(optarg, &linkaddr[nlinkaddr], sizeof(struct ether_addr)) == 0) { + puts("Error in Source link-layer address option."); + exit(EXIT_FAILURE); + } + + nlinkaddr++; + tllaopta_f = 1; + break; + + case 'r': /* IPv6 Redirected Address */ + + if ((charptr = strtok_r(optarg, "/", &lasts)) == NULL) { + puts("Error in Redirected Address"); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, charptr, &rediraddr) <= 0) { + puts("inet_pton(): Redirected Address not valid"); + exit(EXIT_FAILURE); + } + + rediraddr_f = 1; + + if ((charptr = strtok_r(NULL, " ", &lasts)) != NULL) { + redirpreflen = atoi(charptr); + + if (redirpreflen > 128) { + puts("Prefix length error in IPv6 Source Address"); + exit(EXIT_FAILURE); + } + + sanitize_ipv6_prefix(&rediraddr, redirpreflen); + redirprefix_f = 1; + } + + break; + + case 't': /* Target Address to which traffic will be redirected */ + if ((charptr = strtok_r(optarg, "/", &lasts)) == NULL) { + puts("Error in Target Address"); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, charptr, &targetaddr) <= 0) { + puts("inet_pton(): Target Address not valid"); + exit(EXIT_FAILURE); + } + + targetaddr_f = 1; + + if ((charptr = strtok_r(NULL, " ", &lasts)) != NULL) { + targetpreflen = atoi(charptr); + + if (targetpreflen > 128) { + puts("Prefix length error in Target Address"); + exit(EXIT_FAILURE); + } + + sanitize_ipv6_prefix(&targetaddr, targetpreflen); + targetprefix_f = 1; + } + + break; + + case 'p': /* Protocol used in the redirected header */ + if (strcmp(optarg, "TCP") == 0) + rhtcp_f = 1; + else if (strcmp(optarg, "ICMP6") == 0) + rhicmp6_f = 1; + else if (strcmp(optarg, "UDP") == 0) + rhudp_f = 1; + else { + puts("Unsupported protocol in option '-p'"); + exit(EXIT_FAILURE); + } + break; + + case 'P': /* Payload Size*/ + rhlength = atoi(optarg); + rhlength = (rhlength << 3) >> 3; /* The Redirected Header has a granularity of 8 bytes */ + rhlength_f = 1; + break; + + case 'n': /* No Redirected Header */ + norheader_f = 1; + break; + + case 'c': /* Hop Limit of the IPv6 Payload */ + ip6hoplimit = atoi(optarg); + ip6hoplimit_f = 1; + break; + + case 'x': /* Redirected peer address */ + strncpy(targetipv6.name, optarg, NI_MAXHOST); + targetipv6.name[NI_MAXHOST - 1] = 0; + targetipv6.flags = AI_CANONNAME; + + if ((r = get_ipv6_target(&targetipv6)) != 0) { + + if (r < 0) { + printf("Unknown Destination: %s\n", gai_strerror(targetipv6.res)); + } + else { + puts("Unknown Destination: No IPv6 address found for specified destination"); + } + + exit(EXIT_FAILURE); + } + + peeraddr = targetipv6.ip6; + peeraddr_f = 1; + break; + + case 'o': /* Redir port */ + redirport = atoi(optarg); + redirport_f = 1; + break; + + case 'a': /* Peer port */ + peerport = atoi(optarg); + peerport_f = 1; + break; + + case 'X': + charptr = optarg; + while (*charptr) { + switch (*charptr) { + case 'F': + tcpflags = tcpflags | TH_FIN; + break; + + case 'S': + tcpflags = tcpflags | TH_SYN; + break; + + case 'R': + tcpflags = tcpflags | TH_RST; + break; + + case 'P': + tcpflags = tcpflags | TH_PUSH; + break; + + case 'A': + tcpflags = tcpflags | TH_ACK; + break; + + case 'U': + tcpflags = tcpflags | TH_URG; + break; + + case 'X': /* No TCP flags */ + break; + + default: + printf("Unknown TCP flag '%c'\n", *charptr); + exit(EXIT_FAILURE); + break; + } + + if (*charptr == 'X') + break; + + charptr++; + } + + tcpflags_f = 1; + break; + + case 'q': /* TCP Sequence Number */ + if ((ul_res = strtoul(optarg, &endptr, 0)) == ULONG_MAX) { + perror("Error in 'TCP Sequence NUmber' parameter"); + exit(EXIT_FAILURE); + } + + if (endptr != optarg) { + tcpseq = ul_res; + tcpseq_f = 1; + } + + break; + + case 'Q': /* TCP Acknowledgement Number */ + if ((ul_res = strtoul(optarg, &endptr, 0)) == ULONG_MAX) { + perror("Error in 'TCP Sequence NUmber' parameter"); + exit(EXIT_FAILURE); + } + + if (endptr != optarg) { + tcpack = ul_res; + tcpack_f = 1; + } + break; + + case 'V': /* TCP Urgent Pointer */ + tcpurg = atoi(optarg); + tcpurg_f = 1; + break; + + case 'w': /* TCP Window */ + tcpwin = atoi(optarg); + tcpwin_f = 1; + break; + + case 'M': /* Respond to multicast packets */ + respmcast_f = 1; + break; + + case 'O': /* Make Destination On-Link */ + makeonlink_f = 1; + break; + + case 'N': /* Learn Router */ + learnrouter_f = 1; + break; + + case 'j': /* IPv6 Source Address (block) filter */ + if (filters.nblocksrc >= MAX_BLOCK_SRC) { + puts("Too many IPv6 Source Address (block) filters."); + exit(EXIT_FAILURE); + } + + if ((pref = strtok_r(optarg, "/", &lasts)) == NULL) { + printf("Error in IPv6 Source Address (block) filter number %u.\n", filters.nblocksrc + 1); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, pref, &(filters.blocksrc[filters.nblocksrc])) <= 0) { + printf("Error in IPv6 Source Address (block) filter number %u.", filters.nblocksrc + 1); + exit(EXIT_FAILURE); + } + + if ((charptr = strtok_r(NULL, " ", &lasts)) == NULL) { + filters.blocksrclen[filters.nblocksrc] = 128; + } + else { + filters.blocksrclen[filters.nblocksrc] = atoi(charptr); + + if (filters.blocksrclen[filters.nblocksrc] > 128) { + printf("Length error in IPv6 Source Address (block) filter number %u.\n", filters.nblocksrc + 1); + exit(EXIT_FAILURE); + } + } + + sanitize_ipv6_prefix(&(filters.blocksrc[filters.nblocksrc]), filters.blocksrclen[filters.nblocksrc]); + (filters.nblocksrc)++; + break; + + case 'k': /* IPv6 Destination Address (block) filter */ + if (filters.nblockdst >= MAX_BLOCK_DST) { + puts("Too many IPv6 Destination Address (block) filters."); + exit(EXIT_FAILURE); + } + + if ((pref = strtok_r(optarg, "/", &lasts)) == NULL) { + printf("Error in IPv6 Destination Address (block) filter number %u.\n", filters.nblockdst + 1); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, pref, &(filters.blockdst[filters.nblockdst])) <= 0) { + printf("Error in IPv6 Source Address (block) filter number %u.", filters.nblockdst + 1); + exit(EXIT_FAILURE); + } + + if ((charptr = strtok_r(NULL, " ", &lasts)) == NULL) { + filters.blockdstlen[filters.nblockdst] = 128; + } + else { + filters.blockdstlen[filters.nblockdst] = atoi(charptr); + + if (filters.blockdstlen[filters.nblockdst] > 128) { + printf("Length error in IPv6 Source Address (block) filter number %u.\n", filters.nblockdst + 1); + exit(EXIT_FAILURE); + } + } + + sanitize_ipv6_prefix(&(filters.blockdst[filters.nblockdst]), filters.blockdstlen[filters.nblockdst]); + (filters.nblockdst)++; + break; + + case 'J': /* Link Source Address (block) filter */ + if (filters.nblocklinksrc > MAX_BLOCK_LINK_SRC) { + puts("Too many link-layer Source Address (accept) filters."); + exit(EXIT_FAILURE); + } + + if (ether_pton(optarg, &(filters.blocklinksrc[filters.nblocklinksrc]), sizeof(struct ether_addr)) == 0) { + printf("Error in link-layer Source Address (blick) filter number %u.\n", filters.nblocklinksrc + 1); + exit(EXIT_FAILURE); + } + + (filters.nblocklinksrc)++; + break; + + case 'K': /* Link Destination Address (block) filter */ + if (filters.nblocklinkdst > MAX_BLOCK_LINK_DST) { + puts("Too many link-layer Destination Address (block) filters."); + exit(EXIT_FAILURE); + } + + if (ether_pton(optarg, &(filters.blocklinkdst[filters.nblocklinkdst]), sizeof(struct ether_addr)) == 0) { + printf("Error in link-layer Destination Address (blick) filter number %u.\n", + filters.nblocklinkdst + 1); + exit(EXIT_FAILURE); + } + + filters.nblocklinkdst++; + break; + + case 'b': /* IPv6 Source Address (accept) filter */ + if (filters.nacceptsrc > MAX_ACCEPT_SRC) { + puts("Too many IPv6 Source Address (accept) filters."); + exit(EXIT_FAILURE); + } + + if ((pref = strtok_r(optarg, "/", &lasts)) == NULL) { + printf("Error in IPv6 Source Address (accept) filter number %u.\n", filters.nacceptsrc + 1); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, pref, &(filters.acceptsrc[filters.nacceptsrc])) <= 0) { + printf("Error in IPv6 Source Address (accept) filter number %u.\n", filters.nacceptsrc + 1); + exit(EXIT_FAILURE); + } + + if ((charptr = strtok_r(NULL, " ", &lasts)) == NULL) { + filters.acceptsrclen[filters.nacceptsrc] = 128; + } + else { + filters.acceptsrclen[filters.nacceptsrc] = atoi(charptr); + + if (filters.acceptsrclen[filters.nacceptsrc] > 128) { + printf("Length error in IPv6 Source Address (accept) filter number %u.\n", filters.nacceptsrc + 1); + exit(EXIT_FAILURE); + } + } + + sanitize_ipv6_prefix(&(filters.acceptsrc[filters.nacceptsrc]), filters.acceptsrclen[filters.nacceptsrc]); + (filters.nacceptsrc)++; + filters.acceptfilters_f = 1; + break; + + case 'g': /* IPv6 Destination Address (accept) filter */ + if (filters.nacceptdst > MAX_ACCEPT_DST) { + puts("Too many IPv6 Destination Address (accept) filters."); + exit(EXIT_FAILURE); + } + + if ((pref = strtok_r(optarg, "/", &lasts)) == NULL) { + printf("Error in IPv6 Destination Address (accept) filter number %u.\n", filters.nacceptdst + 1); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, pref, &(filters.acceptdst[filters.nacceptdst])) <= 0) { + printf("Error in IPv6 Source Address (accept) filter number %u.\n", filters.nacceptdst + 1); + exit(EXIT_FAILURE); + } + + if ((charptr = strtok_r(NULL, " ", &lasts)) == NULL) { + filters.acceptdstlen[filters.nacceptdst] = 128; + } + else { + filters.acceptdstlen[filters.nacceptdst] = atoi(charptr); + + if (filters.acceptdstlen[filters.nacceptdst] > 128) { + printf("Length error in IPv6 Source Address (accept) filter number %u.\n", filters.nacceptdst + 1); + exit(EXIT_FAILURE); + } + } + + sanitize_ipv6_prefix(&(filters.acceptdst[filters.nacceptdst]), filters.acceptdstlen[filters.nacceptdst]); + (filters.nacceptdst)++; + filters.acceptfilters_f = 1; + break; + + case 'B': /* Link-layer Source Address (accept) filter */ + if (filters.nacceptlinksrc > MAX_ACCEPT_LINK_SRC) { + puts("Too many link-later Source Address (accept) filters."); + exit(EXIT_FAILURE); + } + + if (ether_pton(optarg, &(filters.acceptlinksrc[filters.nacceptlinksrc]), sizeof(struct ether_addr)) == 0) { + printf("Error in link-layer Source Address (accept) filter number %u.\n", filters.nacceptlinksrc + 1); + exit(EXIT_FAILURE); + } + + (filters.nacceptlinksrc)++; + filters.acceptfilters_f = 1; + break; + + case 'G': /* Link Destination Address (accept) filter */ + if (filters.nacceptlinkdst > MAX_ACCEPT_LINK_DST) { + puts("Too many link-layer Destination Address (accept) filters."); + exit(EXIT_FAILURE); + } + + if (ether_pton(optarg, &(filters.acceptlinkdst[filters.nacceptlinkdst]), sizeof(struct ether_addr)) == 0) { + printf("Error in link-layer Destination Address (accept) filter number %u.\n", + filters.nacceptlinkdst + 1); + exit(EXIT_FAILURE); + } + + (filters.nacceptlinkdst)++; + filters.acceptfilters_f = 1; + break; + + case 'f': /* Sanity filters */ + sanityfilters_f = 1; + break; + + case 'R': /* Flood Redirected */ + nredirs = atoi(optarg); + + if (nredirs == 0) { + puts("Invalid number of Redirects in option -R"); + exit(EXIT_FAILURE); + } + + floodr_f = 1; + break; + + case 'T': /* Flood targets */ + ntargets = atoi(optarg); + if (ntargets == 0) { + puts("Invalid number of Target Addresses in option -T"); + exit(EXIT_FAILURE); + } + + floodt_f = 1; + break; + + case 'F': /* Flood sources */ + nsources = atoi(optarg); + if (nsources == 0) { + puts("Invalid number of sources in option -F"); + exit(EXIT_FAILURE); + } + + floods_f = 1; + break; + + case 'l': /* "Loop mode */ + loop_f = 1; + break; + + case 'z': /* Sleep option */ + nsleep = atoi(optarg); + if (nsleep == 0) { + puts("Invalid number of seconds in '-z' option"); + exit(EXIT_FAILURE); + } + + sleep_f = 1; + break; + + case 'L': /* "Listen mode */ + idata.listen_f = 1; + break; + + case 'v': /* Be verbose */ + idata.verbose_f++; + break; + + case 'h': /* Help */ + print_help(); + + exit(EXIT_FAILURE); + break; + + default: + usage(); + exit(EXIT_FAILURE); + break; + + } /* switch */ + } /* while(getopt) */ + + if (geteuid()) { + puts("rd6 needs root privileges to run."); + exit(EXIT_FAILURE); + } + + if (!idata.iface_f) { + if (idata.dstaddr_f && IN6_IS_ADDR_LINKLOCAL(&(idata.dstaddr))) { + puts("Must specify a network interface for link-local destinations"); + exit(EXIT_FAILURE); + } + else if (idata.listen_f) { + puts("Must specify a network interface when employing the 'listenging' mode"); + exit(EXIT_FAILURE); + } + } + + if (idata.listen_f && loop_f) { + puts("'Error: listen' mode and 'loop' mode are incompatible"); + exit(EXIT_FAILURE); + } + + /* + If the flood option ("-F") has been specified, but no prefix has been specified, + select the random Source Addresses from the link-local unicast prefix (fe80::/64). + */ + if (floods_f && !idata.srcprefix_f) { + if (inet_pton(AF_INET6, "fe80::", &(idata.srcaddr)) <= 0) { + puts("inet_pton(): Error when converting address"); + exit(EXIT_FAILURE); + } + + randomize_ipv6_addr(&(idata.srcaddr), &(idata.srcaddr), 64); + idata.srcpreflen = 64; + } + + if (!floods_f && !idata.srcaddr_f && !learnrouter_f) { + puts("Must specify IPv6 Source Address (usually to that of the current default router)"); + exit(EXIT_FAILURE); + } + + if (!idata.dstaddr_f && !idata.listen_f) { /* Must specify IPv6 Destination Address if listening mode not used */ + puts("IPv6 Destination Address not specified (and listening mode not selected)"); + exit(EXIT_FAILURE); + } + + if (!idata.hsrcaddr_f && !learnrouter_f) /* Source link-layer address is randomized by default */ + randomize_ether_addr(&(idata.hsrcaddr)); + + if (!idata.hdstaddr_f && idata.dstaddr_f) { + if (ether_pton(ETHER_ALLNODES_LINK_ADDR, &idata.hdstaddr, sizeof(idata.hdstaddr)) == 0) { + puts("ether_pton(): Error converting all-nodes multicast address"); + exit(EXIT_FAILURE); + } + } + + if (load_dst_and_pcap(&idata, (idata.dstaddr_f ? LOAD_SRC_NXT_HOP : LOAD_PCAP_ONLY)) == FAILURE) { + puts("Error while learning Source Address and Next Hop"); + exit(EXIT_FAILURE); + } + + if (learnrouter_f) { + randomize_ether_addr(&rs_ether); + ether_to_ipv6_linklocal(&rs_ether, &rs_ipv6); + + if (find_ipv6_router(idata.pfd, &rs_ether, &rs_ipv6, &router_ether, &router_ipv6) != 0) { + puts("Failed learning default IPv6 router"); + exit(EXIT_FAILURE); + } + + if (!idata.hsrcaddr_f) { + idata.hsrcaddr = router_ether; + idata.hsrcaddr_f = 1; + } + + if (!idata.srcaddr_f) { + idata.srcaddr = router_ipv6; + idata.srcaddr_f = 1; + } + } + + release_privileges(); + srandom(time(NULL)); + + if (tllaopt_f && !tllaopta_f) { + if (idata.hsrcaddr_f) { /* The value of the target link-layer address */ + linkaddr[0] = idata.hsrcaddr; /* option defaults to the Ethernet Source Address */ + nlinkaddr++; + } + else { + puts("Must specify the link-layer Source Address when the '-e' option is selected"); + exit(EXIT_FAILURE); + } + } + + /* + If the flood target option ("-T") was specified, but no prefix was specified, + select the random Target Addresses from the link-local unicast prefix (fe80::/64). + */ + if (floodt_f && !targetprefix_f) { + if (inet_pton(AF_INET6, "fe80::", &targetaddr) <= 0) { + puts("inet_pton(): Error when converting address"); + exit(EXIT_FAILURE); + } + + randomize_ipv6_addr(&targetaddr, &targetaddr, 64); + targetpreflen = 64; + } + + if (!floodt_f && !targetaddr_f) { + if (!makeonlink_f) { + puts("Must specify Redirect Target Address"); + exit(EXIT_FAILURE); + } + else if (!floodr_f) { + targetaddr = rediraddr; + targetaddr_f = 1; + } + } + + /* If the "flood destination" option was set, but no prefix was specified for the + "redirected destination", we select random addresses (from ::/0) + */ + if (floodr_f && !redirprefix_f) { + for (i = 0; i < 16; i++) + rediraddr.s6_addr[i] = 0x00; + + redirpreflen = 0; + } + + if (!floods_f) + nsources = 1; + + if (!floodt_f) + ntargets = 1; + + if (!floodr_f) + nredirs = 1; + + if (sanityfilters_f) { + if (filters.nacceptlinkdst > MAX_ACCEPT_LINK_DST) { + puts("Too many link-layer Destination Address (accept) filters while adding sanity filters."); + exit(EXIT_FAILURE); + } + + if (learnrouter_f) + filters.acceptlinkdst[filters.nacceptlinkdst] = router_ether; + else + filters.acceptlinkdst[filters.nacceptlinkdst] = idata.hsrcaddr; + + filters.nacceptlinkdst++; + filters.acceptfilters_f = 1; + + if (filters.nblocksrc >= MAX_BLOCK_SRC) { + puts("Too many IPv6 Source Address (block) filters while adding sanity filters."); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, "fe80::", &(filters.blocksrc[filters.nblocksrc])) <= 0) { + puts("Error while adding sanity filter for link-local addresses."); + exit(EXIT_FAILURE); + } + + filters.blocksrclen[filters.nblocksrc] = 16; + filters.nblocksrc++; + } + + if (!sleep_f) + nsleep = 1; + + if (!idata.fragh_f && dstoptuhdr_f) { + puts("Dst. Options Header (Unfragmentable Part) set, but Fragmentation not specified"); + exit(EXIT_FAILURE); + } + + if (!norheader_f && !(rhtcp_f || rhudp_f || rhicmp6_f)) + rhdefault_f = 1; + + if (!ip6hoplimit_f) + ip6hoplimit = 255; + + if (!ip6length_f) + ip6length = 1460; + + if (!peeraddr_f) + peeraddr = idata.dstaddr; + + if (rhtcp_f || rhdefault_f) { + if (!tcpflags_f) + tcpflags = tcpflags | TH_ACK; + + if (!tcpack_f) + tcpack = random(); + + if (!tcpseq_f) + tcpseq = random(); + + if (!tcpwin_f) + tcpwin = ((uint16_t)random() + 1500) & (uint16_t)0x7f00; + + if (!peerport_f) + peerport = random(); + + if (!redirport_f) + redirport = random(); + + if (!tcpurg_f) + tcpurg = 0; + } + + if (rhudp_f) { + if (!peerport_f) + peerport = random(); + + if (!redirport_f) + redirport = random(); + } + + if (rhicmp6_f) { + if (!icmp6id_f) + icmp6id = random(); + + if (!icmp6seq_f) + icmp6seq = random(); + } + + if (idata.verbose_f) { + print_attack_info(&idata); + } + + /* + Set filter for IPv6 packets (find_ipv6_router() set its own filters before receiving RAs) + */ + if (pcap_compile(idata.pfd, &pcap_filter, PCAP_IPV6_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1) { + printf("pcap_compile(): %s", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } + + if (pcap_setfilter(idata.pfd, &pcap_filter) == -1) { + printf("pcap_setfilter(): %s", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } + + pcap_freecode(&pcap_filter); + + /* Set initial contents of the attack packet */ + init_packet_data(&idata); + + /* Fire an ICMPv6 Redirect if an IPv6 Destination Address was specified */ + if ((idata.dstaddr_f) && (targetaddr_f || floodt_f) && (rediraddr_f || floodr_f)) { + send_packet(&idata, NULL, NULL); + if (idata.verbose_f) + puts("Initial attack packet(s) sent successfully."); + + if (loop_f) { + if (idata.verbose_f) + printf("Now sending Redirect Messages every %u second%s...\n", nsleep, ((nsleep > 1) ? "s" : "")); + while (loop_f) { + sleep(nsleep); + send_packet(&idata, NULL, NULL); + } + } + + exit(EXIT_SUCCESS); + } + + if (idata.listen_f) { + if (idata.verbose_f) { + print_filters(&idata, &filters); + puts("Listening to incoming IPv6 messages..."); + } + + FD_ZERO(&sset); + FD_SET(idata.fd, &sset); + + while (idata.listen_f) { + rset = sset; #if defined(sun) || defined(__sun) || defined(__linux__) - timeout.tv_usec=1000; - timeout.tv_sec= 0; - if((sel=select(idata.fd+1, &rset, NULL, NULL, &timeout)) == -1){ + timeout.tv_usec = 1000; + timeout.tv_sec = 0; + if ((sel = select(idata.fd + 1, &rset, NULL, NULL, &timeout)) == -1) { #else - if((sel=select(idata.fd+1, &rset, NULL, NULL, NULL)) == -1){ + if ((sel = select(idata.fd + 1, &rset, NULL, NULL, NULL)) == -1) { #endif - if(errno == EINTR){ - continue; - } - else{ - puts("Error in select()"); - exit(EXIT_FAILURE); - } - } + if (errno == EINTR) { + continue; + } + else { + puts("Error in select()"); + exit(EXIT_FAILURE); + } + } #if defined(sun) || defined(__sun) || defined(__linux__) - if(TRUE){ + if (TRUE) { #else - if(FD_ISSET(idata.fd, &rset)){ + if (FD_ISSET(idata.fd, &rset)) { #endif - /* Read an IPv6 packet */ - if((r=pcap_next_ex(idata.pfd, &pkthdr, &pktdata)) == -1){ - printf("pcap_next_ex(): %s", pcap_geterr(idata.pfd)); - exit(EXIT_FAILURE); - } - else if(r == 1 && pktdata != NULL){ - pkt_ether = (struct ether_header *) pktdata; - pkt_ipv6 = (struct ip6_hdr *)((char *) pkt_ether + ETHER_HDR_LEN); - - accepted_f=0; - - if(idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK)){ - if(filters.nblocklinksrc){ - if(match_ether(filters.blocklinksrc, filters.nblocklinksrc, &(pkt_ether->src))){ - if(idata.verbose_f>1) - print_filter_result(&idata, pktdata, BLOCKED); - - continue; - } - } - - if(filters.nblocklinkdst){ - if(match_ether(filters.blocklinkdst, filters.nblocklinkdst, &(pkt_ether->dst))){ - if(idata.verbose_f>1) - print_filter_result(&idata, pktdata, BLOCKED); - - continue; - } - } - } - - if(filters.nblocksrc){ - if(match_ipv6(filters.blocksrc, filters.blocksrclen, filters.nblocksrc, &(pkt_ipv6->ip6_src))){ - if(idata.verbose_f>1) - print_filter_result(&idata, pktdata, BLOCKED); - - continue; - } - } - - if(filters.nblockdst){ - if(match_ipv6(filters.blockdst, filters.blockdstlen, filters.nblockdst, &(pkt_ipv6->ip6_dst))){ - if(idata.verbose_f>1) - print_filter_result(&idata, pktdata, BLOCKED); - - continue; - } - } - - if(idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK)){ - if(filters.nacceptlinksrc){ - if(match_ether(filters.acceptlinksrc, filters.nacceptlinksrc, &(pkt_ether->src))) - accepted_f=1; - } - - if(filters.nacceptlinkdst && !accepted_f){ - if(match_ether(filters.acceptlinkdst, filters.nacceptlinkdst, &(pkt_ether->dst))) - accepted_f= 1; - } - } - - if(filters.nacceptsrc && !accepted_f){ - if(match_ipv6(filters.acceptsrc, filters.acceptsrclen, filters.nacceptsrc, &(pkt_ipv6->ip6_src))) - accepted_f= 1; - } - - if(filters.nacceptdst && !accepted_f){ - if(match_ipv6(filters.acceptdst, filters.acceptdstlen, filters.nacceptdst, &(pkt_ipv6->ip6_dst))) - accepted_f=1; - } - - if(filters.acceptfilters_f && !accepted_f){ - if(idata.verbose_f>1) - print_filter_result(&idata, pktdata, BLOCKED); - - continue; - } - - if(idata.verbose_f>1) - print_filter_result(&idata, pktdata, ACCEPTED); - - /* Send a Redirect message */ - send_packet(&idata, pktdata, pkthdr); - } - } - } - - exit(EXIT_SUCCESS); - } - - - if(!(idata.dstaddr_f && (targetaddr_f || floodt_f) && (rediraddr_f || floodr_f)) && !idata.listen_f){ - puts("Error: Nothing to send! (key parameters left unspecified, and not using listening mode)"); - exit(EXIT_FAILURE); - } - - exit(EXIT_SUCCESS); + /* Read an IPv6 packet */ + if ((r = pcap_next_ex(idata.pfd, &pkthdr, &pktdata)) == -1) { + printf("pcap_next_ex(): %s", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } + else if (r == 1 && pktdata != NULL) { + pkt_ether = (struct ether_header *)pktdata; + pkt_ipv6 = (struct ip6_hdr *)((char *)pkt_ether + ETHER_HDR_LEN); + + accepted_f = 0; + + if (idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK)) { + if (filters.nblocklinksrc) { + if (match_ether(filters.blocklinksrc, filters.nblocklinksrc, &(pkt_ether->src))) { + if (idata.verbose_f > 1) + print_filter_result(&idata, pktdata, BLOCKED); + + continue; + } + } + + if (filters.nblocklinkdst) { + if (match_ether(filters.blocklinkdst, filters.nblocklinkdst, &(pkt_ether->dst))) { + if (idata.verbose_f > 1) + print_filter_result(&idata, pktdata, BLOCKED); + + continue; + } + } + } + + if (filters.nblocksrc) { + if (match_ipv6(filters.blocksrc, filters.blocksrclen, filters.nblocksrc, + &(pkt_ipv6->ip6_src))) { + if (idata.verbose_f > 1) + print_filter_result(&idata, pktdata, BLOCKED); + + continue; + } + } + + if (filters.nblockdst) { + if (match_ipv6(filters.blockdst, filters.blockdstlen, filters.nblockdst, + &(pkt_ipv6->ip6_dst))) { + if (idata.verbose_f > 1) + print_filter_result(&idata, pktdata, BLOCKED); + + continue; + } + } + + if (idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK)) { + if (filters.nacceptlinksrc) { + if (match_ether(filters.acceptlinksrc, filters.nacceptlinksrc, &(pkt_ether->src))) + accepted_f = 1; + } + + if (filters.nacceptlinkdst && !accepted_f) { + if (match_ether(filters.acceptlinkdst, filters.nacceptlinkdst, &(pkt_ether->dst))) + accepted_f = 1; + } + } + + if (filters.nacceptsrc && !accepted_f) { + if (match_ipv6(filters.acceptsrc, filters.acceptsrclen, filters.nacceptsrc, + &(pkt_ipv6->ip6_src))) + accepted_f = 1; + } + + if (filters.nacceptdst && !accepted_f) { + if (match_ipv6(filters.acceptdst, filters.acceptdstlen, filters.nacceptdst, + &(pkt_ipv6->ip6_dst))) + accepted_f = 1; + } + + if (filters.acceptfilters_f && !accepted_f) { + if (idata.verbose_f > 1) + print_filter_result(&idata, pktdata, BLOCKED); + + continue; + } + + if (idata.verbose_f > 1) + print_filter_result(&idata, pktdata, ACCEPTED); + + /* Send a Redirect message */ + send_packet(&idata, pktdata, pkthdr); + } + } + } + + exit(EXIT_SUCCESS); + } + + if (!(idata.dstaddr_f && (targetaddr_f || floodt_f) && (rediraddr_f || floodr_f)) && !idata.listen_f) { + puts("Error: Nothing to send! (key parameters left unspecified, and not using listening mode)"); + exit(EXIT_FAILURE); + } + + exit(EXIT_SUCCESS); } - - /* * Function: init_packet_data() * * Initialize the contents of the attack packet (Ethernet header, IPv6 Header, and ICMPv6 header) * that are expected to remain constant for the specified attack. */ -void init_packet_data(struct iface_data *idata){ - struct dlt_null *dlt_null; - ethernet= (struct ether_header *) buffer; - dlt_null= (struct dlt_null *) buffer; - v6buffer = buffer + idata->linkhsize; - ipv6 = (struct ip6_hdr *) v6buffer; - - if(idata->type == DLT_EN10MB){ - ethernet->ether_type = htons(ETHERTYPE_IPV6); - - if(!(idata->flags & IFACE_LOOPBACK)){ - ethernet->src = idata->hsrcaddr; - ethernet->dst = idata->hdstaddr; - } - } - else if(idata->type == DLT_NULL){ - dlt_null->family= PF_INET6; - } -#if defined (__OpenBSD__) - else if(idata->type == DLT_LOOP){ - dlt_null->family= htonl(PF_INET6); - } +void init_packet_data(struct iface_data *idata) { + struct dlt_null *dlt_null; + ethernet = (struct ether_header *)buffer; + dlt_null = (struct dlt_null *)buffer; + v6buffer = buffer + idata->linkhsize; + ipv6 = (struct ip6_hdr *)v6buffer; + + if (idata->type == DLT_EN10MB) { + ethernet->ether_type = htons(ETHERTYPE_IPV6); + + if (!(idata->flags & IFACE_LOOPBACK)) { + ethernet->src = idata->hsrcaddr; + ethernet->dst = idata->hdstaddr; + } + } + else if (idata->type == DLT_NULL) { + dlt_null->family = PF_INET6; + } +#if defined(__OpenBSD__) + else if (idata->type == DLT_LOOP) { + dlt_null->family = htonl(PF_INET6); + } #endif - ipv6->ip6_flow=0; - ipv6->ip6_vfc= 0x60; - ipv6->ip6_hlim= hoplimit; - ipv6->ip6_src= idata->srcaddr; - ipv6->ip6_dst= idata->dstaddr; - - prev_nh = (unsigned char *) &(ipv6->ip6_nxt); - - ptr = (unsigned char *) v6buffer + MIN_IPV6_HLEN; - - if(hbhopthdr_f){ - hbhopthdrs=0; - - while(hbhopthdrs < nhbhopthdr){ - if((ptr+ hbhopthdrlen[hbhopthdrs]) > (v6buffer+ idata->mtu)){ - puts("Packet too large while processing HBH Opt. Header"); - exit(EXIT_FAILURE); - } - - *prev_nh = IPPROTO_HOPOPTS; - prev_nh = ptr; - memcpy(ptr, hbhopthdr[hbhopthdrs], hbhopthdrlen[hbhopthdrs]); - ptr = ptr + hbhopthdrlen[hbhopthdrs]; - hbhopthdrs++; - } - } - - if(dstoptuhdr_f){ - dstoptuhdrs=0; - - while(dstoptuhdrs < ndstoptuhdr){ - if((ptr+ dstoptuhdrlen[dstoptuhdrs]) > (v6buffer+ idata->mtu)){ - puts("Packet too large while processing Dest. Opt. Header (Unfrag. Part)"); - exit(EXIT_FAILURE); - } - - *prev_nh = IPPROTO_DSTOPTS; - prev_nh = ptr; - memcpy(ptr, dstoptuhdr[dstoptuhdrs], dstoptuhdrlen[dstoptuhdrs]); - ptr = ptr + dstoptuhdrlen[dstoptuhdrs]; - dstoptuhdrs++; - } - } - - /* Everything that follows is the Fragmentable Part of the packet */ - fragpart = ptr; - - if(idata->fragh_f){ - /* Check that we are able to send the Unfragmentable Part, together with a - Fragment Header and a chunk data over our link layer - */ - if( (fragpart+sizeof(fraghdr)+nfrags) > (v6buffer+idata->mtu)){ - printf("Unfragmentable part too large for current MTU (%u bytes)\n", idata->mtu); - exit(EXIT_FAILURE); - } - - /* We prepare a separete Fragment Header, but we do not include it in the packet to be sent. - This Fragment Header will be used (an assembled with the rest of the packet by the - send_packet() function. - */ - memset(&fraghdr, 0, FRAG_HDR_SIZE); - *prev_nh = IPPROTO_FRAGMENT; - prev_nh = (unsigned char *) &fraghdr; - } - - if(dstopthdr_f){ - dstopthdrs=0; - - while(dstopthdrs < ndstopthdr){ - if((ptr+ dstopthdrlen[dstopthdrs]) > (v6buffer + idata->max_packet_size)){ - puts("Packet too large while processing Dest. Opt. Header (should be using the Frag. option?)"); - exit(EXIT_FAILURE); - } - - *prev_nh = IPPROTO_DSTOPTS; - prev_nh = ptr; - memcpy(ptr, dstopthdr[dstopthdrs], dstopthdrlen[dstopthdrs]); - ptr = ptr + dstopthdrlen[dstopthdrs]; - dstopthdrs++; - } - } - - - *prev_nh = IPPROTO_ICMPV6; - - if( (ptr+sizeof(struct nd_redirect)) > (v6buffer + idata->max_packet_size)){ - puts("Packet too large while inserting ICMPv6 Redirect header (should be using Frag. option?)"); - exit(EXIT_FAILURE); - } - - rd= (struct nd_redirect *) ptr; - - rd->nd_rd_type = ND_REDIRECT; - rd->nd_rd_code = 0; - rd->nd_rd_reserved = 0; - rd->nd_rd_target = targetaddr; - rd->nd_rd_dst = rediraddr; - - ptr += sizeof(struct nd_redirect); - - if(tllaopt_f && nlinkaddr==1){ - if( (ptr+sizeof(struct nd_opt_tlla)) <= (v6buffer + idata->max_packet_size) ){ - tllaopt = (struct nd_opt_tlla *) ptr; - tllaopt->type= ND_OPT_TARGET_LINKADDR; - tllaopt->length= TLLA_OPT_LEN; - memcpy(tllaopt->address, linkaddr[0].a, ETH_ALEN); - ptr += sizeof(struct nd_opt_tlla); - } - else{ - puts("Packet Too Large while processing target link-layer address option"); - exit(EXIT_FAILURE); - } - } - - startofprefixes=ptr; + ipv6->ip6_flow = 0; + ipv6->ip6_vfc = 0x60; + ipv6->ip6_hlim = hoplimit; + ipv6->ip6_src = idata->srcaddr; + ipv6->ip6_dst = idata->dstaddr; + + prev_nh = (unsigned char *)&(ipv6->ip6_nxt); + + ptr = (unsigned char *)v6buffer + MIN_IPV6_HLEN; + + if (hbhopthdr_f) { + hbhopthdrs = 0; + + while (hbhopthdrs < nhbhopthdr) { + if ((ptr + hbhopthdrlen[hbhopthdrs]) > (v6buffer + idata->mtu)) { + puts("Packet too large while processing HBH Opt. Header"); + exit(EXIT_FAILURE); + } + + *prev_nh = IPPROTO_HOPOPTS; + prev_nh = ptr; + memcpy(ptr, hbhopthdr[hbhopthdrs], hbhopthdrlen[hbhopthdrs]); + ptr = ptr + hbhopthdrlen[hbhopthdrs]; + hbhopthdrs++; + } + } + + if (dstoptuhdr_f) { + dstoptuhdrs = 0; + + while (dstoptuhdrs < ndstoptuhdr) { + if ((ptr + dstoptuhdrlen[dstoptuhdrs]) > (v6buffer + idata->mtu)) { + puts("Packet too large while processing Dest. Opt. Header (Unfrag. Part)"); + exit(EXIT_FAILURE); + } + + *prev_nh = IPPROTO_DSTOPTS; + prev_nh = ptr; + memcpy(ptr, dstoptuhdr[dstoptuhdrs], dstoptuhdrlen[dstoptuhdrs]); + ptr = ptr + dstoptuhdrlen[dstoptuhdrs]; + dstoptuhdrs++; + } + } + + /* Everything that follows is the Fragmentable Part of the packet */ + fragpart = ptr; + + if (idata->fragh_f) { + /* Check that we are able to send the Unfragmentable Part, together with a + Fragment Header and a chunk data over our link layer + */ + if ((fragpart + sizeof(fraghdr) + nfrags) > (v6buffer + idata->mtu)) { + printf("Unfragmentable part too large for current MTU (%u bytes)\n", idata->mtu); + exit(EXIT_FAILURE); + } + + /* We prepare a separete Fragment Header, but we do not include it in the packet to be sent. + This Fragment Header will be used (an assembled with the rest of the packet by the + send_packet() function. + */ + memset(&fraghdr, 0, FRAG_HDR_SIZE); + *prev_nh = IPPROTO_FRAGMENT; + prev_nh = (unsigned char *)&fraghdr; + } + + if (dstopthdr_f) { + dstopthdrs = 0; + + while (dstopthdrs < ndstopthdr) { + if ((ptr + dstopthdrlen[dstopthdrs]) > (v6buffer + idata->max_packet_size)) { + puts("Packet too large while processing Dest. Opt. Header (should be using the Frag. option?)"); + exit(EXIT_FAILURE); + } + + *prev_nh = IPPROTO_DSTOPTS; + prev_nh = ptr; + memcpy(ptr, dstopthdr[dstopthdrs], dstopthdrlen[dstopthdrs]); + ptr = ptr + dstopthdrlen[dstopthdrs]; + dstopthdrs++; + } + } + + *prev_nh = IPPROTO_ICMPV6; + + if ((ptr + sizeof(struct nd_redirect)) > (v6buffer + idata->max_packet_size)) { + puts("Packet too large while inserting ICMPv6 Redirect header (should be using Frag. option?)"); + exit(EXIT_FAILURE); + } + + rd = (struct nd_redirect *)ptr; + + rd->nd_rd_type = ND_REDIRECT; + rd->nd_rd_code = 0; + rd->nd_rd_reserved = 0; + rd->nd_rd_target = targetaddr; + rd->nd_rd_dst = rediraddr; + + ptr += sizeof(struct nd_redirect); + + if (tllaopt_f && nlinkaddr == 1) { + if ((ptr + sizeof(struct nd_opt_tlla)) <= (v6buffer + idata->max_packet_size)) { + tllaopt = (struct nd_opt_tlla *)ptr; + tllaopt->type = ND_OPT_TARGET_LINKADDR; + tllaopt->length = TLLA_OPT_LEN; + memcpy(tllaopt->address, linkaddr[0].a, ETH_ALEN); + ptr += sizeof(struct nd_opt_tlla); + } + else { + puts("Packet Too Large while processing target link-layer address option"); + exit(EXIT_FAILURE); + } + } + + startofprefixes = ptr; } - - /* * Function: send_packet() * * Initialize the remaining fields of the Neighbor Advertisement Message, and * send the attack packet(s). */ -void send_packet(struct iface_data *idata, const u_char *pktdata, struct pcap_pkthdr *pkthdr){ - if(pktdata != NULL){ /* Sending a Redirect in response to a received packet */ - pkt_ether = (struct ether_header *) pktdata; - pkt_ipv6 = (struct ip6_hdr *)((char *) pkt_ether + idata->linkhsize); - pkt_end = (unsigned char *) pktdata + pkthdr->caplen; - - /* The packet length is the minimum of what we capured, and what is specified in the - IPv6 Total Lenght field - */ - if( pkt_end > ((unsigned char *)pkt_ipv6 + sizeof(struct ip6_hdr) + ntohs(pkt_ipv6->ip6_plen)) ) - pkt_end = (unsigned char *)pkt_ipv6 + sizeof(struct ip6_hdr) + ntohs(pkt_ipv6->ip6_plen); - - pkt_ipv6addr = &(pkt_ipv6->ip6_src); - - /* - We don't send any packets if the Source Address of the captured packet is the unspecified - address. - */ - if(IN6_IS_ADDR_UNSPECIFIED(pkt_ipv6addr)){ - return; - } - else{ - ipv6->ip6_dst = pkt_ipv6->ip6_src; - ethernet->dst = pkt_ether->src; - } - - pkt_ipv6addr = &(pkt_ipv6->ip6_dst); - - /* - We respond to packets sent to a multicast address only if the tool has been explicitly instructed - to do so. - */ - if(IN6_IS_ADDR_MULTICAST(pkt_ipv6addr) && !respmcast_f) - return; - - rd->nd_rd_dst = pkt_ipv6->ip6_dst; - } - - sources=0; - - do{ - if(floods_f){ - /* - Randomizing the IPv6 Source address based on the prefix specified by - "srcaddr" and srcpreflen. - */ - randomize_ipv6_addr(&(ipv6->ip6_src), &(idata->srcaddr), idata->srcpreflen); - - if(!idata->hsrcaddr_f){ - randomize_ether_addr(&(ethernet->src)); - } - - if(tllaopt_f && !tllaopta_f){ - memcpy(tllaopt->address, ethernet->src.a, ETH_ALEN); - } - } - - redirs=0; - - do{ - if(floodr_f){ - /* - Randomizing the Redirected Address based on the prefix specified by rediraddr - and redirpreflen. - */ - randomize_ipv6_addr(&(rd->nd_rd_dst), &rediraddr, redirpreflen); - } - - - targets=0; - - do{ - if(floodt_f){ - /* - Randomizing the Redirect Target Address based on the prefix specified - by targetaddr and targetpreflen. - */ - randomize_ipv6_addr(&(rd->nd_rd_target), &targetaddr, targetpreflen); - } - else if(makeonlink_f){ - /* Code used to check for makeonlink_f && floodr_f */ - /* The target field contains the address specified by the "-t" option. - Otherwise (if we must make the address "on-link", the ND target field - is set to the same value as the RD Destination Address - */ - rd->nd_rd_target= rd->nd_rd_dst; - } - - /* - * If a single target link-layer address option is to be included, it is included - * by init_packet_data() - */ - if(nlinkaddr==1) - linkaddrs=1; - else - linkaddrs=0; - - ptr=startofprefixes; - - while(linkaddrsmax_packet_size){ - tllaopt = (struct nd_opt_tlla *) ptr; - tllaopt->type= ND_OPT_TARGET_LINKADDR; - tllaopt->length= TLLA_OPT_LEN; - memcpy(tllaopt->address, linkaddr[linkaddrs].a, ETH_ALEN); - ptr += sizeof(struct nd_opt_tlla); - linkaddrs++; - newdata_f=1; - } - - if(linkaddrs 1280) - rhbytes=48; - else - rhbytes= 1280- currentsize - sizeof(struct nd_opt_rd_hdr); - } - - pktbytes= pkt_end - (unsigned char*) pkt_ipv6; - - if( rhbytes > pktbytes) - rhbytes= pktbytes; - - rhbytes= (rhbytes>>3) << 3; - - if( (ptr+sizeof(struct nd_opt_rd_hdr)+rhbytes) > (v6buffer + idata->max_packet_size)){ - puts("Packet Too Large while inserting Redirected Header Option"); - exit(EXIT_FAILURE); - } - rh = (struct nd_opt_rd_hdr *) ptr; - rh->nd_opt_rh_type = ND_OPT_REDIRECTED_HEADER; - rh->nd_opt_rh_len = rhbytes/8 + 1; - rh->nd_opt_rh_reserved1= 0; - rh->nd_opt_rh_reserved2= 0; - ptr+= sizeof(struct nd_opt_rd_hdr); - memcpy(ptr, pkt_ipv6, rhbytes); - ptr+= rhbytes; - } - else{ - /* The Redirect is *not* being sent in response to a received packet */ - - if(rhlength_f){ - rhbytes= rhlength; - } - else{ - currentsize= ptr - (unsigned char *)ipv6; - if( (currentsize+sizeof(struct nd_opt_rd_hdr)) > 1280) - rhbytes=48; - else - rhbytes= 1280- currentsize - sizeof(struct nd_opt_rd_hdr); - } - - rhbytes= (rhbytes>>3) << 3; - - if( (ptr+sizeof(struct nd_opt_rd_hdr)+rhbytes) > (v6buffer + idata->max_packet_size)){ - puts("Packet Too Large while inserting Redirected Header Option"); - exit(EXIT_FAILURE); - } - - rh = (struct nd_opt_rd_hdr *) ptr; - rh->nd_opt_rh_type = ND_OPT_REDIRECTED_HEADER; - rh->nd_opt_rh_len = rhbytes/8 + 1; - rh->nd_opt_rh_reserved1= 0; - rh->nd_opt_rh_reserved2= 0; - ptr+= sizeof(struct nd_opt_rd_hdr); - - rhipv6 = (struct ip6_hdr *) rhbuff; - rhipv6->ip6_flow= 0; - rhipv6->ip6_vfc= 0x60; - rhipv6->ip6_plen= htons(ip6length); - rhipv6->ip6_hlim= ip6hoplimit; - rhipv6->ip6_src= peeraddr; - rhipv6->ip6_dst= rd->nd_rd_dst; - - if(rhtcp_f || rhdefault_f){ - rhipv6->ip6_nxt= IPPROTO_TCP; - rhtcp= (struct tcp_hdr *) (rhbuff + sizeof(struct ip6_hdr)); - memset(rhtcp, 0, sizeof(struct tcp_hdr)); - rhtcp->th_sport= htons(peerport); - rhtcp->th_dport= htons(redirport); - rhtcp->th_seq = htonl(tcpseq); - rhtcp->th_ack= htonl(tcpack); - rhtcp->th_flags= tcpflags; - rhtcp->th_urp= htons(tcpurg); - rhtcp->th_win= htons(tcpwin); - rhtcp->th_off= MIN_TCP_HLEN >> 2; - rhtcp->th_sum = random(); - - if(rhbytes <= (MIN_IPV6_HLEN + MIN_TCP_HLEN)){ - memcpy(ptr, rhbuff, rhbytes); - ptr+= rhbytes; - } - else{ - memcpy(ptr, rhbuff, MIN_IPV6_HLEN+MIN_TCP_HLEN); - ptr += MIN_IPV6_HLEN+MIN_TCP_HLEN; - rhbytes -= MIN_IPV6_HLEN+MIN_TCP_HLEN; - - while(rhbytes>=4){ - *(uint32_t *)ptr = random(); - ptr += sizeof(uint32_t); - rhbytes -= sizeof(uint32_t); - } - } - } - - else if(rhudp_f){ - rhipv6->ip6_nxt= IPPROTO_UDP; - rhudp = (struct udp_hdr *) (rhbuff + sizeof(struct ip6_hdr)); - rhudp->uh_sport= htons(peerport); - rhudp->uh_dport= htons(redirport); - rhudp->uh_ulen= rhipv6->ip6_plen; - rhudp->uh_sum= random(); - - if(rhbytes <= (MIN_IPV6_HLEN + MIN_UDP_HLEN)){ - memcpy(ptr, rhbuff, rhbytes); - ptr+= rhbytes; - } - else{ - memcpy(ptr, rhbuff, MIN_IPV6_HLEN+MIN_UDP_HLEN); - ptr += MIN_IPV6_HLEN+MIN_UDP_HLEN; - rhbytes -= MIN_IPV6_HLEN+MIN_UDP_HLEN; - while(rhbytes>=4){ - *(uint32_t *)ptr = random(); - ptr += sizeof(uint32_t); - rhbytes -= sizeof(uint32_t); - } - } - } - else if(rhicmp6_f){ - rhipv6->ip6_nxt= IPPROTO_ICMPV6; - rhicmp6 = (struct icmp6_hdr *) (rhbuff + sizeof(struct ip6_hdr)); - rhicmp6->icmp6_type = ICMP6_ECHO_REQUEST; - rhicmp6->icmp6_code = 0; - rhicmp6->icmp6_cksum = random(); - rhicmp6->icmp6_data16[0]= random(); /* Identifier */ - rhicmp6->icmp6_data16[1]= random(); /* Sequence Number */ - - if(rhbytes <= (MIN_IPV6_HLEN + MIN_ICMP6_HLEN)){ - memcpy(ptr, rhbuff, rhbytes); - ptr+= rhbytes; - } - else{ - memcpy(ptr, rhbuff, MIN_IPV6_HLEN+MIN_ICMP6_HLEN); - ptr += MIN_IPV6_HLEN+MIN_ICMP6_HLEN; - rhbytes -= MIN_IPV6_HLEN+MIN_ICMP6_HLEN; - while(rhbytes>=4){ - *(uint32_t *)ptr = random(); - ptr += sizeof(uint32_t); - rhbytes -= sizeof(uint32_t); - } - } - } - } - } - - rd->nd_rd_cksum = 0; - rd->nd_rd_cksum = in_chksum(v6buffer, rd, ptr-((unsigned char *)rd), IPPROTO_ICMPV6); - - if(!idata->fragh_f){ - ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); - - if((nw=pcap_inject(idata->pfd, buffer, ptr - buffer)) == -1){ - printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); - exit(EXIT_FAILURE); - } - - if(nw != (ptr-buffer)){ - printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, \ - (LUI) (ptr-buffer)); - exit(EXIT_FAILURE); - } - } - else{ - ptrend= ptr; - ptr= fragpart; - fptr = fragbuffer; - fipv6 = (struct ip6_hdr *) (fragbuffer + ETHER_HDR_LEN); - fptrend = fptr + ETHER_HDR_LEN+MIN_IPV6_HLEN+MAX_IPV6_PAYLOAD; - memcpy(fptr, buffer, fragpart-buffer); - fptr = fptr + (fragpart-buffer); - - if( (fptr+FRAG_HDR_SIZE)> fptrend){ - puts("Unfragmentable Part is Too Large"); - exit(EXIT_FAILURE); - } - - memcpy(fptr, (char *) &fraghdr, FRAG_HDR_SIZE); - fh= (struct ip6_frag *) fptr; - fh->ip6f_ident=random(); - startoffragment = fptr + FRAG_HDR_SIZE; - - /* - * Check that the selected fragment size is not larger than the largest - * fragment size that can be sent - */ - if(nfrags > (fptrend - fptr)) - nfrags= (fptrend-fptr); - - m=IP6F_MORE_FRAG; - - while((ptr< ptrend) && m==IP6F_MORE_FRAG){ - fptr= startoffragment; - - if( (ptrend-ptr) <= nfrags){ - fragsize= ptrend-ptr; - m=0; - } - else{ - fragsize = (nfrags + 7) & ntohs(IP6F_OFF_MASK); - } - - memcpy(fptr, ptr, fragsize); - fh->ip6f_offlg = (htons(ptr-fragpart) & IP6F_OFF_MASK) | m; - ptr+=fragsize; - fptr+=fragsize; - - fipv6->ip6_plen = htons((fptr - fragbuffer) - MIN_IPV6_HLEN - ETHER_HDR_LEN); - - if((nw=pcap_inject(idata->pfd, fragbuffer, fptr - fragbuffer)) == -1){ - printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); - exit(EXIT_FAILURE); - } - - if(nw != (fptr- fragbuffer)){ - printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", \ - nw, (LUI) (ptr-buffer)); - exit(EXIT_FAILURE); - } - } /* Sending fragments */ - } /* Sending fragmented datagram */ - - targets++; - - }while(targetslinkhsize); + pkt_end = (unsigned char *)pktdata + pkthdr->caplen; + + /* The packet length is the minimum of what we capured, and what is specified in the + IPv6 Total Lenght field + */ + if (pkt_end > ((unsigned char *)pkt_ipv6 + sizeof(struct ip6_hdr) + ntohs(pkt_ipv6->ip6_plen))) + pkt_end = (unsigned char *)pkt_ipv6 + sizeof(struct ip6_hdr) + ntohs(pkt_ipv6->ip6_plen); + + pkt_ipv6addr = &(pkt_ipv6->ip6_src); + + /* + We don't send any packets if the Source Address of the captured packet is the unspecified + address. + */ + if (IN6_IS_ADDR_UNSPECIFIED(pkt_ipv6addr)) { + return; + } + else { + ipv6->ip6_dst = pkt_ipv6->ip6_src; + ethernet->dst = pkt_ether->src; + } + + pkt_ipv6addr = &(pkt_ipv6->ip6_dst); + + /* + We respond to packets sent to a multicast address only if the tool has been explicitly instructed + to do so. + */ + if (IN6_IS_ADDR_MULTICAST(pkt_ipv6addr) && !respmcast_f) + return; + + rd->nd_rd_dst = pkt_ipv6->ip6_dst; + } + + sources = 0; + + do { + if (floods_f) { + /* + Randomizing the IPv6 Source address based on the prefix specified by + "srcaddr" and srcpreflen. + */ + randomize_ipv6_addr(&(ipv6->ip6_src), &(idata->srcaddr), idata->srcpreflen); + + if (!idata->hsrcaddr_f) { + randomize_ether_addr(&(ethernet->src)); + } + + if (tllaopt_f && !tllaopta_f) { + memcpy(tllaopt->address, ethernet->src.a, ETH_ALEN); + } + } + + redirs = 0; + + do { + if (floodr_f) { + /* + Randomizing the Redirected Address based on the prefix specified by rediraddr + and redirpreflen. + */ + randomize_ipv6_addr(&(rd->nd_rd_dst), &rediraddr, redirpreflen); + } + + targets = 0; + + do { + if (floodt_f) { + /* + Randomizing the Redirect Target Address based on the prefix specified + by targetaddr and targetpreflen. + */ + randomize_ipv6_addr(&(rd->nd_rd_target), &targetaddr, targetpreflen); + } + else if (makeonlink_f) { + /* Code used to check for makeonlink_f && floodr_f */ + /* The target field contains the address specified by the "-t" option. + Otherwise (if we must make the address "on-link", the ND target field + is set to the same value as the RD Destination Address + */ + rd->nd_rd_target = rd->nd_rd_dst; + } + + /* + * If a single target link-layer address option is to be included, it is included + * by init_packet_data() + */ + if (nlinkaddr == 1) + linkaddrs = 1; + else + linkaddrs = 0; + + ptr = startofprefixes; + + while (linkaddrs < nlinkaddr && + ((ptr + sizeof(struct nd_opt_tlla)) - v6buffer) <= idata->max_packet_size) { + tllaopt = (struct nd_opt_tlla *)ptr; + tllaopt->type = ND_OPT_TARGET_LINKADDR; + tllaopt->length = TLLA_OPT_LEN; + memcpy(tllaopt->address, linkaddr[linkaddrs].a, ETH_ALEN); + ptr += sizeof(struct nd_opt_tlla); + linkaddrs++; + newdata_f = 1; + } + + if (linkaddrs < nlinkaddr) { + puts("Too many Target Link-ayer Address options (should be using 'frag' option?"); + exit(EXIT_FAILURE); + } + + /* We include a Redirected Header by default */ + if (!norheader_f) { + /* + The amount of data that we include in the Redirected Header depends on a number + of factors: + a) If a specific amount has been specified, we include up to that amount of + data (i.e., provided it is available from the captured packet) + b) If our packet has not yet exceeded the minimum IPv6 MTU (1280 bytes), we + include as many bytes as possible without exceeding that size. + c) If our packet already exceeds the minimum IPv6 MTU, we include at most 68 + bytes + */ + if (pktdata != NULL) { + if (rhlength_f) { + rhbytes = rhlength; + } + else { + currentsize = ptr - (unsigned char *)ipv6; + if ((currentsize + sizeof(struct nd_opt_rd_hdr)) > 1280) + rhbytes = 48; + else + rhbytes = 1280 - currentsize - sizeof(struct nd_opt_rd_hdr); + } + + pktbytes = pkt_end - (unsigned char *)pkt_ipv6; + + if (rhbytes > pktbytes) + rhbytes = pktbytes; + + rhbytes = (rhbytes >> 3) << 3; + + if ((ptr + sizeof(struct nd_opt_rd_hdr) + rhbytes) > (v6buffer + idata->max_packet_size)) { + puts("Packet Too Large while inserting Redirected Header Option"); + exit(EXIT_FAILURE); + } + rh = (struct nd_opt_rd_hdr *)ptr; + rh->nd_opt_rh_type = ND_OPT_REDIRECTED_HEADER; + rh->nd_opt_rh_len = rhbytes / 8 + 1; + rh->nd_opt_rh_reserved1 = 0; + rh->nd_opt_rh_reserved2 = 0; + ptr += sizeof(struct nd_opt_rd_hdr); + memcpy(ptr, pkt_ipv6, rhbytes); + ptr += rhbytes; + } + else { + /* The Redirect is *not* being sent in response to a received packet */ + + if (rhlength_f) { + rhbytes = rhlength; + } + else { + currentsize = ptr - (unsigned char *)ipv6; + if ((currentsize + sizeof(struct nd_opt_rd_hdr)) > 1280) + rhbytes = 48; + else + rhbytes = 1280 - currentsize - sizeof(struct nd_opt_rd_hdr); + } + + rhbytes = (rhbytes >> 3) << 3; + + if ((ptr + sizeof(struct nd_opt_rd_hdr) + rhbytes) > (v6buffer + idata->max_packet_size)) { + puts("Packet Too Large while inserting Redirected Header Option"); + exit(EXIT_FAILURE); + } + + rh = (struct nd_opt_rd_hdr *)ptr; + rh->nd_opt_rh_type = ND_OPT_REDIRECTED_HEADER; + rh->nd_opt_rh_len = rhbytes / 8 + 1; + rh->nd_opt_rh_reserved1 = 0; + rh->nd_opt_rh_reserved2 = 0; + ptr += sizeof(struct nd_opt_rd_hdr); + + rhipv6 = (struct ip6_hdr *)rhbuff; + rhipv6->ip6_flow = 0; + rhipv6->ip6_vfc = 0x60; + rhipv6->ip6_plen = htons(ip6length); + rhipv6->ip6_hlim = ip6hoplimit; + rhipv6->ip6_src = peeraddr; + rhipv6->ip6_dst = rd->nd_rd_dst; + + if (rhtcp_f || rhdefault_f) { + rhipv6->ip6_nxt = IPPROTO_TCP; + rhtcp = (struct tcp_hdr *)(rhbuff + sizeof(struct ip6_hdr)); + memset(rhtcp, 0, sizeof(struct tcp_hdr)); + rhtcp->th_sport = htons(peerport); + rhtcp->th_dport = htons(redirport); + rhtcp->th_seq = htonl(tcpseq); + rhtcp->th_ack = htonl(tcpack); + rhtcp->th_flags = tcpflags; + rhtcp->th_urp = htons(tcpurg); + rhtcp->th_win = htons(tcpwin); + rhtcp->th_off = MIN_TCP_HLEN >> 2; + rhtcp->th_sum = random(); + + if (rhbytes <= (MIN_IPV6_HLEN + MIN_TCP_HLEN)) { + memcpy(ptr, rhbuff, rhbytes); + ptr += rhbytes; + } + else { + memcpy(ptr, rhbuff, MIN_IPV6_HLEN + MIN_TCP_HLEN); + ptr += MIN_IPV6_HLEN + MIN_TCP_HLEN; + rhbytes -= MIN_IPV6_HLEN + MIN_TCP_HLEN; + + while (rhbytes >= 4) { + *(uint32_t *)ptr = random(); + ptr += sizeof(uint32_t); + rhbytes -= sizeof(uint32_t); + } + } + } + + else if (rhudp_f) { + rhipv6->ip6_nxt = IPPROTO_UDP; + rhudp = (struct udp_hdr *)(rhbuff + sizeof(struct ip6_hdr)); + rhudp->uh_sport = htons(peerport); + rhudp->uh_dport = htons(redirport); + rhudp->uh_ulen = rhipv6->ip6_plen; + rhudp->uh_sum = random(); + + if (rhbytes <= (MIN_IPV6_HLEN + MIN_UDP_HLEN)) { + memcpy(ptr, rhbuff, rhbytes); + ptr += rhbytes; + } + else { + memcpy(ptr, rhbuff, MIN_IPV6_HLEN + MIN_UDP_HLEN); + ptr += MIN_IPV6_HLEN + MIN_UDP_HLEN; + rhbytes -= MIN_IPV6_HLEN + MIN_UDP_HLEN; + while (rhbytes >= 4) { + *(uint32_t *)ptr = random(); + ptr += sizeof(uint32_t); + rhbytes -= sizeof(uint32_t); + } + } + } + else if (rhicmp6_f) { + rhipv6->ip6_nxt = IPPROTO_ICMPV6; + rhicmp6 = (struct icmp6_hdr *)(rhbuff + sizeof(struct ip6_hdr)); + rhicmp6->icmp6_type = ICMP6_ECHO_REQUEST; + rhicmp6->icmp6_code = 0; + rhicmp6->icmp6_cksum = random(); + rhicmp6->icmp6_data16[0] = random(); /* Identifier */ + rhicmp6->icmp6_data16[1] = random(); /* Sequence Number */ + + if (rhbytes <= (MIN_IPV6_HLEN + MIN_ICMP6_HLEN)) { + memcpy(ptr, rhbuff, rhbytes); + ptr += rhbytes; + } + else { + memcpy(ptr, rhbuff, MIN_IPV6_HLEN + MIN_ICMP6_HLEN); + ptr += MIN_IPV6_HLEN + MIN_ICMP6_HLEN; + rhbytes -= MIN_IPV6_HLEN + MIN_ICMP6_HLEN; + while (rhbytes >= 4) { + *(uint32_t *)ptr = random(); + ptr += sizeof(uint32_t); + rhbytes -= sizeof(uint32_t); + } + } + } + } + } + + rd->nd_rd_cksum = 0; + rd->nd_rd_cksum = in_chksum(v6buffer, rd, ptr - ((unsigned char *)rd), IPPROTO_ICMPV6); + + if (!idata->fragh_f) { + ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); + + if ((nw = pcap_inject(idata->pfd, buffer, ptr - buffer)) == -1) { + printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); + exit(EXIT_FAILURE); + } + + if (nw != (ptr - buffer)) { + printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, (LUI)(ptr - buffer)); + exit(EXIT_FAILURE); + } + } + else { + ptrend = ptr; + ptr = fragpart; + fptr = fragbuffer; + fipv6 = (struct ip6_hdr *)(fragbuffer + ETHER_HDR_LEN); + fptrend = fptr + ETHER_HDR_LEN + MIN_IPV6_HLEN + MAX_IPV6_PAYLOAD; + memcpy(fptr, buffer, fragpart - buffer); + fptr = fptr + (fragpart - buffer); + + if ((fptr + FRAG_HDR_SIZE) > fptrend) { + puts("Unfragmentable Part is Too Large"); + exit(EXIT_FAILURE); + } + + memcpy(fptr, (char *)&fraghdr, FRAG_HDR_SIZE); + fh = (struct ip6_frag *)fptr; + fh->ip6f_ident = random(); + startoffragment = fptr + FRAG_HDR_SIZE; + + /* + * Check that the selected fragment size is not larger than the largest + * fragment size that can be sent + */ + if (nfrags > (fptrend - fptr)) + nfrags = (fptrend - fptr); + + m = IP6F_MORE_FRAG; + + while ((ptr < ptrend) && m == IP6F_MORE_FRAG) { + fptr = startoffragment; + + if ((ptrend - ptr) <= nfrags) { + fragsize = ptrend - ptr; + m = 0; + } + else { + fragsize = (nfrags + 7) & ntohs(IP6F_OFF_MASK); + } + + memcpy(fptr, ptr, fragsize); + fh->ip6f_offlg = (htons(ptr - fragpart) & IP6F_OFF_MASK) | m; + ptr += fragsize; + fptr += fragsize; + + fipv6->ip6_plen = htons((fptr - fragbuffer) - MIN_IPV6_HLEN - ETHER_HDR_LEN); + + if ((nw = pcap_inject(idata->pfd, fragbuffer, fptr - fragbuffer)) == -1) { + printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); + exit(EXIT_FAILURE); + } + + if (nw != (fptr - fragbuffer)) { + printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, + (LUI)(ptr - buffer)); + exit(EXIT_FAILURE); + } + } /* Sending fragments */ + } /* Sending fragmented datagram */ + + targets++; + + } while (targets < ntargets); + + redirs++; + } while (redirs < nredirs); + + sources++; + } while (sources < nsources); } - - /* * Function: usage() * * Prints the syntax of the rd6 tool */ -void usage(void){ +void usage(void) { puts("usage: rd6 [-i INTERFACE] [-s SRC_ADDR[/LEN]] [-d DST_ADDR] [-S LINK_SRC_ADDR] " - "[-D LINK-DST-ADDR] [-A HOP_LIMIT] [-y FRAG_SIZE] [-u DST_OPT_HDR_SIZE] " - "[-U DST_OPT_U_HDR_SIZE] [-H HBH_OPT_HDR_SIZE] [-r RD_DESTADDR/LEN] [-t RD_TARGETADDR/LEN] " - "[-p PAYLOAD_TYPE] [-P PAYLOAD_SIZE] [-n] [-c HOP_LIMIT] [-x SRC_ADDR] [-a SRC_PORT] " - "[-o DST_PORT] [-X TCP_FLAGS] [-q TCP_SEQ] [-Q TCP_ACK] [-V TCP_URP] [-w TCP_WIN] [-M] " - "[-O] [-N] [-E LINK_ADDR] [-e] [-j PREFIX[/LEN]] [-k PREFIX[/LEN]] [-J LINK_ADDR] [-K LINK_ADDR] " - "[-b PREFIX[/LEN]] [-g PREFIX[/LEN]] [-B LINK_ADDR] [-G LINK_ADDR] [-f] " - "[-R N_DESTS] [-T N_TARGETS] [-F N_SOURCES] [-L | -l] [-z] [-v] [-h]"); + "[-D LINK-DST-ADDR] [-A HOP_LIMIT] [-y FRAG_SIZE] [-u DST_OPT_HDR_SIZE] " + "[-U DST_OPT_U_HDR_SIZE] [-H HBH_OPT_HDR_SIZE] [-r RD_DESTADDR/LEN] [-t RD_TARGETADDR/LEN] " + "[-p PAYLOAD_TYPE] [-P PAYLOAD_SIZE] [-n] [-c HOP_LIMIT] [-x SRC_ADDR] [-a SRC_PORT] " + "[-o DST_PORT] [-X TCP_FLAGS] [-q TCP_SEQ] [-Q TCP_ACK] [-V TCP_URP] [-w TCP_WIN] [-M] " + "[-O] [-N] [-E LINK_ADDR] [-e] [-j PREFIX[/LEN]] [-k PREFIX[/LEN]] [-J LINK_ADDR] [-K LINK_ADDR] " + "[-b PREFIX[/LEN]] [-g PREFIX[/LEN]] [-B LINK_ADDR] [-G LINK_ADDR] [-f] " + "[-R N_DESTS] [-T N_TARGETS] [-F N_SOURCES] [-L | -l] [-z] [-v] [-h]"); } - /* * Function: print_help() * * Prints help information for the rd6 tool */ -void print_help(void){ - puts(SI6_TOOLKIT); - puts( "rd6: Security assessment tool for attack vectors based on Redirect messages\n"); - usage(); - - puts("\nOPTIONS:\n" - " --interface, -i Network interface\n" - " --src-addr, -s IPv6 Source Address\n" - " --dst-addr, -d IPv6 Destination Address\n" - " --hop-limit, -A IPv6 Hop Limit\n" - " --frag-hdr. -y Fragment Header\n" - " --dst-opt-hdr, -u Destination Options Header (Fragmentable Part)\n" - " --dst-opt-u-hdr, -U Destination Options Header (Unfragmentable Part)\n" - " --hbh-opt-hdr, -H Hop by Hop Options Header\n" - " --link-src-addr, -S Link-layer Destination Address\n" - " --link-dst-addr, -D Link-layer Source Address\n" - " --redir-dest, -r Redirect Destination Address\n" - " --redir-target, -t Redirect Target Address\n" - " --payload-type, -p Redirected Header Payload Type\n" - " --payload-size, -P Redirected Header Payload Size\n" - " --no-payload, -n Do not include a Redirected Header Option\n" - " --ipv6-hlim, -c Redirected Header Payload's Hop Limit\n" - " --peer-addr, -x Redirected Header Payload's IPv6 Source Address\n" - " --peer-port, -a Redirected Header Payload's Source Port\n" - " --redir-port, -o Redirected Header Payload's Destination Port\n" - " --tcp-flags, -X Redirected Header Payload's TCP Flags\n" - " --tcp-seq, -q Redirected Header Payload's TCP SEQ Number\n" - " --tcp-ack, -Q Redirected Header Payload's TCP ACK Number\n" - " --tcp-urg, -V Redirected Header Payload's TCP URG Pointer\n" - " --tcp-win, -w Redirected Header Payload's TCP Window\n" - " --resp-mcast, -M Respond to Multicast Packets\n" - " --make-onlink, -O Make victim on-link\n" - " --learn-router, -N Dynamically learn local router addresses\n" - " --target-lla-opt, -E Target link-layer address option\n" - " --add-tlla-opt, -e Add Target link-layer address option\n" - " --block-src, -j Block IPv6 Source Address prefix\n" - " --block-dst, -k Block IPv6 Destination Address prefix\n" - " --block-link-src, -J Block Ethernet Source Address\n" - " --block-link-dst, -K Block Ethernet Destination Address\n" - " --accept-src, -b Accept IPv6 Source Address prefix\n" - " --accept-dst, -g Accept IPv6 Destination Address prefix\n" - " --accept-link-src, -B Accept Ethernet Source Address\n" - " --accept-link-dst, -G Accept Ethernet Destination Address\n" - " --sanity-filters, -f Add sanity filters\n" - " --flood-dests, -R Flood with multiple Redirect Destination Addresses\n" - " --flood-targets, -T Flood with multiple Redirect Target Addresses\n" - " --flood-sources, -F Flood with multiple IPv6 Source Addresses\n" - " --listen, -L Listen to incoming packets\n" - " --loop, -l Send periodic Redirect messages\n" - " --sleep, -z Pause between sending Redirect messages\n" - " --help, -h Print help for the rd6 tool\n" - " --verbose, -v Be verbose\n" - "\n" - "Programmed by Fernando Gont for SI6 Networks \n" - "Please send any bug reports to " - ); +void print_help(void) { + puts(SI6_TOOLKIT); + puts("rd6: Security assessment tool for attack vectors based on Redirect messages\n"); + usage(); + + puts("\nOPTIONS:\n" + " --interface, -i Network interface\n" + " --src-addr, -s IPv6 Source Address\n" + " --dst-addr, -d IPv6 Destination Address\n" + " --hop-limit, -A IPv6 Hop Limit\n" + " --frag-hdr. -y Fragment Header\n" + " --dst-opt-hdr, -u Destination Options Header (Fragmentable Part)\n" + " --dst-opt-u-hdr, -U Destination Options Header (Unfragmentable Part)\n" + " --hbh-opt-hdr, -H Hop by Hop Options Header\n" + " --link-src-addr, -S Link-layer Destination Address\n" + " --link-dst-addr, -D Link-layer Source Address\n" + " --redir-dest, -r Redirect Destination Address\n" + " --redir-target, -t Redirect Target Address\n" + " --payload-type, -p Redirected Header Payload Type\n" + " --payload-size, -P Redirected Header Payload Size\n" + " --no-payload, -n Do not include a Redirected Header Option\n" + " --ipv6-hlim, -c Redirected Header Payload's Hop Limit\n" + " --peer-addr, -x Redirected Header Payload's IPv6 Source Address\n" + " --peer-port, -a Redirected Header Payload's Source Port\n" + " --redir-port, -o Redirected Header Payload's Destination Port\n" + " --tcp-flags, -X Redirected Header Payload's TCP Flags\n" + " --tcp-seq, -q Redirected Header Payload's TCP SEQ Number\n" + " --tcp-ack, -Q Redirected Header Payload's TCP ACK Number\n" + " --tcp-urg, -V Redirected Header Payload's TCP URG Pointer\n" + " --tcp-win, -w Redirected Header Payload's TCP Window\n" + " --resp-mcast, -M Respond to Multicast Packets\n" + " --make-onlink, -O Make victim on-link\n" + " --learn-router, -N Dynamically learn local router addresses\n" + " --target-lla-opt, -E Target link-layer address option\n" + " --add-tlla-opt, -e Add Target link-layer address option\n" + " --block-src, -j Block IPv6 Source Address prefix\n" + " --block-dst, -k Block IPv6 Destination Address prefix\n" + " --block-link-src, -J Block Ethernet Source Address\n" + " --block-link-dst, -K Block Ethernet Destination Address\n" + " --accept-src, -b Accept IPv6 Source Address prefix\n" + " --accept-dst, -g Accept IPv6 Destination Address prefix\n" + " --accept-link-src, -B Accept Ethernet Source Address\n" + " --accept-link-dst, -G Accept Ethernet Destination Address\n" + " --sanity-filters, -f Add sanity filters\n" + " --flood-dests, -R Flood with multiple Redirect Destination Addresses\n" + " --flood-targets, -T Flood with multiple Redirect Target Addresses\n" + " --flood-sources, -F Flood with multiple IPv6 Source Addresses\n" + " --listen, -L Listen to incoming packets\n" + " --loop, -l Send periodic Redirect messages\n" + " --sleep, -z Pause between sending Redirect messages\n" + " --help, -h Print help for the rd6 tool\n" + " --verbose, -v Be verbose\n" + "\n" + "Programmed by Fernando Gont for SI6 Networks \n" + "Please send any bug reports to "); } - /* * Function: print_attack_info() * * Prints attack details (when the verbose ("-v") option is specified). */ - -void print_attack_info(struct iface_data *idata){ - if(makeonlink_f) - puts("Making nodes on-link (setting the RD Target Address to the RD Destination Address)"); - - if(floods_f) - printf("Flooding the target from %u different IPv6 Source Addresses\n", nsources); - - if(floodr_f) - printf("Flooding the target with %u Redirected Addresses\n", nredirs); - - if(floodt_f) - printf("Flooding the target with %u Target Addresses\n", ntargets); - - if(!floods_f){ - if(ether_ntop(&idata->hsrcaddr, plinkaddr, sizeof(plinkaddr)) == 0){ - puts("ether_ntop(): Error converting address"); - exit(EXIT_FAILURE); - } - - printf("Ethernet Source Address: %s%s\n", plinkaddr, ((!idata->hsrcaddr_f)?" (randomized)":"")); - } - else{ - if(idata->hsrcaddr_f){ - if(ether_ntop(&idata->hsrcaddr, plinkaddr, sizeof(plinkaddr)) == 0){ - puts("ether_ntop(): Error converting address"); - exit(EXIT_FAILURE); - } - - printf("Ethernet Source Address: %s\n", plinkaddr); - } - else - puts("Ethernet Source Address: randomized for each packet"); - } - - /* - Ethernet Destination Address only used if a IPv6 Destination Address or an - Ethernet Destination Address were specified. - */ - if(idata->dstaddr_f){ - if(ether_ntop(&idata->hdstaddr, plinkaddr, sizeof(plinkaddr)) == 0){ - puts("ether_ntop(): Error converting address"); - exit(EXIT_FAILURE); - } - - printf("Ethernet Destination Address: %s%s\n", plinkaddr, \ - ((!idata->hdstaddr_f)?" (all-nodes multicast)":"")); - } - - - if(inet_ntop(AF_INET6, &idata->srcaddr, psrcaddr, sizeof(psrcaddr)) == NULL){ - puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); - exit(EXIT_FAILURE); - } - - if(!floods_f){ - printf("IPv6 Source Address: %s%s\n", psrcaddr, ((!idata->srcaddr_f)?" (randomized)":"")); - } - else{ - printf("IPv6 Source Address: randomized, from the %s/%u prefix%s\n", psrcaddr, idata->srcpreflen, \ - (!idata->srcprefix_f)?" (default)":""); - } - - if(idata->dstaddr_f){ - if(inet_ntop(AF_INET6, &(idata->dstaddr), pdstaddr, sizeof(pdstaddr)) == NULL){ - puts("inet_ntop(): Error converting IPv6 Destination Address to presentation format"); - exit(EXIT_FAILURE); - } - - printf("IPv6 Destination Address: %s%s\n", pdstaddr, ((!idata->dstaddr_f)?" (all-nodes link-local multicast)":"")); - } - - printf("IPv6 Hop Limit: %u%s\n", hoplimit, (hoplimit_f)?"":" (default)"); - - for(i=0; ifragh_f) - printf("Sending each packet in fragments of %u bytes (plus the Unfragmentable part)\n", nfrags); - - if(inet_ntop(AF_INET6, &rediraddr, pv6addr, sizeof(pv6addr)) == NULL){ - puts("inet_ntop(): Error converting Redirected Address to presentation format"); - exit(EXIT_FAILURE); - } - - if(idata->dstaddr_f){ - if(!floodr_f){ - printf("Redirect Destination Address: %s%s\n", pv6addr, ((!rediraddr_f)?" (randomized)":"")); - } - else{ - printf("Redirect Destination Address: randomized, from the %s/%u prefix%s\n", pv6addr, redirpreflen, \ - (!redirprefix_f)?" (default)":""); - } - } - - if(inet_ntop(AF_INET6, &targetaddr, pv6addr, sizeof(pv6addr)) == NULL){ - puts("inet_ntop(): Error converting Redirect Target Address to presentation format"); - exit(EXIT_FAILURE); - } - - if(idata->dstaddr_f && targetaddr_f){ - if(!floodt_f){ - printf("Redirect Target Address: %s%s\n", pv6addr, ((!targetaddr_f)?" (randomized)":"")); - } - else{ - printf("Redirect Target Address: randomized, from the %s/%u prefix%s\n", pv6addr, targetpreflen, \ - (!targetprefix_f)?" (default)":""); - } - } - - for(i=0;i Address: %s\n", \ - ((floods_f && !tllaopta_f)?"(randomized for each packet)":plinkaddr)); - } - - if((rhtcp_f || rhdefault_f) && idata->dstaddr_f){ - printf("Payload Type: IPv6/TCP%s\n", (rhdefault_f?" (default)":"")); - printf("Source Port: %u%s\tDestination Port: %u%s\n", peerport, (peerport_f?"":" (randomized)"),\ - redirport, (redirport_f?"":" (randomized)")); - - printf("SEQ Number: %u%s\tACK Number: %u%s\n", tcpseq, (tcpseq_f?"":" (randomized)"), \ - tcpack, (tcpack_f?"":" (randomized)")); - - printf("Flags: %s%s%s%s%s%s%s%s\t", ((tcpflags & TH_FIN)?"F":""), ((tcpflags & TH_SYN)?"S":""), \ - ((tcpflags & TH_RST)?"R":""), ((tcpflags & TH_PUSH)?"P":""),\ - ((tcpflags & TH_ACK)?"A":""), ((tcpflags & TH_URG)?"U":""),\ - ((!tcpflags)?"none":""), ((!tcpflags_f)?" (default)":"")); - - printf("Window: %u%s\tURG Pointer: %u%s\n", tcpwin, (tcpwin_f?"":" (randomized)"), \ - tcpurg, (tcpurg_f?"":" (default)")); - } - - if(rhudp_f && idata->dstaddr_f){ - puts("Payload Type: IPv6/UDP"); - printf("Source Port: %u%s\tDestination Port: %u%s\n", peerport, (peerport_f?"":" (randomized)"),\ - redirport, (redirport_f?"":" (randomized)")); - } - - if(rhicmp6_f && idata->dstaddr_f){ - puts("Payload Type: IPv6/ICMPv6 Echo Request"); - printf("Identifier: %u%s\tSequence Number: %u%s", icmp6id, (icmp6id_f?"":" (randomized)"), \ - icmp6seq, (icmp6seq_f?"":" (randomized)")); - } -} +void print_attack_info(struct iface_data *idata) { + if (makeonlink_f) + puts("Making nodes on-link (setting the RD Target Address to the RD Destination Address)"); + + if (floods_f) + printf("Flooding the target from %u different IPv6 Source Addresses\n", nsources); + + if (floodr_f) + printf("Flooding the target with %u Redirected Addresses\n", nredirs); + + if (floodt_f) + printf("Flooding the target with %u Target Addresses\n", ntargets); + + if (!floods_f) { + if (ether_ntop(&idata->hsrcaddr, plinkaddr, sizeof(plinkaddr)) == 0) { + puts("ether_ntop(): Error converting address"); + exit(EXIT_FAILURE); + } + + printf("Ethernet Source Address: %s%s\n", plinkaddr, ((!idata->hsrcaddr_f) ? " (randomized)" : "")); + } + else { + if (idata->hsrcaddr_f) { + if (ether_ntop(&idata->hsrcaddr, plinkaddr, sizeof(plinkaddr)) == 0) { + puts("ether_ntop(): Error converting address"); + exit(EXIT_FAILURE); + } + + printf("Ethernet Source Address: %s\n", plinkaddr); + } + else + puts("Ethernet Source Address: randomized for each packet"); + } + + /* + Ethernet Destination Address only used if a IPv6 Destination Address or an + Ethernet Destination Address were specified. + */ + if (idata->dstaddr_f) { + if (ether_ntop(&idata->hdstaddr, plinkaddr, sizeof(plinkaddr)) == 0) { + puts("ether_ntop(): Error converting address"); + exit(EXIT_FAILURE); + } + + printf("Ethernet Destination Address: %s%s\n", plinkaddr, + ((!idata->hdstaddr_f) ? " (all-nodes multicast)" : "")); + } + + if (inet_ntop(AF_INET6, &idata->srcaddr, psrcaddr, sizeof(psrcaddr)) == NULL) { + puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); + exit(EXIT_FAILURE); + } + + if (!floods_f) { + printf("IPv6 Source Address: %s%s\n", psrcaddr, ((!idata->srcaddr_f) ? " (randomized)" : "")); + } + else { + printf("IPv6 Source Address: randomized, from the %s/%u prefix%s\n", psrcaddr, idata->srcpreflen, + (!idata->srcprefix_f) ? " (default)" : ""); + } + + if (idata->dstaddr_f) { + if (inet_ntop(AF_INET6, &(idata->dstaddr), pdstaddr, sizeof(pdstaddr)) == NULL) { + puts("inet_ntop(): Error converting IPv6 Destination Address to presentation format"); + exit(EXIT_FAILURE); + } + + printf("IPv6 Destination Address: %s%s\n", pdstaddr, + ((!idata->dstaddr_f) ? " (all-nodes link-local multicast)" : "")); + } + + printf("IPv6 Hop Limit: %u%s\n", hoplimit, (hoplimit_f) ? "" : " (default)"); + + for (i = 0; i < ndstoptuhdr; i++) + printf("Destination Options Header (Unfragmentable part): %u bytes\n", dstoptuhdrlen[i]); + + for (i = 0; i < nhbhopthdr; i++) + printf("Hop by Hop Options Header: %u bytes\n", hbhopthdrlen[i]); + + for (i = 0; i < ndstopthdr; i++) + printf("Destination Options Header: %u bytes\n", dstopthdrlen[i]); + + if (idata->fragh_f) + printf("Sending each packet in fragments of %u bytes (plus the Unfragmentable part)\n", nfrags); + + if (inet_ntop(AF_INET6, &rediraddr, pv6addr, sizeof(pv6addr)) == NULL) { + puts("inet_ntop(): Error converting Redirected Address to presentation format"); + exit(EXIT_FAILURE); + } + + if (idata->dstaddr_f) { + if (!floodr_f) { + printf("Redirect Destination Address: %s%s\n", pv6addr, ((!rediraddr_f) ? " (randomized)" : "")); + } + else { + printf("Redirect Destination Address: randomized, from the %s/%u prefix%s\n", pv6addr, redirpreflen, + (!redirprefix_f) ? " (default)" : ""); + } + } + + if (inet_ntop(AF_INET6, &targetaddr, pv6addr, sizeof(pv6addr)) == NULL) { + puts("inet_ntop(): Error converting Redirect Target Address to presentation format"); + exit(EXIT_FAILURE); + } + + if (idata->dstaddr_f && targetaddr_f) { + if (!floodt_f) { + printf("Redirect Target Address: %s%s\n", pv6addr, ((!targetaddr_f) ? " (randomized)" : "")); + } + else { + printf("Redirect Target Address: randomized, from the %s/%u prefix%s\n", pv6addr, targetpreflen, + (!targetprefix_f) ? " (default)" : ""); + } + } + + for (i = 0; i < nlinkaddr; i++) { + if (ether_ntop(&linkaddr[i], plinkaddr, sizeof(plinkaddr)) == 0) { + puts("ether_ntop(): Error converting address"); + exit(EXIT_FAILURE); + } + + printf("Target Link-layer Address option -> Address: %s\n", + ((floods_f && !tllaopta_f) ? "(randomized for each packet)" : plinkaddr)); + } + + if ((rhtcp_f || rhdefault_f) && idata->dstaddr_f) { + printf("Payload Type: IPv6/TCP%s\n", (rhdefault_f ? " (default)" : "")); + printf("Source Port: %u%s\tDestination Port: %u%s\n", peerport, (peerport_f ? "" : " (randomized)"), redirport, + (redirport_f ? "" : " (randomized)")); + + printf("SEQ Number: %u%s\tACK Number: %u%s\n", tcpseq, (tcpseq_f ? "" : " (randomized)"), tcpack, + (tcpack_f ? "" : " (randomized)")); + + printf("Flags: %s%s%s%s%s%s%s%s\t", ((tcpflags & TH_FIN) ? "F" : ""), ((tcpflags & TH_SYN) ? "S" : ""), + ((tcpflags & TH_RST) ? "R" : ""), ((tcpflags & TH_PUSH) ? "P" : ""), ((tcpflags & TH_ACK) ? "A" : ""), + ((tcpflags & TH_URG) ? "U" : ""), ((!tcpflags) ? "none" : ""), ((!tcpflags_f) ? " (default)" : "")); + + printf("Window: %u%s\tURG Pointer: %u%s\n", tcpwin, (tcpwin_f ? "" : " (randomized)"), tcpurg, + (tcpurg_f ? "" : " (default)")); + } + + if (rhudp_f && idata->dstaddr_f) { + puts("Payload Type: IPv6/UDP"); + printf("Source Port: %u%s\tDestination Port: %u%s\n", peerport, (peerport_f ? "" : " (randomized)"), redirport, + (redirport_f ? "" : " (randomized)")); + } + + if (rhicmp6_f && idata->dstaddr_f) { + puts("Payload Type: IPv6/ICMPv6 Echo Request"); + printf("Identifier: %u%s\tSequence Number: %u%s", icmp6id, (icmp6id_f ? "" : " (randomized)"), icmp6seq, + (icmp6seq_f ? "" : " (randomized)")); + } +} diff --git a/tools/rd6.h b/tools/rd6.h index 825625c..e0db02a 100644 --- a/tools/rd6.h +++ b/tools/rd6.h @@ -2,5 +2,3 @@ * Header file for the rd6 tool * */ - - diff --git a/tools/rs6.c b/tools/rs6.c index 5653b77..5049730 100644 --- a/tools/rs6.c +++ b/tools/rs6.c @@ -18,7 +18,7 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . - * + * * Build with: make rs6 * * The libpcap library must be previously installed on your system. @@ -26,525 +26,517 @@ * Please send any bug reports to Fernando Gont */ -#include #include #include +#include +#include +#include #include #include -#include +#include #include #include -#include -#include -#include #include -#include #include +#include +#include -#include "rs6.h" -#include "libipv6.h" #include "ipv6toolkit.h" +#include "libipv6.h" +#include "rs6.h" + +void init_packet_data(struct iface_data *); +void send_packet(struct iface_data *); +void print_attack_info(struct iface_data *); +void usage(void); +void print_help(void); + +struct pcap_pkthdr *pkthdr; +const u_char *pktdata; +struct in6_addr *pkt_ipv6addr; +bpf_u_int32 my_netmask; +bpf_u_int32 my_ip; +struct bpf_program pcap_filter; +char dev[64], errbuf[PCAP_ERRBUF_SIZE]; +char all_nodes_addr[] = ALL_NODES_MULTICAST_ADDR; + +unsigned char buffer[65556]; +unsigned char *v6buffer, *ptr, *startofprefixes; + +struct ip6_hdr *ipv6, *pkt_ipv6; +struct nd_router_solicit *rs; +struct ether_header *ethernet, *pkt_ether; +struct nd_opt_slla *sllaopt; +char *lasts, *endptr; + +int nw; +unsigned long ul_res, ul_val; + +unsigned int i, j, sources, nsources, startrand; + +uint16_t mask; +uint8_t hoplimit; -void init_packet_data(struct iface_data *); -void send_packet(struct iface_data *); -void print_attack_info(struct iface_data *); -void usage(void); -void print_help(void); - - -struct pcap_pkthdr *pkthdr; -const u_char *pktdata; -struct in6_addr *pkt_ipv6addr; -bpf_u_int32 my_netmask; -bpf_u_int32 my_ip; -struct bpf_program pcap_filter; -char dev[64], errbuf[PCAP_ERRBUF_SIZE]; -char all_nodes_addr[]= ALL_NODES_MULTICAST_ADDR; - -unsigned char buffer[65556]; -unsigned char *v6buffer, *ptr, *startofprefixes; - -struct ip6_hdr *ipv6, *pkt_ipv6; -struct nd_router_solicit *rs; -struct ether_header *ethernet, *pkt_ether; -struct nd_opt_slla *sllaopt; -char *lasts, *endptr; - -int nw; -unsigned long ul_res, ul_val; - -unsigned int i, j, sources, nsources, startrand; - -uint16_t mask; -uint8_t hoplimit; - -struct ether_addr linkaddr[MAX_SLLA_OPTION]; -unsigned int nlinkaddr=0, linkaddrs; -unsigned int nsleep; - -char *charptr; - -char plinkaddr[ETHER_ADDR_PLEN], phsrcaddr[ETHER_ADDR_PLEN], phdstaddr[ETHER_ADDR_PLEN]; -char psrcaddr[INET6_ADDRSTRLEN], pdstaddr[INET6_ADDRSTRLEN], pprefix[INET6_ADDRSTRLEN]; -unsigned char sllopt_f=0, sllopta_f=0, loop_f = 0, sleep_f=0, floods_f=0, hoplimit_f=0; -unsigned char newdata_f=0; +struct ether_addr linkaddr[MAX_SLLA_OPTION]; +unsigned int nlinkaddr = 0, linkaddrs; +unsigned int nsleep; + +char *charptr; + +char plinkaddr[ETHER_ADDR_PLEN], phsrcaddr[ETHER_ADDR_PLEN], phdstaddr[ETHER_ADDR_PLEN]; +char psrcaddr[INET6_ADDRSTRLEN], pdstaddr[INET6_ADDRSTRLEN], pprefix[INET6_ADDRSTRLEN]; +unsigned char sllopt_f = 0, sllopta_f = 0, loop_f = 0, sleep_f = 0, floods_f = 0, hoplimit_f = 0; +unsigned char newdata_f = 0; /* Support for IPv6 extension headers */ -unsigned int dstopthdrs, dstoptuhdrs, hbhopthdrs; -unsigned char hbhopthdr_f=0, dstoptuhdr_f=0, dstopthdr_f=0; -unsigned char *dstopthdr[MAX_DST_OPT_HDR], *dstoptuhdr[MAX_DST_OPT_U_HDR]; -unsigned char *hbhopthdr[MAX_HBH_OPT_HDR]; -unsigned int dstopthdrlen[MAX_DST_OPT_HDR], dstoptuhdrlen[MAX_DST_OPT_U_HDR]; -unsigned int hbhopthdrlen[MAX_HBH_OPT_HDR], m, pad; - -struct ip6_frag fraghdr, *fh; -struct ip6_hdr *fipv6; -unsigned char fragbuffer[ETHER_HDR_LEN+MIN_IPV6_HLEN+MAX_IPV6_PAYLOAD]; -unsigned char *fragpart, *fptr, *fptrend, *ptrend, *ptrhdr, *ptrhdrend; -unsigned int hdrlen, ndstopthdr=0, nhbhopthdr=0, ndstoptuhdr=0; -unsigned int nfrags, fragsize; -unsigned char *prev_nh, *startoffragment; - -struct iface_data idata; - -int main(int argc, char **argv){ - extern char *optarg; - int r; - - static struct option longopts[] = { - {"interface", required_argument, 0, 'i'}, - {"src-addr", required_argument, 0, 's'}, - {"dst-addr", required_argument, 0, 'd'}, - {"hop-limit", required_argument, 0, 'A'}, - {"dst-opt-hdr", required_argument, 0, 'u'}, - {"dst-opt-u-hdr", required_argument, 0, 'U'}, - {"hbh-opt-hdr", required_argument, 0, 'H'}, - {"frag-hdr", required_argument, 0, 'y'}, - {"link-src-addr", required_argument, 0, 'S'}, - {"link-dst-addr", required_argument, 0, 'D'}, - {"add-slla-opt", no_argument, 0, 'e'}, - {"src-link-opt", required_argument, 0, 'E'}, - {"flood-sources", required_argument, 0, 'F'}, - {"loop", no_argument, 0, 'l'}, - {"sleep", no_argument, 0, 'z'}, - {"verbose", no_argument, 0, 'v'}, - {"help", no_argument, 0, 'h'}, - {0, 0, 0, 0 } - }; - - const char shortopts[]= "i:s:d:A:u:U:H:y:S:D:eE:F:lz:vh"; - char option; - - if(argc<=1){ - usage(); - exit(EXIT_FAILURE); - } - - hoplimit=255; - - if(init_iface_data(&idata) == FAILURE){ - puts("Error initializing internal data structure"); - exit(EXIT_FAILURE); - } - - while((r=getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { - option= r; - - switch(option) { - case 'i': /* Interface */ - strncpy(idata.iface, optarg, IFACE_LENGTH); - idata.iface[IFACE_LENGTH-1]=0; - idata.iface_f=TRUE; - break; - - case 's': /* IPv6 Source Address */ - if((charptr = strtok_r(optarg, "/", &lasts)) == NULL){ - puts("Error in IPv6 Source Address ('-s' option)"); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, charptr, &(idata.srcaddr)) <= 0){ - puts("inet_pton(): address not valid"); - exit(EXIT_FAILURE); - } - - idata.srcaddr_f = 1; - - if((charptr = strtok_r(NULL, " ", &lasts)) != NULL){ - idata.srcpreflen = atoi(charptr); - - if(idata.srcpreflen>128){ - puts("Prefix length error in IPv6 Source Address"); - exit(EXIT_FAILURE); - } - - sanitize_ipv6_prefix(&(idata.srcaddr), idata.srcpreflen); - idata.srcprefix_f=1; - } - - break; - - case 'd': /* IPv6 Destination Address */ - if( inet_pton(AF_INET6, optarg, &(idata.dstaddr)) <= 0){ - puts("inet_pton(): address not valid"); - exit(EXIT_FAILURE); - } - - idata.dstaddr_f = 1; - break; - - case 'A': /* Hop Limit */ - hoplimit= atoi(optarg); - hoplimit_f=1; - break; - - case 'y': /* Fragment header */ - nfrags= atoi(optarg); - - if(nfrags < 8){ - puts("Error in Fragmentation option: Fragment Size must be at least 8 bytes"); - exit(EXIT_FAILURE); - } - - idata.fragh_f= 1; - break; - - case 'u': /* Destinations Options Header */ - if(ndstopthdr >= MAX_DST_OPT_HDR){ - puts("Too many Destination Options Headers"); - exit(EXIT_FAILURE); - } - - hdrlen= atoi(optarg); - - if(hdrlen < 8){ - puts("Bad length in Destination Options Header"); - exit(EXIT_FAILURE); - } - - hdrlen = ((hdrlen+7)/8) * 8; - dstopthdrlen[ndstopthdr]= hdrlen; - - if( (dstopthdr[ndstopthdr]= malloc(hdrlen)) == NULL){ - puts("Not enough memory for Destination Options Header"); - exit(EXIT_FAILURE); - } - - ptrhdr= dstopthdr[ndstopthdr] + 2; - ptrhdrend= dstopthdr[ndstopthdr] + hdrlen; - - while( ptrhdr < ptrhdrend){ - if( (ptrhdrend-ptrhdr)>257) - pad= 257; - else - pad= ptrhdrend-ptrhdr; - - if(!insert_pad_opt(ptrhdr, ptrhdrend, pad)){ - puts("Destination Options Header Too Big"); - exit(EXIT_FAILURE); - } - - ptrhdr= ptrhdr + pad; - } - - *(dstopthdr[ndstopthdr]+1)= (hdrlen/8)-1; - ndstopthdr++; - dstopthdr_f=1; - break; - - case 'U': /* Destination Options Header (Unfragmentable Part) */ - if(ndstoptuhdr >= MAX_DST_OPT_U_HDR){ - puts("Too many Destination Options Headers (Unfragmentable Part)"); - exit(EXIT_FAILURE); - } - - hdrlen= atoi(optarg); - - if(hdrlen < 8){ - puts("Bad length in Destination Options Header (Unfragmentable Part)"); - exit(EXIT_FAILURE); - } - - hdrlen = ((hdrlen+7)/8) * 8; - dstoptuhdrlen[ndstoptuhdr]= hdrlen; - - if( (dstoptuhdr[ndstoptuhdr]= malloc(hdrlen)) == NULL){ - puts("Not enough memory for Destination Options Header (Unfragmentable Part)"); - exit(EXIT_FAILURE); - } - - ptrhdr= dstoptuhdr[ndstoptuhdr]+2; - ptrhdrend= dstoptuhdr[ndstoptuhdr] + hdrlen; - - while( ptrhdr < ptrhdrend){ - - if( (ptrhdrend-ptrhdr)>257) - pad= 257; - else - pad= ptrhdrend-ptrhdr; - - if(!insert_pad_opt(ptrhdr, ptrhdrend, pad)){ - puts("Destination Options Header (Unfragmentable Part) Too Big"); - exit(EXIT_FAILURE); - } - - ptrhdr = ptrhdr + pad; - } - - *(dstoptuhdr[ndstoptuhdr]+1)= (hdrlen/8) - 1; - ndstoptuhdr++; - dstoptuhdr_f=1; - break; - - case 'H': /* Hop-by-Hop Options Header */ - if(nhbhopthdr >= MAX_HBH_OPT_HDR){ - puts("Too many Hop-by-Hop Options Headers"); - exit(EXIT_FAILURE); - } - - hdrlen= atoi(optarg); - - if(hdrlen < 8){ - puts("Bad length in Hop-by-Hop Options Header"); - exit(EXIT_FAILURE); - } - - hdrlen = ((hdrlen+7)/8) * 8; - hbhopthdrlen[nhbhopthdr]= hdrlen; - - if( (hbhopthdr[nhbhopthdr]= malloc(hdrlen)) == NULL){ - puts("Not enough memory for Hop-by-Hop Options Header"); - exit(EXIT_FAILURE); - } - - ptrhdr= hbhopthdr[nhbhopthdr] + 2; - ptrhdrend= hbhopthdr[nhbhopthdr] + hdrlen; - - - while( ptrhdr < ptrhdrend){ - - if( (ptrhdrend-ptrhdr)>257) - pad= 257; - else - pad= ptrhdrend-ptrhdr; - - if(!insert_pad_opt(ptrhdr, ptrhdrend, pad)){ - puts("Hop-by-Hop Options Header Too Big"); - exit(EXIT_FAILURE); - } - - ptrhdr = ptrhdr + pad; - } - - *(hbhopthdr[nhbhopthdr]+1)= (hdrlen/8) - 1; - nhbhopthdr++; - hbhopthdr_f=1; - break; - - case 'S': /* Source Ethernet address */ - idata.hsrcaddr_f = 1; - - if(ether_pton(optarg, &(idata.hsrcaddr), sizeof(idata.hsrcaddr)) == 0){ - puts("Error in Source link-layer address."); - exit(EXIT_FAILURE); - } - break; - - case 'D': /* Destination Ethernet Address */ - idata.hdstaddr_f = 1; - - if(ether_pton(optarg, &(idata.hdstaddr), sizeof(idata.hdstaddr)) == 0){ - puts("Error in Source link-layer address."); - exit(EXIT_FAILURE); - } - break; - - case 'E': /* Source link-layer option */ - sllopt_f = 1; - - if(ether_pton(optarg, &linkaddr[nlinkaddr], sizeof(struct ether_addr)) == 0){ - puts("Error in Source link-layer address option."); - exit(EXIT_FAILURE); - } - - sllopta_f=1; - nlinkaddr++; - break; - - case 'e': /* Add Source link-layer option */ - sllopt_f = 1; - break; - - case 'F': /* Flood sources */ - nsources= atoi(optarg); - if(nsources == 0){ - puts("Invalid number of sources in option -F"); - exit(EXIT_FAILURE); - } - - floods_f= 1; - break; - - case 'l': /* "Loop mode */ - loop_f = 1; - break; - - case 'z': /* Sleep option */ - nsleep=atoi(optarg); - if(nsleep==0){ - puts("Invalid number of seconds in '-z' option"); - exit(EXIT_FAILURE); - } - - sleep_f=1; - break; - - case 'v': /* Be verbose */ - idata.verbose_f=1; - break; - - case 'h': /* Help */ - print_help(); - - exit(EXIT_FAILURE); - break; - - default: - usage(); - exit(EXIT_FAILURE); - break; - - } /* switch */ +unsigned int dstopthdrs, dstoptuhdrs, hbhopthdrs; +unsigned char hbhopthdr_f = 0, dstoptuhdr_f = 0, dstopthdr_f = 0; +unsigned char *dstopthdr[MAX_DST_OPT_HDR], *dstoptuhdr[MAX_DST_OPT_U_HDR]; +unsigned char *hbhopthdr[MAX_HBH_OPT_HDR]; +unsigned int dstopthdrlen[MAX_DST_OPT_HDR], dstoptuhdrlen[MAX_DST_OPT_U_HDR]; +unsigned int hbhopthdrlen[MAX_HBH_OPT_HDR], m, pad; + +struct ip6_frag fraghdr, *fh; +struct ip6_hdr *fipv6; +unsigned char fragbuffer[ETHER_HDR_LEN + MIN_IPV6_HLEN + MAX_IPV6_PAYLOAD]; +unsigned char *fragpart, *fptr, *fptrend, *ptrend, *ptrhdr, *ptrhdrend; +unsigned int hdrlen, ndstopthdr = 0, nhbhopthdr = 0, ndstoptuhdr = 0; +unsigned int nfrags, fragsize; +unsigned char *prev_nh, *startoffragment; + +struct iface_data idata; + +int main(int argc, char **argv) { + extern char *optarg; + int r; + + static struct option longopts[] = {{"interface", required_argument, 0, 'i'}, + {"src-addr", required_argument, 0, 's'}, + {"dst-addr", required_argument, 0, 'd'}, + {"hop-limit", required_argument, 0, 'A'}, + {"dst-opt-hdr", required_argument, 0, 'u'}, + {"dst-opt-u-hdr", required_argument, 0, 'U'}, + {"hbh-opt-hdr", required_argument, 0, 'H'}, + {"frag-hdr", required_argument, 0, 'y'}, + {"link-src-addr", required_argument, 0, 'S'}, + {"link-dst-addr", required_argument, 0, 'D'}, + {"add-slla-opt", no_argument, 0, 'e'}, + {"src-link-opt", required_argument, 0, 'E'}, + {"flood-sources", required_argument, 0, 'F'}, + {"loop", no_argument, 0, 'l'}, + {"sleep", no_argument, 0, 'z'}, + {"verbose", no_argument, 0, 'v'}, + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0}}; + + const char shortopts[] = "i:s:d:A:u:U:H:y:S:D:eE:F:lz:vh"; + char option; + + if (argc <= 1) { + usage(); + exit(EXIT_FAILURE); + } + + hoplimit = 255; + + if (init_iface_data(&idata) == FAILURE) { + puts("Error initializing internal data structure"); + exit(EXIT_FAILURE); + } + + while ((r = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { + option = r; + + switch (option) { + case 'i': /* Interface */ + strncpy(idata.iface, optarg, IFACE_LENGTH); + idata.iface[IFACE_LENGTH - 1] = 0; + idata.iface_f = TRUE; + break; + + case 's': /* IPv6 Source Address */ + if ((charptr = strtok_r(optarg, "/", &lasts)) == NULL) { + puts("Error in IPv6 Source Address ('-s' option)"); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, charptr, &(idata.srcaddr)) <= 0) { + puts("inet_pton(): address not valid"); + exit(EXIT_FAILURE); + } + + idata.srcaddr_f = 1; + + if ((charptr = strtok_r(NULL, " ", &lasts)) != NULL) { + idata.srcpreflen = atoi(charptr); + + if (idata.srcpreflen > 128) { + puts("Prefix length error in IPv6 Source Address"); + exit(EXIT_FAILURE); + } + + sanitize_ipv6_prefix(&(idata.srcaddr), idata.srcpreflen); + idata.srcprefix_f = 1; + } + + break; + + case 'd': /* IPv6 Destination Address */ + if (inet_pton(AF_INET6, optarg, &(idata.dstaddr)) <= 0) { + puts("inet_pton(): address not valid"); + exit(EXIT_FAILURE); + } + + idata.dstaddr_f = 1; + break; + + case 'A': /* Hop Limit */ + hoplimit = atoi(optarg); + hoplimit_f = 1; + break; + + case 'y': /* Fragment header */ + nfrags = atoi(optarg); + + if (nfrags < 8) { + puts("Error in Fragmentation option: Fragment Size must be at least 8 bytes"); + exit(EXIT_FAILURE); + } + + idata.fragh_f = 1; + break; + + case 'u': /* Destinations Options Header */ + if (ndstopthdr >= MAX_DST_OPT_HDR) { + puts("Too many Destination Options Headers"); + exit(EXIT_FAILURE); + } + + hdrlen = atoi(optarg); + + if (hdrlen < 8) { + puts("Bad length in Destination Options Header"); + exit(EXIT_FAILURE); + } + + hdrlen = ((hdrlen + 7) / 8) * 8; + dstopthdrlen[ndstopthdr] = hdrlen; + + if ((dstopthdr[ndstopthdr] = malloc(hdrlen)) == NULL) { + puts("Not enough memory for Destination Options Header"); + exit(EXIT_FAILURE); + } + + ptrhdr = dstopthdr[ndstopthdr] + 2; + ptrhdrend = dstopthdr[ndstopthdr] + hdrlen; + + while (ptrhdr < ptrhdrend) { + if ((ptrhdrend - ptrhdr) > 257) + pad = 257; + else + pad = ptrhdrend - ptrhdr; + + if (!insert_pad_opt(ptrhdr, ptrhdrend, pad)) { + puts("Destination Options Header Too Big"); + exit(EXIT_FAILURE); + } + + ptrhdr = ptrhdr + pad; + } + + *(dstopthdr[ndstopthdr] + 1) = (hdrlen / 8) - 1; + ndstopthdr++; + dstopthdr_f = 1; + break; + + case 'U': /* Destination Options Header (Unfragmentable Part) */ + if (ndstoptuhdr >= MAX_DST_OPT_U_HDR) { + puts("Too many Destination Options Headers (Unfragmentable Part)"); + exit(EXIT_FAILURE); + } + + hdrlen = atoi(optarg); + + if (hdrlen < 8) { + puts("Bad length in Destination Options Header (Unfragmentable Part)"); + exit(EXIT_FAILURE); + } + + hdrlen = ((hdrlen + 7) / 8) * 8; + dstoptuhdrlen[ndstoptuhdr] = hdrlen; + + if ((dstoptuhdr[ndstoptuhdr] = malloc(hdrlen)) == NULL) { + puts("Not enough memory for Destination Options Header (Unfragmentable Part)"); + exit(EXIT_FAILURE); + } + + ptrhdr = dstoptuhdr[ndstoptuhdr] + 2; + ptrhdrend = dstoptuhdr[ndstoptuhdr] + hdrlen; + + while (ptrhdr < ptrhdrend) { + + if ((ptrhdrend - ptrhdr) > 257) + pad = 257; + else + pad = ptrhdrend - ptrhdr; + + if (!insert_pad_opt(ptrhdr, ptrhdrend, pad)) { + puts("Destination Options Header (Unfragmentable Part) Too Big"); + exit(EXIT_FAILURE); + } + + ptrhdr = ptrhdr + pad; + } + + *(dstoptuhdr[ndstoptuhdr] + 1) = (hdrlen / 8) - 1; + ndstoptuhdr++; + dstoptuhdr_f = 1; + break; + + case 'H': /* Hop-by-Hop Options Header */ + if (nhbhopthdr >= MAX_HBH_OPT_HDR) { + puts("Too many Hop-by-Hop Options Headers"); + exit(EXIT_FAILURE); + } + + hdrlen = atoi(optarg); + + if (hdrlen < 8) { + puts("Bad length in Hop-by-Hop Options Header"); + exit(EXIT_FAILURE); + } + + hdrlen = ((hdrlen + 7) / 8) * 8; + hbhopthdrlen[nhbhopthdr] = hdrlen; + + if ((hbhopthdr[nhbhopthdr] = malloc(hdrlen)) == NULL) { + puts("Not enough memory for Hop-by-Hop Options Header"); + exit(EXIT_FAILURE); + } + + ptrhdr = hbhopthdr[nhbhopthdr] + 2; + ptrhdrend = hbhopthdr[nhbhopthdr] + hdrlen; + + while (ptrhdr < ptrhdrend) { + + if ((ptrhdrend - ptrhdr) > 257) + pad = 257; + else + pad = ptrhdrend - ptrhdr; + + if (!insert_pad_opt(ptrhdr, ptrhdrend, pad)) { + puts("Hop-by-Hop Options Header Too Big"); + exit(EXIT_FAILURE); + } + + ptrhdr = ptrhdr + pad; + } + + *(hbhopthdr[nhbhopthdr] + 1) = (hdrlen / 8) - 1; + nhbhopthdr++; + hbhopthdr_f = 1; + break; + + case 'S': /* Source Ethernet address */ + idata.hsrcaddr_f = 1; + + if (ether_pton(optarg, &(idata.hsrcaddr), sizeof(idata.hsrcaddr)) == 0) { + puts("Error in Source link-layer address."); + exit(EXIT_FAILURE); + } + break; + + case 'D': /* Destination Ethernet Address */ + idata.hdstaddr_f = 1; + + if (ether_pton(optarg, &(idata.hdstaddr), sizeof(idata.hdstaddr)) == 0) { + puts("Error in Source link-layer address."); + exit(EXIT_FAILURE); + } + break; + + case 'E': /* Source link-layer option */ + sllopt_f = 1; + + if (ether_pton(optarg, &linkaddr[nlinkaddr], sizeof(struct ether_addr)) == 0) { + puts("Error in Source link-layer address option."); + exit(EXIT_FAILURE); + } + + sllopta_f = 1; + nlinkaddr++; + break; + + case 'e': /* Add Source link-layer option */ + sllopt_f = 1; + break; + + case 'F': /* Flood sources */ + nsources = atoi(optarg); + if (nsources == 0) { + puts("Invalid number of sources in option -F"); + exit(EXIT_FAILURE); + } + + floods_f = 1; + break; + + case 'l': /* "Loop mode */ + loop_f = 1; + break; + + case 'z': /* Sleep option */ + nsleep = atoi(optarg); + if (nsleep == 0) { + puts("Invalid number of seconds in '-z' option"); + exit(EXIT_FAILURE); + } + + sleep_f = 1; + break; + + case 'v': /* Be verbose */ + idata.verbose_f = 1; + break; + + case 'h': /* Help */ + print_help(); + + exit(EXIT_FAILURE); + break; + + default: + usage(); + exit(EXIT_FAILURE); + break; + + } /* switch */ } /* while(getopt) */ - if(geteuid()) { - puts("rs6 needs root privileges to run."); - exit(EXIT_FAILURE); - } + if (geteuid()) { + puts("rs6 needs root privileges to run."); + exit(EXIT_FAILURE); + } + + if (!idata.iface_f) { + puts("Must specify the network interface with the -i option"); + exit(EXIT_FAILURE); + } - if(!idata.iface_f){ - puts("Must specify the network interface with the -i option"); - exit(EXIT_FAILURE); - } + if (load_dst_and_pcap(&idata, (idata.dstaddr_f ? LOAD_SRC_NXT_HOP : LOAD_PCAP_ONLY)) == FAILURE) { + puts("Error while learning Source Address and Next Hop"); + exit(EXIT_FAILURE); + } - if(load_dst_and_pcap(&idata, (idata.dstaddr_f?LOAD_SRC_NXT_HOP:LOAD_PCAP_ONLY)) == FAILURE){ - puts("Error while learning Source Address and Next Hop"); - exit(EXIT_FAILURE); - } + release_privileges(); - release_privileges(); + if (pcap_datalink(idata.pfd) != DLT_EN10MB) { + printf("Error: Interface %s is not an Ethernet interface\n", idata.iface); + exit(EXIT_FAILURE); + } - if( pcap_datalink(idata.pfd) != DLT_EN10MB){ - printf("Error: Interface %s is not an Ethernet interface\n", idata.iface); - exit(EXIT_FAILURE); - } + if (pcap_compile(idata.pfd, &pcap_filter, PCAP_NOPACKETS_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1) { + printf("pcap_compile(): %s", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } - if(pcap_compile(idata.pfd, &pcap_filter, PCAP_NOPACKETS_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1){ - printf("pcap_compile(): %s", pcap_geterr(idata.pfd)); - exit(EXIT_FAILURE); - } - - if(pcap_setfilter(idata.pfd, &pcap_filter) == -1){ - printf("pcap_setfilter(): %s", pcap_geterr(idata.pfd)); - exit(EXIT_FAILURE); - } + if (pcap_setfilter(idata.pfd, &pcap_filter) == -1) { + printf("pcap_setfilter(): %s", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } - pcap_freecode(&pcap_filter); + pcap_freecode(&pcap_filter); - srandom(time(NULL)); + srandom(time(NULL)); - /* + /* If the IPv6 Source Address has not been specified, and the "-F" (flood) option has not been specified, select a random link-local unicast address. */ - if(!idata.srcaddr_f && !floods_f){ - /* When randomizing a link-local IPv6 address, select addresses that belong to the - prefix fe80::/64 (that's what a link-local address looks-like in legitimate cases). - The KAME implementation discards addresses in which the second highe-order 16 bits - (srcaddr.s6_addr16[1] in our case) are not zero. - */ - if ( inet_pton(AF_INET6, "fe80::", &(idata.srcaddr)) <= 0){ - puts("inet_pton(): Error when converting address"); - exit(EXIT_FAILURE); - } - - randomize_ipv6_addr(&(idata.srcaddr), &(idata.srcaddr), 64); + if (!idata.srcaddr_f && !floods_f) { + /* When randomizing a link-local IPv6 address, select addresses that belong to the + prefix fe80::/64 (that's what a link-local address looks-like in legitimate cases). + The KAME implementation discards addresses in which the second highe-order 16 bits + (srcaddr.s6_addr16[1] in our case) are not zero. + */ + if (inet_pton(AF_INET6, "fe80::", &(idata.srcaddr)) <= 0) { + puts("inet_pton(): Error when converting address"); + exit(EXIT_FAILURE); + } + + randomize_ipv6_addr(&(idata.srcaddr), &(idata.srcaddr), 64); } - /* If the flood option ("-F") has been specified, but no prefix has been specified, select the random Source Addresses from the link-local unicast prefix (fe80::/64). */ - if(floods_f && !idata.srcprefix_f){ - if ( inet_pton(AF_INET6, "fe80::", &(idata.srcaddr)) <= 0){ - puts("inet_pton(): Error when converting address"); - exit(EXIT_FAILURE); - } - - randomize_ipv6_addr(&(idata.srcaddr), &(idata.srcaddr), 64); - idata.srcpreflen=64; - } - - if(!idata.dstaddr_f){ /* Destination Address defaults to all-nodes (ff02::1) */ - if( inet_pton(AF_INET6, ALL_ROUTERS_MULTICAST_ADDR, &(idata.dstaddr)) <= 0){ - puts("inet_pton(): address not valid"); - exit(EXIT_FAILURE); - } - } - - if(!idata.hsrcaddr_f) /* Source link-layer address is randomized by default */ - randomize_ether_addr(&(idata.hsrcaddr)); - - if(!idata.hdstaddr_f) /* Destination link-layer address defaults to all-nodes */ - if(ether_pton(ETHER_ALLROUTERS_LINK_ADDR, &(idata.hdstaddr), sizeof(idata.hdstaddr)) == 0){ - puts("ether_pton(): Error converting all-nodes multicast address"); - exit(EXIT_FAILURE); - } - - if(sllopt_f && !sllopta_f){ /* The value of the source link-layer address option */ - linkaddr[0]= idata.hsrcaddr; /* defaults to the source Ethernet address */ - nlinkaddr++; - } - - if(!floods_f) - nsources=1; - - if(!sleep_f) - nsleep=1; - - if( !idata.fragh_f && dstoptuhdr_f){ - puts("Dst. Options Header (Unfragmentable Part) set, but Fragmentation not specified"); - exit(EXIT_FAILURE); - } - - if(idata.verbose_f){ - print_attack_info(&idata); - } + if (floods_f && !idata.srcprefix_f) { + if (inet_pton(AF_INET6, "fe80::", &(idata.srcaddr)) <= 0) { + puts("inet_pton(): Error when converting address"); + exit(EXIT_FAILURE); + } + + randomize_ipv6_addr(&(idata.srcaddr), &(idata.srcaddr), 64); + idata.srcpreflen = 64; + } + + if (!idata.dstaddr_f) { /* Destination Address defaults to all-nodes (ff02::1) */ + if (inet_pton(AF_INET6, ALL_ROUTERS_MULTICAST_ADDR, &(idata.dstaddr)) <= 0) { + puts("inet_pton(): address not valid"); + exit(EXIT_FAILURE); + } + } + + if (!idata.hsrcaddr_f) /* Source link-layer address is randomized by default */ + randomize_ether_addr(&(idata.hsrcaddr)); + + if (!idata.hdstaddr_f) /* Destination link-layer address defaults to all-nodes */ + if (ether_pton(ETHER_ALLROUTERS_LINK_ADDR, &(idata.hdstaddr), sizeof(idata.hdstaddr)) == 0) { + puts("ether_pton(): Error converting all-nodes multicast address"); + exit(EXIT_FAILURE); + } + + if (sllopt_f && !sllopta_f) { /* The value of the source link-layer address option */ + linkaddr[0] = idata.hsrcaddr; /* defaults to the source Ethernet address */ + nlinkaddr++; + } + + if (!floods_f) + nsources = 1; + + if (!sleep_f) + nsleep = 1; + + if (!idata.fragh_f && dstoptuhdr_f) { + puts("Dst. Options Header (Unfragmentable Part) set, but Fragmentation not specified"); + exit(EXIT_FAILURE); + } + + if (idata.verbose_f) { + print_attack_info(&idata); + } /* Set initial contents of the attack packet */ init_packet_data(&idata); - + send_packet(&idata); - - if(idata.verbose_f) - puts("Initial attack packet(s) sent successfully."); - - if(loop_f && idata.verbose_f) - printf("Now sending Router Solicitations every %u second%s...\n", nsleep, \ - ((nsleep>1)?"s":"")); - - while(loop_f){ - sleep(nsleep); - send_packet(&idata); - } - - exit(EXIT_SUCCESS); -} + if (idata.verbose_f) + puts("Initial attack packet(s) sent successfully."); + if (loop_f && idata.verbose_f) + printf("Now sending Router Solicitations every %u second%s...\n", nsleep, ((nsleep > 1) ? "s" : "")); + + while (loop_f) { + sleep(nsleep); + send_packet(&idata); + } + + exit(EXIT_SUCCESS); +} /* * Function: init_packet_data() @@ -552,142 +544,142 @@ int main(int argc, char **argv){ * Initialize the contents of the attack packet (Ethernet header, IPv6 Header, and ICMPv6 header) * that are expected to remain constant for the specified attack. */ -void init_packet_data(struct iface_data *idata){ - struct dlt_null *dlt_null; - ethernet= (struct ether_header *) buffer; - dlt_null= (struct dlt_null *) buffer; - v6buffer = buffer + idata->linkhsize; - ipv6 = (struct ip6_hdr *) v6buffer; - - if(idata->type == DLT_EN10MB){ - ethernet->ether_type = htons(ETHERTYPE_IPV6); - - if(!(idata->flags & IFACE_LOOPBACK)){ - ethernet->src = idata->hsrcaddr; - ethernet->dst = idata->hdstaddr; - } - } - else if(idata->type == DLT_NULL){ - dlt_null->family= PF_INET6; - } -#if defined (__OpenBSD__) - else if(idata->type == DLT_LOOP){ - dlt_null->family= htonl(PF_INET6); - } +void init_packet_data(struct iface_data *idata) { + struct dlt_null *dlt_null; + ethernet = (struct ether_header *)buffer; + dlt_null = (struct dlt_null *)buffer; + v6buffer = buffer + idata->linkhsize; + ipv6 = (struct ip6_hdr *)v6buffer; + + if (idata->type == DLT_EN10MB) { + ethernet->ether_type = htons(ETHERTYPE_IPV6); + + if (!(idata->flags & IFACE_LOOPBACK)) { + ethernet->src = idata->hsrcaddr; + ethernet->dst = idata->hdstaddr; + } + } + else if (idata->type == DLT_NULL) { + dlt_null->family = PF_INET6; + } +#if defined(__OpenBSD__) + else if (idata->type == DLT_LOOP) { + dlt_null->family = htonl(PF_INET6); + } #endif - ipv6->ip6_flow=0; - ipv6->ip6_vfc= 0x60; - ipv6->ip6_hlim= hoplimit; - ipv6->ip6_src= idata->srcaddr; - ipv6->ip6_dst= idata->dstaddr; - prev_nh = (unsigned char *) &(ipv6->ip6_nxt); - - ptr = (unsigned char *) v6buffer + MIN_IPV6_HLEN; - - if(hbhopthdr_f){ - hbhopthdrs=0; - - while(hbhopthdrs < nhbhopthdr){ - if((ptr+ hbhopthdrlen[hbhopthdrs]) > (v6buffer+ idata->mtu)){ - puts("Packet too large while processing HBH Opt. Header"); - exit(EXIT_FAILURE); - } - - *prev_nh = IPPROTO_HOPOPTS; - prev_nh = ptr; - memcpy(ptr, hbhopthdr[hbhopthdrs], hbhopthdrlen[hbhopthdrs]); - ptr = ptr + hbhopthdrlen[hbhopthdrs]; - hbhopthdrs++; - } - } - - if(dstoptuhdr_f){ - dstoptuhdrs=0; - - while(dstoptuhdrs < ndstoptuhdr){ - if((ptr+ dstoptuhdrlen[dstoptuhdrs]) > (v6buffer+ idata->mtu)){ - puts("Packet too large while processing Dest. Opt. Header (Unfrag. Part)"); - exit(EXIT_FAILURE); - } - - *prev_nh = IPPROTO_DSTOPTS; - prev_nh = ptr; - memcpy(ptr, dstoptuhdr[dstoptuhdrs], dstoptuhdrlen[dstoptuhdrs]); - ptr = ptr + dstoptuhdrlen[dstoptuhdrs]; - dstoptuhdrs++; - } - } - - /* Everything that follows is the Fragmentable Part of the packet */ - fragpart = ptr; - - if(idata->fragh_f){ - /* Check that we are able to send the Unfragmentable Part, together with a - Fragment Header and a chunk data over our link layer - */ - if( (fragpart+sizeof(fraghdr)+nfrags) > (v6buffer+idata->mtu)){ - printf("Unfragmentable part too large for current MTU (%u bytes)\n", idata->mtu); - exit(EXIT_FAILURE); - } - - /* We prepare a separete Fragment Header, but we do not include it in the packet to be sent. - This Fragment Header will be used (an assembled with the rest of the packet by the - send_packet() function. - */ - memset(&fraghdr, 0, FRAG_HDR_SIZE); - *prev_nh = IPPROTO_FRAGMENT; - prev_nh = (unsigned char *) &fraghdr; - } - - if(dstopthdr_f){ - dstopthdrs=0; - - while(dstopthdrs < ndstopthdr){ - if((ptr+ dstopthdrlen[dstopthdrs]) > (v6buffer+idata->max_packet_size)){ - puts("Packet too large while processing Dest. Opt. Header (U. part) (should be using the Frag. option?)"); - exit(EXIT_FAILURE); - } - - *prev_nh = IPPROTO_DSTOPTS; - prev_nh = ptr; - memcpy(ptr, dstopthdr[dstopthdrs], dstopthdrlen[dstopthdrs]); - ptr = ptr + dstopthdrlen[dstopthdrs]; - dstopthdrs++; - } - } - - *prev_nh = IPPROTO_ICMPV6; - - if( (ptr+sizeof(struct nd_router_solicit)) > (v6buffer+idata->max_packet_size)){ - puts("Packet too large while inserting Router Solicitation header (should be using Frag. option?)"); - exit(EXIT_FAILURE); - } - - rs= (struct nd_router_solicit *) (ptr); - rs->nd_rs_type = ND_ROUTER_SOLICIT; - rs->nd_rs_code = 0; - - ptr += sizeof(struct nd_router_solicit); - - /* If a single source link-layer address is specified, it is included in all packets */ - if(sllopt_f && nlinkaddr==1){ - if( (ptr+sizeof(struct nd_opt_slla)) <= (v6buffer+idata->max_packet_size)){ - sllaopt = (struct nd_opt_slla *) ptr; - sllaopt->type= ND_OPT_SOURCE_LINKADDR; - sllaopt->length= SLLA_OPT_LEN; - memcpy(sllaopt->address, linkaddr[0].a, ETH_ALEN); - ptr += sizeof(struct nd_opt_slla); - } - else{ - puts("Packet too large while processing source link-layer address opt. (should be using Frag. option?)"); - exit(EXIT_FAILURE); - } - } - - startofprefixes = ptr; -} + ipv6->ip6_flow = 0; + ipv6->ip6_vfc = 0x60; + ipv6->ip6_hlim = hoplimit; + ipv6->ip6_src = idata->srcaddr; + ipv6->ip6_dst = idata->dstaddr; + prev_nh = (unsigned char *)&(ipv6->ip6_nxt); + + ptr = (unsigned char *)v6buffer + MIN_IPV6_HLEN; + + if (hbhopthdr_f) { + hbhopthdrs = 0; + + while (hbhopthdrs < nhbhopthdr) { + if ((ptr + hbhopthdrlen[hbhopthdrs]) > (v6buffer + idata->mtu)) { + puts("Packet too large while processing HBH Opt. Header"); + exit(EXIT_FAILURE); + } + + *prev_nh = IPPROTO_HOPOPTS; + prev_nh = ptr; + memcpy(ptr, hbhopthdr[hbhopthdrs], hbhopthdrlen[hbhopthdrs]); + ptr = ptr + hbhopthdrlen[hbhopthdrs]; + hbhopthdrs++; + } + } + + if (dstoptuhdr_f) { + dstoptuhdrs = 0; + + while (dstoptuhdrs < ndstoptuhdr) { + if ((ptr + dstoptuhdrlen[dstoptuhdrs]) > (v6buffer + idata->mtu)) { + puts("Packet too large while processing Dest. Opt. Header (Unfrag. Part)"); + exit(EXIT_FAILURE); + } + + *prev_nh = IPPROTO_DSTOPTS; + prev_nh = ptr; + memcpy(ptr, dstoptuhdr[dstoptuhdrs], dstoptuhdrlen[dstoptuhdrs]); + ptr = ptr + dstoptuhdrlen[dstoptuhdrs]; + dstoptuhdrs++; + } + } + + /* Everything that follows is the Fragmentable Part of the packet */ + fragpart = ptr; + + if (idata->fragh_f) { + /* Check that we are able to send the Unfragmentable Part, together with a + Fragment Header and a chunk data over our link layer + */ + if ((fragpart + sizeof(fraghdr) + nfrags) > (v6buffer + idata->mtu)) { + printf("Unfragmentable part too large for current MTU (%u bytes)\n", idata->mtu); + exit(EXIT_FAILURE); + } + + /* We prepare a separete Fragment Header, but we do not include it in the packet to be sent. + This Fragment Header will be used (an assembled with the rest of the packet by the + send_packet() function. + */ + memset(&fraghdr, 0, FRAG_HDR_SIZE); + *prev_nh = IPPROTO_FRAGMENT; + prev_nh = (unsigned char *)&fraghdr; + } + + if (dstopthdr_f) { + dstopthdrs = 0; + + while (dstopthdrs < ndstopthdr) { + if ((ptr + dstopthdrlen[dstopthdrs]) > (v6buffer + idata->max_packet_size)) { + puts("Packet too large while processing Dest. Opt. Header (U. part) (should be using the Frag. " + "option?)"); + exit(EXIT_FAILURE); + } + + *prev_nh = IPPROTO_DSTOPTS; + prev_nh = ptr; + memcpy(ptr, dstopthdr[dstopthdrs], dstopthdrlen[dstopthdrs]); + ptr = ptr + dstopthdrlen[dstopthdrs]; + dstopthdrs++; + } + } + + *prev_nh = IPPROTO_ICMPV6; + + if ((ptr + sizeof(struct nd_router_solicit)) > (v6buffer + idata->max_packet_size)) { + puts("Packet too large while inserting Router Solicitation header (should be using Frag. option?)"); + exit(EXIT_FAILURE); + } + rs = (struct nd_router_solicit *)(ptr); + rs->nd_rs_type = ND_ROUTER_SOLICIT; + rs->nd_rs_code = 0; + + ptr += sizeof(struct nd_router_solicit); + + /* If a single source link-layer address is specified, it is included in all packets */ + if (sllopt_f && nlinkaddr == 1) { + if ((ptr + sizeof(struct nd_opt_slla)) <= (v6buffer + idata->max_packet_size)) { + sllaopt = (struct nd_opt_slla *)ptr; + sllaopt->type = ND_OPT_SOURCE_LINKADDR; + sllaopt->length = SLLA_OPT_LEN; + memcpy(sllaopt->address, linkaddr[0].a, ETH_ALEN); + ptr += sizeof(struct nd_opt_slla); + } + else { + puts("Packet too large while processing source link-layer address opt. (should be using Frag. option?)"); + exit(EXIT_FAILURE); + } + } + + startofprefixes = ptr; +} /* * Function: send_packet() @@ -695,266 +687,252 @@ void init_packet_data(struct iface_data *idata){ * Initialize the remaining fields of the Router Solicitation Message, and * send the attack apcket(s). */ -void send_packet(struct iface_data *idata){ - sources=0; - - do{ - if(floods_f){ - /* - Randomize the IPv6 Source address based on the specified prefix and prefix length - (defaults to fe80::/64). - */ - randomize_ipv6_addr(&(ipv6->ip6_src), &(idata->srcaddr), idata->srcpreflen); - - if(!idata->hsrcaddr_f){ - randomize_ether_addr(&(ethernet->src)); - - /* - If the source-link layer address must be included, but no value was - specified we set it to the randomized Ethernet Source Address - */ - if(sllopt_f && !sllopta_f){ - memcpy(sllaopt->address, ethernet->src.a, ETH_ALEN); - } - } - } - - if(nlinkaddr==1) - linkaddrs=1; - else - linkaddrs=0; - - do{ - newdata_f=0; - ptr = startofprefixes; - - while(linkaddrsmax_packet_size){ - sllaopt = (struct nd_opt_slla *) ptr; - sllaopt->type= ND_OPT_SOURCE_LINKADDR; - sllaopt->length= SLLA_OPT_LEN; - memcpy(sllaopt->address, linkaddr[linkaddrs].a, ETH_ALEN); - ptr += sizeof(struct nd_opt_slla); - linkaddrs++; - newdata_f=1; - } - - - rs->nd_rs_cksum = 0; - rs->nd_rs_cksum = in_chksum(v6buffer, rs, ptr-((unsigned char *)rs), IPPROTO_ICMPV6); - - - if(!idata->fragh_f){ - ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); - - if((nw=pcap_inject(idata->pfd, buffer, ptr - buffer)) == -1){ - printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); - exit(EXIT_FAILURE); - } - - if(nw != (ptr-buffer)){ - printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, \ - (LUI) (ptr-buffer)); - exit(EXIT_FAILURE); - } - } - else{ - ptrend= ptr; - ptr= fragpart; - fptr = fragbuffer; - fipv6 = (struct ip6_hdr *) (fragbuffer + ETHER_HDR_LEN); - fptrend = fptr + ETHER_HDR_LEN+MIN_IPV6_HLEN+MAX_IPV6_PAYLOAD; - memcpy(fptr, buffer, fragpart-buffer); - fptr = fptr + (fragpart-buffer); - - if( (fptr+FRAG_HDR_SIZE)> fptrend){ - puts("Unfragmentable Part is Too Large"); - exit(EXIT_FAILURE); - } - - memcpy(fptr, (char *) &fraghdr, FRAG_HDR_SIZE); - fh= (struct ip6_frag *) fptr; - fh->ip6f_ident=random(); - startoffragment = fptr + FRAG_HDR_SIZE; - - /* - * Check that the selected fragment size is not larger than the largest fragment - * size that can be sent - */ - - if(nfrags > (fptrend - fptr)) - nfrags= (fptrend-fptr); - - m=IP6F_MORE_FRAG; - - while((ptr< ptrend) && m==IP6F_MORE_FRAG){ - fptr= startoffragment; - - if( (ptrend-ptr) <= nfrags){ - fragsize= ptrend-ptr; - m=0; - } - else{ - fragsize = (nfrags + 7) & ntohs(IP6F_OFF_MASK); - } - - memcpy(fptr, ptr, fragsize); - fh->ip6f_offlg = (htons(ptr-fragpart) & IP6F_OFF_MASK) | m; - ptr+=fragsize; - fptr+=fragsize; - - fipv6->ip6_plen = htons((fptr - fragbuffer) - MIN_IPV6_HLEN - ETHER_HDR_LEN); - - if((nw=pcap_inject(idata->pfd, fragbuffer, fptr - fragbuffer)) == -1){ - printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); - exit(EXIT_FAILURE); - } - - if(nw != (fptr- fragbuffer)){ - printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw,\ - (LUI) (ptr-buffer)); - exit(EXIT_FAILURE); - } - } - } - }while(linkaddrs>nlinkaddr && newdata_f); - - sources++; - }while(sourcesip6_src), &(idata->srcaddr), idata->srcpreflen); + + if (!idata->hsrcaddr_f) { + randomize_ether_addr(&(ethernet->src)); + + /* + If the source-link layer address must be included, but no value was + specified we set it to the randomized Ethernet Source Address + */ + if (sllopt_f && !sllopta_f) { + memcpy(sllaopt->address, ethernet->src.a, ETH_ALEN); + } + } + } + + if (nlinkaddr == 1) + linkaddrs = 1; + else + linkaddrs = 0; + + do { + newdata_f = 0; + ptr = startofprefixes; + + while (linkaddrs < nlinkaddr && (ptr + sizeof(struct nd_opt_slla) - v6buffer) <= idata->max_packet_size) { + sllaopt = (struct nd_opt_slla *)ptr; + sllaopt->type = ND_OPT_SOURCE_LINKADDR; + sllaopt->length = SLLA_OPT_LEN; + memcpy(sllaopt->address, linkaddr[linkaddrs].a, ETH_ALEN); + ptr += sizeof(struct nd_opt_slla); + linkaddrs++; + newdata_f = 1; + } + + rs->nd_rs_cksum = 0; + rs->nd_rs_cksum = in_chksum(v6buffer, rs, ptr - ((unsigned char *)rs), IPPROTO_ICMPV6); + + if (!idata->fragh_f) { + ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); + + if ((nw = pcap_inject(idata->pfd, buffer, ptr - buffer)) == -1) { + printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); + exit(EXIT_FAILURE); + } + + if (nw != (ptr - buffer)) { + printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, (LUI)(ptr - buffer)); + exit(EXIT_FAILURE); + } + } + else { + ptrend = ptr; + ptr = fragpart; + fptr = fragbuffer; + fipv6 = (struct ip6_hdr *)(fragbuffer + ETHER_HDR_LEN); + fptrend = fptr + ETHER_HDR_LEN + MIN_IPV6_HLEN + MAX_IPV6_PAYLOAD; + memcpy(fptr, buffer, fragpart - buffer); + fptr = fptr + (fragpart - buffer); + + if ((fptr + FRAG_HDR_SIZE) > fptrend) { + puts("Unfragmentable Part is Too Large"); + exit(EXIT_FAILURE); + } + + memcpy(fptr, (char *)&fraghdr, FRAG_HDR_SIZE); + fh = (struct ip6_frag *)fptr; + fh->ip6f_ident = random(); + startoffragment = fptr + FRAG_HDR_SIZE; + + /* + * Check that the selected fragment size is not larger than the largest fragment + * size that can be sent + */ + + if (nfrags > (fptrend - fptr)) + nfrags = (fptrend - fptr); + + m = IP6F_MORE_FRAG; + + while ((ptr < ptrend) && m == IP6F_MORE_FRAG) { + fptr = startoffragment; + + if ((ptrend - ptr) <= nfrags) { + fragsize = ptrend - ptr; + m = 0; + } + else { + fragsize = (nfrags + 7) & ntohs(IP6F_OFF_MASK); + } + + memcpy(fptr, ptr, fragsize); + fh->ip6f_offlg = (htons(ptr - fragpart) & IP6F_OFF_MASK) | m; + ptr += fragsize; + fptr += fragsize; + + fipv6->ip6_plen = htons((fptr - fragbuffer) - MIN_IPV6_HLEN - ETHER_HDR_LEN); + + if ((nw = pcap_inject(idata->pfd, fragbuffer, fptr - fragbuffer)) == -1) { + printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); + exit(EXIT_FAILURE); + } + + if (nw != (fptr - fragbuffer)) { + printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, (LUI)(ptr - buffer)); + exit(EXIT_FAILURE); + } + } + } + } while (linkaddrs > nlinkaddr && newdata_f); + + sources++; + } while (sources < nsources); } - - /* * Function: usage() * * Print the syntax of the rs6 tool */ -void usage(void){ +void usage(void) { puts("usage: rs6 -i INTERFACE [-s SRC_ADDR[/LEN]] [-d DST_ADDR] [-y FRAG_SIZE]" - " [-u DST_OPT_HDR_SIZE] [-U DST_OPT_U_HDR_SIZE] [-H HBH_OPT_HDR_SIZE]" - " [-S LINK_SRC_ADDR] [-D LINK-DST-ADDR] [-E LINK_ADDR] [-e] [-F N_SOURCES]" - " [-z SECONDS] [-l] [-v] [-h]"); + " [-u DST_OPT_HDR_SIZE] [-U DST_OPT_U_HDR_SIZE] [-H HBH_OPT_HDR_SIZE]" + " [-S LINK_SRC_ADDR] [-D LINK-DST-ADDR] [-E LINK_ADDR] [-e] [-F N_SOURCES]" + " [-z SECONDS] [-l] [-v] [-h]"); } - /* * Function: print_help() * * Print help information for the rs6 tool */ -void print_help(void){ - puts(SI6_TOOLKIT); - puts( "rs6: Security assessment tool for attack vectors based on RS messages\n"); - usage(); - - puts("\nOPTIONS:\n" - " --interface, -i Network interface\n" - " --src-addr, -s IPv6 Source Address\n" - " --dst-addr, -d IPv6 Destination Address\n" - " --frag-hdr. -y Fragment Header\n" - " --dst-opt-hdr, -u Destination Options Header (Fragmentable Part)\n" - " --dst-opt-u-hdr, -U Destination Options Header (Unfragmentable Part)\n" - " --hbh-opt-hdr, -H Hop by Hop Options Header\n" - " --link-src-addr, -S Link-layer Destination Address\n" - " --link-dst-addr, -D Link-layer Source Address\n" - " --src-link-opt, -E Source link-layer address option\n" - " --add-slla-opt, -e Add Source link-layer address option\n" - " --flood-sources, -F Number of Source Addresses to forge randomly\n" - " --loop, -l Send Router Solicitations periodically\n" - " --sleep, -z Pause between peiodic Router Solicitations\n" - " --help, -h Print help for the rs6 tool\n" - " --verbose, -v Be verbose\n" - "\n" - "Programmed by Fernando Gont for SI6 Networks \n" - "Please send any bug reports to " - ); +void print_help(void) { + puts(SI6_TOOLKIT); + puts("rs6: Security assessment tool for attack vectors based on RS messages\n"); + usage(); + + puts("\nOPTIONS:\n" + " --interface, -i Network interface\n" + " --src-addr, -s IPv6 Source Address\n" + " --dst-addr, -d IPv6 Destination Address\n" + " --frag-hdr. -y Fragment Header\n" + " --dst-opt-hdr, -u Destination Options Header (Fragmentable Part)\n" + " --dst-opt-u-hdr, -U Destination Options Header (Unfragmentable Part)\n" + " --hbh-opt-hdr, -H Hop by Hop Options Header\n" + " --link-src-addr, -S Link-layer Destination Address\n" + " --link-dst-addr, -D Link-layer Source Address\n" + " --src-link-opt, -E Source link-layer address option\n" + " --add-slla-opt, -e Add Source link-layer address option\n" + " --flood-sources, -F Number of Source Addresses to forge randomly\n" + " --loop, -l Send Router Solicitations periodically\n" + " --sleep, -z Pause between peiodic Router Solicitations\n" + " --help, -h Print help for the rs6 tool\n" + " --verbose, -v Be verbose\n" + "\n" + "Programmed by Fernando Gont for SI6 Networks \n" + "Please send any bug reports to "); } - - /* * Function: print_attack_info() * * Print attack details (when the verbose ("-v") option is specified). */ -void print_attack_info(struct iface_data *idata){ - if(floods_f) - printf("Flooding the target from %u different IPv6 Source Addresses\n", nsources); - - if(!floods_f){ - if(ether_ntop(&(idata->hsrcaddr), plinkaddr, sizeof(plinkaddr)) == 0){ - puts("ether_ntop(): Error converting address"); - exit(EXIT_FAILURE); - } - - printf("Ethernet Source Address: %s%s\n", plinkaddr, ((!idata->hsrcaddr_f)?" (randomized)":"")); - } - else{ - if(idata->hsrcaddr_f){ - if(ether_ntop(&(idata->hsrcaddr), plinkaddr, sizeof(plinkaddr)) == 0){ - puts("ether_ntop(): Error converting address"); - exit(EXIT_FAILURE); - } - - printf("Ethernet Source Address: %s\n", plinkaddr); - } - else - puts("Ethernet Source Address: randomized for each packet"); - } - - if(ether_ntop(&(idata->hdstaddr), phdstaddr, sizeof(phdstaddr)) == 0){ - puts("ether_ntop(): Error converting address"); - exit(EXIT_FAILURE); - } - - printf("Ethernet Destination Address: %s%s\n", phdstaddr, \ - ((!idata->hdstaddr_f)?" (all-routers multicast)":"")); - - - if(inet_ntop(AF_INET6, &(idata->srcaddr), psrcaddr, sizeof(psrcaddr)) == NULL){ - puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); - exit(EXIT_FAILURE); - } - - if(!floods_f){ - printf("IPv6 Source Address: %s%s\n", psrcaddr, ((!idata->srcaddr_f)?" (randomized)":"")); - } - else{ - printf("IPv6 Source Address: randomized, from the %s/%u prefix%s\n", psrcaddr, idata->srcpreflen, \ - (!idata->srcprefix_f)?" (default)":""); - } - - if(inet_ntop(AF_INET6, &(idata->dstaddr), pdstaddr, sizeof(pdstaddr)) == NULL){ - perror("inet_ntop()"); - exit(EXIT_FAILURE); - } - - printf("IPv6 Destination Address: %s%s\n", pdstaddr, \ - ((!idata->dstaddr_f)?" (all-routers link-local multicast)":"")); - - printf("IPv6 Hop Limit: %u%s\n", hoplimit, (hoplimit_f)?"":" (default)"); - - for(i=0; ifragh_f) - printf("Sending each packet in fragments of %u bytes (plus the Unfragmentable part)\n", nfrags); - - for(i=0;i Address: %s\n", \ - ((floods_f && !sllopta_f)?"(randomized for each packet)":plinkaddr)); - } -} +void print_attack_info(struct iface_data *idata) { + if (floods_f) + printf("Flooding the target from %u different IPv6 Source Addresses\n", nsources); + + if (!floods_f) { + if (ether_ntop(&(idata->hsrcaddr), plinkaddr, sizeof(plinkaddr)) == 0) { + puts("ether_ntop(): Error converting address"); + exit(EXIT_FAILURE); + } + + printf("Ethernet Source Address: %s%s\n", plinkaddr, ((!idata->hsrcaddr_f) ? " (randomized)" : "")); + } + else { + if (idata->hsrcaddr_f) { + if (ether_ntop(&(idata->hsrcaddr), plinkaddr, sizeof(plinkaddr)) == 0) { + puts("ether_ntop(): Error converting address"); + exit(EXIT_FAILURE); + } + + printf("Ethernet Source Address: %s\n", plinkaddr); + } + else + puts("Ethernet Source Address: randomized for each packet"); + } + + if (ether_ntop(&(idata->hdstaddr), phdstaddr, sizeof(phdstaddr)) == 0) { + puts("ether_ntop(): Error converting address"); + exit(EXIT_FAILURE); + } + printf("Ethernet Destination Address: %s%s\n", phdstaddr, ((!idata->hdstaddr_f) ? " (all-routers multicast)" : "")); + if (inet_ntop(AF_INET6, &(idata->srcaddr), psrcaddr, sizeof(psrcaddr)) == NULL) { + puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); + exit(EXIT_FAILURE); + } + + if (!floods_f) { + printf("IPv6 Source Address: %s%s\n", psrcaddr, ((!idata->srcaddr_f) ? " (randomized)" : "")); + } + else { + printf("IPv6 Source Address: randomized, from the %s/%u prefix%s\n", psrcaddr, idata->srcpreflen, + (!idata->srcprefix_f) ? " (default)" : ""); + } + + if (inet_ntop(AF_INET6, &(idata->dstaddr), pdstaddr, sizeof(pdstaddr)) == NULL) { + perror("inet_ntop()"); + exit(EXIT_FAILURE); + } + + printf("IPv6 Destination Address: %s%s\n", pdstaddr, + ((!idata->dstaddr_f) ? " (all-routers link-local multicast)" : "")); + + printf("IPv6 Hop Limit: %u%s\n", hoplimit, (hoplimit_f) ? "" : " (default)"); + + for (i = 0; i < ndstoptuhdr; i++) + printf("Destination Options Header (Unfragmentable part): %u bytes\n", dstoptuhdrlen[i]); + + for (i = 0; i < nhbhopthdr; i++) + printf("Hop by Hop Options Header: %u bytes\n", hbhopthdrlen[i]); + + for (i = 0; i < ndstopthdr; i++) + printf("Destination Options Header: %u bytes\n", dstopthdrlen[i]); + + if (idata->fragh_f) + printf("Sending each packet in fragments of %u bytes (plus the Unfragmentable part)\n", nfrags); + + for (i = 0; i < nlinkaddr; i++) { + if (ether_ntop(&linkaddr[i], plinkaddr, sizeof(plinkaddr)) == 0) { + puts("ether_ntop(): Error converting address"); + exit(EXIT_FAILURE); + } + + printf("Source Link-layer Address option -> Address: %s\n", + ((floods_f && !sllopta_f) ? "(randomized for each packet)" : plinkaddr)); + } +} diff --git a/tools/rs6.h b/tools/rs6.h index 92a6e5c..dae0f97 100644 --- a/tools/rs6.h +++ b/tools/rs6.h @@ -2,5 +2,3 @@ * Header file for the rs6 tool * */ - - diff --git a/tools/scan6.c b/tools/scan6.c index 42ede7f..962d8b7 100644 --- a/tools/scan6.c +++ b/tools/scan6.c @@ -25,3139 +25,3127 @@ * Please send any bug reports to Fernando Gont */ -#include #include -#include +#include #include +#include #include -#include +#include #include +#include +#include +#include #include #include -#include #include -#include -#include #include -#include #include -#include +#include #include +#include #include #include #include #include -#include +#include #include -#include "scan6.h" #include "ipv6toolkit.h" #include "libipv6.h" +#include "scan6.h" /* #define DEBUG */ /* Function prototypes */ -void init_packet_data(struct iface_data *); -int create_candidate_globals(struct iface_data *, struct host_list *, struct host_list *, \ - struct host_list *); -int find_local_globals(pcap_t *, struct iface_data *, unsigned char, const char *, struct host_list *); -void free_host_entries(struct host_list *); -int host_scan_local(pcap_t *, struct iface_data *, struct in6_addr *, unsigned char, \ - struct host_entry *); -int multi_scan_local(pcap_t *, struct iface_data *, struct in6_addr *, unsigned char, \ - const char *, struct host_list *); -void print_help(void); -void print_port_entries(struct port_list *); -int print_host_entries(struct host_list *, unsigned char); -int print_unique_host_entries(struct host_list *, unsigned char); -void local_sig_alarm(int); -void usage(void); -int validate_host_entries(pcap_t *, struct iface_data *, struct host_list *, struct host_list *); - -int probe_node_nd(const char *, struct ether_addr *, struct in6_addr *, struct in6_addr *,\ - struct ether_addr *); -int process_icmp6_response(struct iface_data *, struct host_list *, unsigned char , \ - struct pcap_pkthdr *, const u_char *, unsigned char *); -int valid_icmp6_response(struct iface_data *, unsigned char, struct pcap_pkthdr *,\ - const u_char *, unsigned char *); -int valid_icmp6_response_remote(struct iface_data *, struct scan_list *, unsigned char, \ - struct pcap_pkthdr *, const u_char *, unsigned char *); -int print_scan_entries(struct scan_list *); -int load_ipv4mapped32_entries(struct scan_list *, struct scan_entry *, struct prefix4_entry *); -int load_ipv4mapped64_entries(struct scan_list *, struct scan_entry *, struct prefix4_entry *); -int load_embeddedport_entries(struct scan_list *, struct scan_entry *); -int load_lowbyte_entries(struct scan_list *, struct scan_entry *); -int load_oui_entries(struct scan_list *, struct scan_entry *, struct ether_addr *); -int load_port_table(struct port_table_entry *, char *, unsigned int); -int load_top_ports_entries(struct port_list *, struct port_list *, uint8_t, unsigned int); -int load_vm_entries(struct scan_list *, struct scan_entry *, struct prefix4_entry *); -int load_vendor_entries(struct scan_list *, struct scan_entry *, char *); -int load_knownprefix_entries(struct scan_list *, struct scan_list *, FILE *); -int load_knowniid_entries(struct scan_list *, struct scan_list *, struct prefix_list *); -int load_knowniidfile_entries(struct scan_list *, struct scan_list *, FILE *); -int load_smart_entries(struct scan_list *, struct scan_list *); -int match_strings(char *, char *); -int load_bruteforce_entries(struct scan_list *, struct scan_entry *); -void prefix_to_scan(struct prefix_entry *, struct scan_entry *); -void print_port_entries(struct port_list *); -void print_port_scan(struct port_list *, unsigned int *, int); -void print_port_table(struct port_table_entry *, unsigned int); -int get_next_target(struct scan_list *); - -int get_next_port(struct port_list *); -int is_port_in_range(struct port_list *); -int is_target_in_range(struct scan_list *); -int send_probe_remote(struct iface_data *, struct scan_list *, struct in6_addr *, unsigned char); -int send_pscan_probe(struct iface_data *, struct scan_list *, struct port_list *, struct in6_addr *, unsigned char); -void reset_scan_list(struct scan_list *); -void reset_port_list(struct port_list *); -int process_config_file(const char *); -int is_ip6_in_scan_list(struct scan_list *, struct in6_addr *); -int add_to_scan_list(struct scan_list *, struct scan_entry *); -int is_scan_entry_duplicate(struct scan_list *, struct scan_entry *); - +void init_packet_data(struct iface_data *); +int create_candidate_globals(struct iface_data *, struct host_list *, struct host_list *, struct host_list *); +int find_local_globals(pcap_t *, struct iface_data *, unsigned char, const char *, struct host_list *); +void free_host_entries(struct host_list *); +int host_scan_local(pcap_t *, struct iface_data *, struct in6_addr *, unsigned char, struct host_entry *); +int multi_scan_local(pcap_t *, struct iface_data *, struct in6_addr *, unsigned char, const char *, struct host_list *); +void print_help(void); +void print_port_entries(struct port_list *); +int print_host_entries(struct host_list *, unsigned char); +int print_unique_host_entries(struct host_list *, unsigned char); +void local_sig_alarm(int); +void usage(void); +int validate_host_entries(pcap_t *, struct iface_data *, struct host_list *, struct host_list *); + +int probe_node_nd(const char *, struct ether_addr *, struct in6_addr *, struct in6_addr *, struct ether_addr *); +int process_icmp6_response(struct iface_data *, struct host_list *, unsigned char, struct pcap_pkthdr *, const u_char *, + unsigned char *); +int valid_icmp6_response(struct iface_data *, unsigned char, struct pcap_pkthdr *, const u_char *, unsigned char *); +int valid_icmp6_response_remote(struct iface_data *, struct scan_list *, unsigned char, struct pcap_pkthdr *, + const u_char *, unsigned char *); +int print_scan_entries(struct scan_list *); +int load_ipv4mapped32_entries(struct scan_list *, struct scan_entry *, struct prefix4_entry *); +int load_ipv4mapped64_entries(struct scan_list *, struct scan_entry *, struct prefix4_entry *); +int load_embeddedport_entries(struct scan_list *, struct scan_entry *); +int load_lowbyte_entries(struct scan_list *, struct scan_entry *); +int load_oui_entries(struct scan_list *, struct scan_entry *, struct ether_addr *); +int load_port_table(struct port_table_entry *, char *, unsigned int); +int load_top_ports_entries(struct port_list *, struct port_list *, uint8_t, unsigned int); +int load_vm_entries(struct scan_list *, struct scan_entry *, struct prefix4_entry *); +int load_vendor_entries(struct scan_list *, struct scan_entry *, char *); +int load_knownprefix_entries(struct scan_list *, struct scan_list *, FILE *); +int load_knowniid_entries(struct scan_list *, struct scan_list *, struct prefix_list *); +int load_knowniidfile_entries(struct scan_list *, struct scan_list *, FILE *); +int load_smart_entries(struct scan_list *, struct scan_list *); +int match_strings(char *, char *); +int load_bruteforce_entries(struct scan_list *, struct scan_entry *); +void prefix_to_scan(struct prefix_entry *, struct scan_entry *); +void print_port_entries(struct port_list *); +void print_port_scan(struct port_list *, unsigned int *, int); +void print_port_table(struct port_table_entry *, unsigned int); +int get_next_target(struct scan_list *); + +int get_next_port(struct port_list *); +int is_port_in_range(struct port_list *); +int is_target_in_range(struct scan_list *); +int send_probe_remote(struct iface_data *, struct scan_list *, struct in6_addr *, unsigned char); +int send_pscan_probe(struct iface_data *, struct scan_list *, struct port_list *, struct in6_addr *, unsigned char); +void reset_scan_list(struct scan_list *); +void reset_port_list(struct port_list *); +int process_config_file(const char *); +int is_ip6_in_scan_list(struct scan_list *, struct in6_addr *); +int add_to_scan_list(struct scan_list *, struct scan_entry *); +int is_scan_entry_duplicate(struct scan_list *, struct scan_entry *); /* Used for multiscan */ -struct host_list host_local, host_global, host_candidate; -struct host_entry *host_locals[MAX_IPV6_ENTRIES], *host_globals[MAX_IPV6_ENTRIES]; -struct host_entry *host_candidates[MAX_IPV6_ENTRIES]; +struct host_list host_local, host_global, host_candidate; +struct host_entry *host_locals[MAX_IPV6_ENTRIES], *host_globals[MAX_IPV6_ENTRIES]; +struct host_entry *host_candidates[MAX_IPV6_ENTRIES]; /* Used for router discovery */ -struct iface_data idata; +struct iface_data idata; /* Variables used for learning the default router */ -struct ether_addr router_ether, rs_ether; -struct in6_addr router_ipv6, rs_ipv6; +struct ether_addr router_ether, rs_ether; +struct in6_addr router_ipv6, rs_ipv6; -struct in6_addr randprefix; -unsigned char randpreflen; +struct in6_addr randprefix; +unsigned char randpreflen; /* Data structures for packets read from the wire */ -struct pcap_pkthdr *pkthdr; -const u_char *pktdata; -unsigned char *pkt_end; -struct ether_header *pkt_ether; -struct ip6_hdr *pkt_ipv6; -struct in6_addr *pkt_ipv6addr; -unsigned int pktbytes; -struct icmp6_hdr *pkt_icmp6; -struct nd_neighbor_solicit *pkt_ns; -struct tcp_hdr *pkt_tcp; -struct udp_hdr *pkt_udp; -struct ip6_eh *pkt_eh; -int result; -unsigned char error_f; - - -bpf_u_int32 my_netmask; -bpf_u_int32 my_ip; -struct bpf_program pcap_filter; -char dev[64], errbuf[PCAP_ERRBUF_SIZE]; -unsigned char buffer[BUFFER_SIZE], buffrh[MIN_IPV6_HLEN + MIN_TCP_HLEN]; -char line[LINE_BUFFER_SIZE]; -unsigned char *v6buffer, *ptr, *startofprefixes; -char *pref; - -struct ip6_hdr *ipv6; -struct icmp6_hdr *icmp6; - -struct ether_header *ethernet; -unsigned int ndst=0; - -char *lasts, *rpref; -char *charptr; - -int nw; -unsigned long ul_res, ul_val; -unsigned int i, j, startrand; -unsigned int skip; -unsigned char dstpreflen; - -uint16_t mask; -uint8_t hoplimit; - -char plinkaddr[ETHER_ADDR_PLEN], pv4addr[INET_ADDRSTRLEN]; -char psrcaddr[INET6_ADDRSTRLEN], pdstaddr[INET6_ADDRSTRLEN], pv6addr[INET6_ADDRSTRLEN]; -unsigned char verbose_f=FALSE; -unsigned char rand_src_f=FALSE, rand_link_src_f=FALSE; -unsigned char accepted_f=FALSE, configfile_f=FALSE, dstaddr_f=FALSE, hdstaddr_f=FALSE, dstprefix_f=FALSE; -unsigned char print_f=FALSE, print_local_f=FALSE, print_global_f=FALSE, probe_echo_f=FALSE, probe_unrec_f=FALSE, probe_f=FALSE; -unsigned char print_type=NOT_PRINT_ETHER_ADDR, scan_local_f=FALSE, print_unique_f=FALSE, localaddr_f=FALSE; -unsigned char timestamps_f=FALSE; +struct pcap_pkthdr *pkthdr; +const u_char *pktdata; +unsigned char *pkt_end; +struct ether_header *pkt_ether; +struct ip6_hdr *pkt_ipv6; +struct in6_addr *pkt_ipv6addr; +unsigned int pktbytes; +struct icmp6_hdr *pkt_icmp6; +struct nd_neighbor_solicit *pkt_ns; +struct tcp_hdr *pkt_tcp; +struct udp_hdr *pkt_udp; +struct ip6_eh *pkt_eh; +int result; +unsigned char error_f; + +bpf_u_int32 my_netmask; +bpf_u_int32 my_ip; +struct bpf_program pcap_filter; +char dev[64], errbuf[PCAP_ERRBUF_SIZE]; +unsigned char buffer[BUFFER_SIZE], buffrh[MIN_IPV6_HLEN + MIN_TCP_HLEN]; +char line[LINE_BUFFER_SIZE]; +unsigned char *v6buffer, *ptr, *startofprefixes; +char *pref; + +struct ip6_hdr *ipv6; +struct icmp6_hdr *icmp6; + +struct ether_header *ethernet; +unsigned int ndst = 0; + +char *lasts, *rpref; +char *charptr; + +int nw; +unsigned long ul_res, ul_val; +unsigned int i, j, startrand; +unsigned int skip; +unsigned char dstpreflen; + +uint16_t mask; +uint8_t hoplimit; + +char plinkaddr[ETHER_ADDR_PLEN], pv4addr[INET_ADDRSTRLEN]; +char psrcaddr[INET6_ADDRSTRLEN], pdstaddr[INET6_ADDRSTRLEN], pv6addr[INET6_ADDRSTRLEN]; +unsigned char verbose_f = FALSE; +unsigned char rand_src_f = FALSE, rand_link_src_f = FALSE; +unsigned char accepted_f = FALSE, configfile_f = FALSE, dstaddr_f = FALSE, hdstaddr_f = FALSE, dstprefix_f = FALSE; +unsigned char print_f = FALSE, print_local_f = FALSE, print_global_f = FALSE, probe_echo_f = FALSE, + probe_unrec_f = FALSE, probe_f = FALSE; +unsigned char print_type = NOT_PRINT_ETHER_ADDR, scan_local_f = FALSE, print_unique_f = FALSE, localaddr_f = FALSE; +unsigned char timestamps_f = FALSE; /* Support for Extension Headers */ -unsigned int dstopthdrs, dstoptuhdrs, hbhopthdrs; -char hbhopthdr_f=FALSE, dstoptuhdr_f=FALSE, dstopthdr_f=FALSE; -unsigned char *dstopthdr[MAX_DST_OPT_HDR], *dstoptuhdr[MAX_DST_OPT_U_HDR]; -unsigned char *hbhopthdr[MAX_HBH_OPT_HDR]; -unsigned int dstopthdrlen[MAX_DST_OPT_HDR], dstoptuhdrlen[MAX_DST_OPT_U_HDR]; -unsigned int hbhopthdrlen[MAX_HBH_OPT_HDR], m, pad; - -struct ip6_frag fraghdr, *fh; -struct ip6_hdr *fipv6; - -unsigned char fragbuffer[ETHER_HDR_LEN+MIN_IPV6_HLEN+MAX_IPV6_PAYLOAD]; -unsigned char *fragpart, *fptr, *fptrend, *ptrend, *ptrhdr, *ptrhdrend; -unsigned int hdrlen, ndstopthdr=0, nhbhopthdr=0, ndstoptuhdr=0; -unsigned int nfrags, fragsize; -unsigned char *prev_nh, *startoffragment; +unsigned int dstopthdrs, dstoptuhdrs, hbhopthdrs; +char hbhopthdr_f = FALSE, dstoptuhdr_f = FALSE, dstopthdr_f = FALSE; +unsigned char *dstopthdr[MAX_DST_OPT_HDR], *dstoptuhdr[MAX_DST_OPT_U_HDR]; +unsigned char *hbhopthdr[MAX_HBH_OPT_HDR]; +unsigned int dstopthdrlen[MAX_DST_OPT_HDR], dstoptuhdrlen[MAX_DST_OPT_U_HDR]; +unsigned int hbhopthdrlen[MAX_HBH_OPT_HDR], m, pad; + +struct ip6_frag fraghdr, *fh; +struct ip6_hdr *fipv6; + +unsigned char fragbuffer[ETHER_HDR_LEN + MIN_IPV6_HLEN + MAX_IPV6_PAYLOAD]; +unsigned char *fragpart, *fptr, *fptrend, *ptrend, *ptrhdr, *ptrhdrend; +unsigned int hdrlen, ndstopthdr = 0, nhbhopthdr = 0, ndstoptuhdr = 0; +unsigned int nfrags, fragsize; +unsigned char *prev_nh, *startoffragment; /* Remote scans */ -unsigned int inc=1; -int ranges; -struct scan_list scan_list; -struct scan_entry *target_list[MAX_SCAN_ENTRIES]; -struct scan_list prefix_list, smart_list; - -struct scan_entry *tgt_pref_list[MAX_PREF_ENTRIES]; -struct scan_entry *smrt_pref_list[MAX_PREF_ENTRIES]; -struct prefix_list iid_list; -struct prefix_entry *tgt_iid_list[MAX_IID_ENTRIES]; -struct port_list tcp_port_list, udp_port_list, *port_list; +unsigned int inc = 1; +int ranges; +struct scan_list scan_list; +struct scan_entry *target_list[MAX_SCAN_ENTRIES]; +struct scan_list prefix_list, smart_list; + +struct scan_entry *tgt_pref_list[MAX_PREF_ENTRIES]; +struct scan_entry *smrt_pref_list[MAX_PREF_ENTRIES]; +struct prefix_list iid_list; +struct prefix_entry *tgt_iid_list[MAX_IID_ENTRIES]; +struct port_list tcp_port_list, udp_port_list, *port_list; /* These tables maintain the port ranges to scan */ -struct port_entry *tcp_prt_list[MAX_PORT_ENTRIES]; -struct port_entry *udp_prt_list[MAX_PORT_ENTRIES]; +struct port_entry *tcp_prt_list[MAX_PORT_ENTRIES]; +struct port_entry *udp_prt_list[MAX_PORT_ENTRIES]; /* These two tables maintain the port -> service name mappings */ struct port_table_entry tcp_port_table[MAX_PORT_RANGE]; struct port_table_entry udp_port_table[MAX_PORT_RANGE]; /* These arrays maintain the port scan results for a single node */ -unsigned int *port_results, tcp_results[MAX_PORT_RANGE], udp_results[MAX_PORT_RANGE]; +unsigned int *port_results, tcp_results[MAX_PORT_RANGE], udp_results[MAX_PORT_RANGE]; /* Load top ports */ -unsigned char loadalltopports_f=FALSE, loadtcptopports_f=FALSE, loadudptopports_f=FALSE; -unsigned int nalltopports, ntcptopports, nudptopports; -uint8_t cprotocol; - -uint16_t portscanl, portscanh, portscanp, portscantemp; -unsigned char dst_f=FALSE, tgt_ipv4mapped32_f=FALSE, tgt_ipv4mapped64_f=FALSE, tgt_lowbyte_f=FALSE, tgt_oui_f=FALSE; -unsigned char tgt_vendor_f=FALSE, tgt_vm_f=FALSE, tgt_bruteforce_f=FALSE, tgt_range_f=FALSE, tgt_portembedded_f=FALSE; -unsigned char tgt_knowniids_f=FALSE, tgt_knowniidsfile_f=FALSE, knownprefixes_f=FALSE; -unsigned char vm_vbox_f=FALSE, vm_vmware_f=FALSE, vm_vmware_esx_f=FALSE, vm_vmware_vsphere_f=FALSE, vm_vmwarem_f=FALSE, v4hostaddr_f=FALSE; -unsigned char v4hostprefix_f=FALSE, sort_ouis_f=FALSE, rnd_probes_f=FALSE, inc_f=FALSE, end_f=FALSE, endpscan_f=FALSE; -unsigned char donesending_f=FALSE, nomoreaddr_f=FALSE; -unsigned char onlink_f=FALSE, pps_f=FALSE, bps_f=FALSE, tcpflags_f=FALSE, rhbytes_f=FALSE, srcport_f=FALSE, dstport_f=FALSE, probetype; -unsigned char loop_f=FALSE, sleep_f=FALSE, smart_f=FALSE, portscan_f=FALSE, droppacket_f=FALSE, pscantype; -uint16_t srcport, dstport; -uint8_t tcpflags=0; -unsigned long pktinterval, rate; -unsigned int packetsize, rhbytes; -struct prefix4_entry v4host; -struct prefix_entry prefix; -struct ether_addr oui; -char *charstart, *charend, *lastcolon; -char rangestart[MAX_RANGE_STR_LEN+1], rangeend[MAX_RANGE_STR_LEN+1]; -char fname[MAX_FILENAME_SIZE], fname_f=FALSE, configfile[MAX_FILENAME_SIZE], knowniidsfile[MAX_FILENAME_SIZE]; -char portsfname[MAX_FILENAME_SIZE], portsfname_f=FALSE, topportsfname[MAX_FILENAME_SIZE], topportsfname_f=FALSE; -char knownprefixesfile[MAX_FILENAME_SIZE]; -FILE *knowniids_fp, *knownprefixes_fp; -char *oui_end=":00:00:00"; -char oui_ascii[ETHER_ADDR_PLEN]; -char vendor[MAX_IEEE_OUIS_LINE_SIZE]; -unsigned int nsleep; -int sel; -fd_set sset, rset, wset, eset; -struct timeval curtime, pcurtime, lastprobe; -struct tm pcurtimetm; -uint16_t service_ports_hex[]={0x21, 0x22, 0x23, 0x25, 0x49, 0x53, 0x80, 0x110, 0x123, 0x179, 0x220, 0x389, \ - 0x443, 0x547, 0x993, 0x995, 0x1194, 0x3306, 0x5060, 0x5061, 0x5432, 0x6446, 0x8080}; -uint16_t service_ports_dec[]={21, 22, 23, 25, 49, 53, 80, 110, 123, 179, 220, 389, \ - 443, 547, 993, 995, 1194, 3306, 5060, 5061, 5432, 6446, 8080}; - +unsigned char loadalltopports_f = FALSE, loadtcptopports_f = FALSE, loadudptopports_f = FALSE; +unsigned int nalltopports, ntcptopports, nudptopports; +uint8_t cprotocol; + +uint16_t portscanl, portscanh, portscanp, portscantemp; +unsigned char dst_f = FALSE, tgt_ipv4mapped32_f = FALSE, tgt_ipv4mapped64_f = FALSE, tgt_lowbyte_f = FALSE, + tgt_oui_f = FALSE; +unsigned char tgt_vendor_f = FALSE, tgt_vm_f = FALSE, tgt_bruteforce_f = FALSE, tgt_range_f = FALSE, + tgt_portembedded_f = FALSE; +unsigned char tgt_knowniids_f = FALSE, tgt_knowniidsfile_f = FALSE, knownprefixes_f = FALSE; +unsigned char vm_vbox_f = FALSE, vm_vmware_f = FALSE, vm_vmware_esx_f = FALSE, vm_vmware_vsphere_f = FALSE, + vm_vmwarem_f = FALSE, v4hostaddr_f = FALSE; +unsigned char v4hostprefix_f = FALSE, sort_ouis_f = FALSE, rnd_probes_f = FALSE, inc_f = FALSE, end_f = FALSE, + endpscan_f = FALSE; +unsigned char donesending_f = FALSE, nomoreaddr_f = FALSE; +unsigned char onlink_f = FALSE, pps_f = FALSE, bps_f = FALSE, tcpflags_f = FALSE, rhbytes_f = FALSE, srcport_f = FALSE, + dstport_f = FALSE, probetype; +unsigned char loop_f = FALSE, sleep_f = FALSE, smart_f = FALSE, portscan_f = FALSE, droppacket_f = FALSE, pscantype; +uint16_t srcport, dstport; +uint8_t tcpflags = 0; +unsigned long pktinterval, rate; +unsigned int packetsize, rhbytes; +struct prefix4_entry v4host; +struct prefix_entry prefix; +struct ether_addr oui; +char *charstart, *charend, *lastcolon; +char rangestart[MAX_RANGE_STR_LEN + 1], rangeend[MAX_RANGE_STR_LEN + 1]; +char fname[MAX_FILENAME_SIZE], fname_f = FALSE, configfile[MAX_FILENAME_SIZE], knowniidsfile[MAX_FILENAME_SIZE]; +char portsfname[MAX_FILENAME_SIZE], portsfname_f = FALSE, topportsfname[MAX_FILENAME_SIZE], topportsfname_f = FALSE; +char knownprefixesfile[MAX_FILENAME_SIZE]; +FILE *knowniids_fp, *knownprefixes_fp; +char *oui_end = ":00:00:00"; +char oui_ascii[ETHER_ADDR_PLEN]; +char vendor[MAX_IEEE_OUIS_LINE_SIZE]; +unsigned int nsleep; +int sel; +fd_set sset, rset, wset, eset; +struct timeval curtime, pcurtime, lastprobe; +struct tm pcurtimetm; +uint16_t service_ports_hex[] = {0x21, 0x22, 0x23, 0x25, 0x49, 0x53, 0x80, 0x110, + 0x123, 0x179, 0x220, 0x389, 0x443, 0x547, 0x993, 0x995, + 0x1194, 0x3306, 0x5060, 0x5061, 0x5432, 0x6446, 0x8080}; +uint16_t service_ports_dec[] = {21, 22, 23, 25, 49, 53, 80, 110, 123, 179, 220, 389, + 443, 547, 993, 995, 1194, 3306, 5060, 5061, 5432, 6446, 8080}; /* IPv6 Address Resolution */ -static sigjmp_buf env; -static unsigned int canjump; - -int main(int argc, char **argv){ - extern char *optarg; - int r; - struct addrinfo hints, *res, *aiptr; - struct target_ipv6 target; - struct timeval timeout; - char date[DATE_STR_LEN], *endptr; - uint8_t ulhtype; - struct scan_entry dummy; - - static struct option longopts[] = { - {"interface", required_argument, 0, 'i'}, - {"src-addr", required_argument, 0, 's'}, - {"dst-addr", required_argument, 0, 'd'}, - {"dst-opt-hdr", required_argument, 0, 'u'}, - {"dst-opt-u-hdr", required_argument, 0, 'U'}, - {"hbh-opt-hdr", required_argument, 0, 'H'}, - {"frag-hdr", required_argument, 0, 'y'}, - {"link-src-addr", required_argument, 0, 'S'}, - {"link-dst-addr", required_argument, 0, 'D'}, - {"local-scan", no_argument, 0, 'L'}, - {"probe-type", required_argument, 0, 'p'}, - {"payload-size", required_argument, 0, 'Z'}, - {"src-port", required_argument, 0, 'o'}, - {"dst-port", required_argument, 0, 'a'}, - {"tcp-flags", required_argument, 0, 'X'}, - {"print-type", required_argument, 0, 'P'}, - {"port-scan", required_argument, 0, 'j'}, - {"tcp-scan-type", required_argument, 0, 'G'}, - {"print-unique", no_argument, 0, 'q'}, - {"print-link-addr", no_argument, 0, 'e'}, - {"print-timestamp", no_argument, 0, 't'}, - {"retrans", required_argument, 0, 'x'}, - {"timeout", required_argument, 0, 'O'}, - {"rand-src-addr", no_argument, 0, 'f'}, - {"rand-link-src-addr", no_argument, 0, 'F'}, - {"smart", no_argument, 0, 'A'}, - {"tgt-virtual-machines", required_argument, 0, 'V'}, - {"tgt-low-byte", no_argument, 0, 'b'}, - {"tgt-ipv4", required_argument, 0, 'B'}, - {"tgt-port", no_argument, 0, 'g'}, - {"tgt-ieee-oui", required_argument, 0, 'k'}, - {"tgt-vendor", required_argument, 0, 'K'}, - {"tgt-iids-file", required_argument, 0, 'w'}, - {"tgt-iid", required_argument, 0, 'W'}, - {"prefixes-file", required_argument, 0, 'm'}, - {"ipv4-host", required_argument, 0, 'Q'}, - {"sort-ouis", no_argument, 0, 'T'}, - {"random-probes", no_argument, 0, 'N'}, - {"inc-size", required_argument, 0, 'I'}, - {"rate-limit", required_argument, 0, 'r'}, - {"loop", no_argument, 0, 'l'}, - {"sleep", required_argument, 0, 'z'}, - {"config-file", required_argument, 0, 'c'}, - {"verbose", no_argument, 0, 'v'}, - {"help", no_argument, 0, 'h'}, - {0, 0, 0, 0 } - }; - - const char shortopts[]= "i:s:d:u:U:H:y:S:D:Lp:Z:o:a:X:P:j:G:qetx:O:fFV:bB:gk:K:w:W:m:Q:TNI:r:lz:c:vh"; - - char option; - - if(argc<=1){ - usage(); - exit(EXIT_FAILURE); - } - - srandom(time(NULL)); - hoplimit=64+random()%180; - - init_iface_data(&idata); - - /* Initialize the scan_list structure (for remote scans) */ - scan_list.target=target_list; - scan_list.ntarget=0; - scan_list.ctarget=0; - scan_list.maxtarget= MAX_SCAN_ENTRIES; - - /* Initialize the prefix_list structure (for remote scans) */ - prefix_list.target= tgt_pref_list; - prefix_list.ntarget=0; - prefix_list.ctarget=0; - prefix_list.maxtarget= MAX_PREF_ENTRIES; - - /* Initialize the smart_list structure (for remote scans) */ - smart_list.target= smrt_pref_list; - smart_list.ntarget=0; - smart_list.ctarget=0; - smart_list.maxtarget= MAX_PREF_ENTRIES; - - /* Initialize the TCP port struture (for port scans) */ - tcp_port_list.port= tcp_prt_list; - tcp_port_list.nport=0; - tcp_port_list.cport=0; - tcp_port_list.proto= IPPROTO_TCP; - tcp_port_list.maxport= MAX_PORT_ENTRIES; - - /* Initialize the UDP port struture (for port scans) */ - udp_port_list.port= udp_prt_list; - udp_port_list.nport=0; - udp_port_list.cport=0; - udp_port_list.proto= IPPROTO_UDP; - udp_port_list.maxport= MAX_PORT_ENTRIES; - - /* Initialize the iid_list structure (for remote scans/tracking) */ - iid_list.prefix= tgt_iid_list; - iid_list.nprefix=0; - iid_list.maxprefix= MAX_IID_ENTRIES; - - while((r=getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { - option= r; - - switch(option) { - case 'i': /* Interface */ - strncpy(idata.iface, optarg, IFACE_LENGTH); - idata.iface[IFACE_LENGTH-1]=0; - idata.ifindex= if_nametoindex(idata.iface); - idata.iface_f=TRUE; - break; - - case 's': /* IPv6 Source Address */ - if((charptr = strtok_r(optarg, "/", &lasts)) == NULL){ - puts("Error in Source Address"); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, charptr, &idata.srcaddr) <= 0){ - puts("inet_pton(): Source Address not valid"); - exit(EXIT_FAILURE); - } - - idata.srcaddr_f=TRUE; - - if((charptr = strtok_r(NULL, " ", &lasts)) != NULL){ - idata.srcpreflen = atoi(charptr); - - if(idata.srcpreflen>128){ - puts("Prefix length error in IPv6 Source Address"); - exit(EXIT_FAILURE); - } - - sanitize_ipv6_prefix(&(idata.srcaddr), idata.srcpreflen); - idata.srcprefix_f=TRUE; - } - - break; - - case 'd': /* IPv6 Destination Address/Prefix */ - if(!address_contains_colons(optarg)){ - /* The '-d' option contains a domain name */ - if((charptr = strtok_r(optarg, "/", &lasts)) == NULL){ - puts("Error in Destination Address"); - exit(EXIT_FAILURE); - } - - strncpy(target.name, charptr, NI_MAXHOST); - target.name[NI_MAXHOST-1]=0; - - if((charptr = strtok_r(NULL, " ", &lasts)) != NULL){ - prefix.len = atoi(charptr); - - if(prefix.len > 128){ - puts("Prefix length error in IPv6 Destination Address"); - exit(EXIT_FAILURE); - } - } - else{ - prefix.len= 128; - } - - memset(&hints, 0, sizeof(hints)); - hints.ai_family= AF_INET6; - hints.ai_canonname = NULL; - hints.ai_addr = NULL; - hints.ai_next = NULL; - hints.ai_socktype= SOCK_DGRAM; - - if( (target.res = getaddrinfo(target.name, NULL, &hints, &res)) != 0){ - printf("Unknown Destination '%s': %s\n", target.name, gai_strerror(target.res)); - exit(EXIT_FAILURE); - } - - for(aiptr=res; aiptr != NULL; aiptr=aiptr->ai_next){ - if(aiptr->ai_family != AF_INET6) - continue; - - if(aiptr->ai_addrlen != sizeof(struct sockaddr_in6)) - continue; - - if(aiptr->ai_addr == NULL) - continue; - - prefix.ip6= ( (struct sockaddr_in6 *)aiptr->ai_addr)->sin6_addr; - - /* - If the prefix length is 64 bits (either implicitly or explicitly), we perform a smart scan - */ - - if(smart_f || (prefix.len == 64 && !is_iid_null(&(prefix.ip6), 64))){ - if(smart_list.ntarget <= smart_list.maxtarget){ - if( (smart_list.target[smart_list.ntarget] = malloc(sizeof(struct scan_entry))) == NULL){ - if(idata.verbose_f) - puts("scan6: Not enough memory"); - - exit(EXIT_FAILURE); - } - - prefix_to_scan(&prefix, smart_list.target[smart_list.ntarget]); - - if(IN6_IS_ADDR_MULTICAST(&(smart_list.target[smart_list.ntarget]->start.in6_addr))){ - if(idata.verbose_f) - puts("scan6: Remote scan cannot target a multicast address"); - - exit(EXIT_FAILURE); - } - - if(IN6_IS_ADDR_MULTICAST(&(smart_list.target[smart_list.ntarget]->end.in6_addr))){ - if(idata.verbose_f) - puts("scan6: Remote scan cannot target a multicast address"); - - exit(EXIT_FAILURE); - } - - idata.dstaddr= smart_list.target[smart_list.ntarget]->start.in6_addr; - smart_list.ntarget++; - } - else{ - /* - If the number of "targets" has already been exceeded, it doesn't make sense to continue further, - since there wouldn't be space for any specific target types - */ - if(idata.verbose_f) - puts("Too many targets!"); - - exit(EXIT_FAILURE); - } - - } - else{ - sanitize_ipv6_prefix(&(prefix.ip6), prefix.len); - - if(prefix_list.ntarget <= prefix_list.maxtarget){ - if( (prefix_list.target[prefix_list.ntarget] = malloc(sizeof(struct scan_entry))) == NULL){ - if(idata.verbose_f) - puts("scan6: Not enough memory"); - - exit(EXIT_FAILURE); - } - - prefix_to_scan(&prefix, prefix_list.target[prefix_list.ntarget]); - - if(IN6_IS_ADDR_MULTICAST(&(prefix_list.target[prefix_list.ntarget]->start.in6_addr))){ - if(idata.verbose_f) - puts("scan6: Remote scan cannot target a multicast address"); - - exit(EXIT_FAILURE); - } - - if(IN6_IS_ADDR_MULTICAST(&(prefix_list.target[prefix_list.ntarget]->end.in6_addr))){ - if(idata.verbose_f) - puts("scan6: Remote scan cannot target a multicast address"); - - exit(EXIT_FAILURE); - } - - idata.dstaddr= prefix_list.target[prefix_list.ntarget]->start.in6_addr; - prefix_list.ntarget++; - } - else{ - /* - If the number of "targets" has already been exceeded, it doesn't make sense to continue further, - since there wouldn't be space for any specific target types - */ - if(idata.verbose_f) - puts("Too many targets!"); - - exit(EXIT_FAILURE); - } - } - } - - freeaddrinfo(res); - } - else if( (ranges= address_contains_ranges(optarg)) == 1){ - /* - When an address range is specified, such address range is scanned, but the correspnding prefix is also - employed for generating additional addresses to be scanned (EUI-64 based, etc.) - */ - charptr= optarg; - charstart= rangestart; - charend= rangeend; - lastcolon= charend; - - while(*charptr && (optarg - charptr) <= MAX_RANGE_STR_LEN){ - if(*charptr != '-'){ - /* If we do not find a dash, just copy this 16-bit word to both the range start and the range end */ - *charstart= *charptr; - *charend= *charptr; - charstart++; - charend++; - - /* - Record the address of the byte following the colon (in the range end), so that we know what to - "overwrite when we find a "range - */ - if(*charptr==':') - lastcolon= charend; - - charptr++; - } - else{ - /* If we found a dash, we must "overwrite" the range end with what follows the dash */ - charend= lastcolon; - charptr++; - - while(*charptr && (optarg - charptr) <= MAX_RANGE_STR_LEN && *charptr !=':' && *charptr !='-'){ - *charend= *charptr; - charend++; - charptr++; - } - } - } - - /* Zero-terminate the strings that we have generated from the option arguments */ - *charstart=0; - *charend=0; - tgt_range_f=TRUE; - - if(scan_list.ntarget <= scan_list.maxtarget){ - if ( inet_pton(AF_INET6, rangestart, &(dummy.start.in6_addr)) <= 0){ - if(idata.verbose_f>1) - puts("inet_pton(): Error converting IPv6 address from presentation to network format"); - - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, rangeend, &(dummy.end.in6_addr)) <= 0){ - if(idata.verbose_f>1) - puts("inet_pton(): Error converting IPv6 address from presentation to network format"); - - exit(EXIT_FAILURE); - } - - dummy.cur.in6_addr= dummy.start.in6_addr; - - /* Check whether the start address is smaller than the end address */ - for(i=0;i<7; i++) - if( ntohs(dummy.start.s6addr16[i]) > ntohs(dummy.end.s6addr16[i])){ - if(idata.verbose_f) - puts("Error in Destination Address range: Start address larger than end address!"); - - exit(EXIT_FAILURE); - } - - if(IN6_IS_ADDR_MULTICAST(&(dummy.start.in6_addr))){ - if(idata.verbose_f) - puts("scan6: Remote scan cannot target a multicast address"); - - exit(EXIT_FAILURE); - } - - if(IN6_IS_ADDR_MULTICAST(&(dummy.end.in6_addr))){ - if(idata.verbose_f) - puts("scan6: Remote scan cannot target a multicast address"); - - exit(EXIT_FAILURE); - } - - idata.dstaddr= dummy.start.in6_addr; - if(add_to_scan_list(&scan_list, &dummy) == FALSE){ - if(idata.verbose_f) - puts("Couldn't add entry to scan list"); - - exit(EXIT_FAILURE); - } - } - else{ - /* - If the number of "targets" has already been exceeded, it doesn't make sense to continue further, - since there wouldn't be space for any specific target types - */ - if(idata.verbose_f) - puts("Too many targets!"); - - exit(EXIT_FAILURE); - } - - if(prefix_list.ntarget <= prefix_list.maxtarget){ - if( (prefix_list.target[prefix_list.ntarget] = malloc(sizeof(struct scan_entry))) == NULL){ - if(idata.verbose_f) - puts("scan6: Not enough memory"); - - exit(EXIT_FAILURE); - } - - /* Copy the recently added target to our prefix list */ - *prefix_list.target[prefix_list.ntarget]= dummy; - prefix_list.ntarget++; - } - else{ - /* - If the number of "targets" has already been exceeded, it doesn't make sense to continue further, - since there wouldn't be space for any specific target types - */ - if(idata.verbose_f) - puts("Too many targets!"); - - exit(EXIT_FAILURE); - } - } - else if(ranges == 0){ - /* The '-d' option contains a prefix with the slash notation */ - if((charptr = strtok_r(optarg, "/", &lasts)) == NULL){ - puts("Error in Destination Address"); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, charptr, &(prefix.ip6)) <= 0){ - puts("inet_pton(): Destination Address not valid"); - exit(EXIT_FAILURE); - } - - if((charptr = strtok_r(NULL, " ", &lasts)) != NULL){ - prefix.len = atoi(charptr); - - if(prefix.len>128){ - puts("Prefix length error in IPv6 Destination Address"); - exit(EXIT_FAILURE); - } - - sanitize_ipv6_prefix(&(prefix.ip6), prefix.len); - } - else{ - prefix.len= 128; - } - - /* If the Prefix length is /128 (explicitly set, or by omission), we do a smart scan */ - if(smart_f || (prefix.len == 64 && !is_iid_null(&(prefix.ip6), 64))){ - if(smart_list.ntarget <= smart_list.maxtarget){ - if( (smart_list.target[smart_list.ntarget] = malloc(sizeof(struct scan_entry))) == NULL){ - if(idata.verbose_f) - puts("scan6: Not enough memory"); - - exit(EXIT_FAILURE); - } - - prefix_to_scan(&prefix, smart_list.target[smart_list.ntarget]); - - if(IN6_IS_ADDR_MULTICAST(&(smart_list.target[smart_list.ntarget]->start.in6_addr))){ - if(idata.verbose_f) - puts("scan6: Remote scan cannot target a multicast address"); - - exit(EXIT_FAILURE); - } - - if(IN6_IS_ADDR_MULTICAST(&(smart_list.target[smart_list.ntarget]->end.in6_addr))){ - if(idata.verbose_f) - puts("scan6: Remote scan cannot target a multicast address"); - - exit(EXIT_FAILURE); - } - - idata.dstaddr= smart_list.target[smart_list.ntarget]->start.in6_addr; - smart_list.ntarget++; - } - else{ - /* - If the number of "targets" has already been exceeded, it doesn't make sense to continue further, - since there wouldn't be space for any specific target types - */ - if(idata.verbose_f) - puts("Too many targets!"); - - exit(EXIT_FAILURE); - } - } - else{ - if(prefix_list.ntarget <= prefix_list.maxtarget){ - if( (prefix_list.target[prefix_list.ntarget] = malloc(sizeof(struct scan_entry))) == NULL){ - if(idata.verbose_f) - puts("scan6: Not enough memory"); - - exit(EXIT_FAILURE); - } - - prefix_to_scan(&prefix, prefix_list.target[prefix_list.ntarget]); - - if(IN6_IS_ADDR_MULTICAST(&(prefix_list.target[prefix_list.ntarget]->start.in6_addr))){ - if(idata.verbose_f) - puts("scan6: Remote scan cannot target a multicast address"); - - exit(EXIT_FAILURE); - } - - if(IN6_IS_ADDR_MULTICAST(&(prefix_list.target[prefix_list.ntarget]->end.in6_addr))){ - if(idata.verbose_f) - puts("scan6: Remote scan cannot target a multicast address"); - - exit(EXIT_FAILURE); - } - - prefix_list.ntarget++; - idata.dstaddr= prefix_list.target[0]->start.in6_addr; - } - else{ - /* - If the number of "targets" has already been exceeded, it doesn't make sense to continue further, - since there wouldn't be space for any specific target types - */ - if(idata.verbose_f) - puts("Too many targets!"); - - exit(EXIT_FAILURE); - } - } - } - - idata.dstaddr_f= TRUE; - dst_f=TRUE; - break; - - case 'u': /* Destinations Options Header */ - if(ndstopthdr >= MAX_DST_OPT_HDR){ - puts("Too many Destination Options Headers"); - exit(EXIT_FAILURE); - } - - hdrlen= atoi(optarg); - - if(hdrlen < 8){ - puts("Bad length in Destination Options Header"); - exit(EXIT_FAILURE); - } - - hdrlen = ((hdrlen+7)/8) * 8; - dstopthdrlen[ndstopthdr]= hdrlen; - - if( (dstopthdr[ndstopthdr]= malloc(hdrlen)) == NULL){ - puts("Not enough memory for Destination Options Header"); - exit(EXIT_FAILURE); - } - - ptrhdr= dstopthdr[ndstopthdr] + 2; - ptrhdrend= dstopthdr[ndstopthdr] + hdrlen; - - while( ptrhdr < ptrhdrend){ - - if( (ptrhdrend-ptrhdr)>257) - pad= 257; - else - pad= ptrhdrend-ptrhdr; - - if(!insert_pad_opt(ptrhdr, ptrhdrend, pad)){ - puts("Destination Options Header Too Big"); - exit(EXIT_FAILURE); - } - - ptrhdr= ptrhdr + pad; - } - - *(dstopthdr[ndstopthdr]+1)= (hdrlen/8)-1; - ndstopthdr++; - dstopthdr_f=TRUE; - break; - - case 'U': /* Destination Options Header (Unfragmentable Part) */ - if(ndstoptuhdr >= MAX_DST_OPT_U_HDR){ - puts("Too many Destination Options Headers (Unfragmentable Part)"); - exit(EXIT_FAILURE); - } - - hdrlen= atoi(optarg); - - if(hdrlen < 8){ - puts("Bad length in Destination Options Header (Unfragmentable Part)"); - exit(EXIT_FAILURE); - } - - hdrlen = ((hdrlen+7)/8) * 8; - dstoptuhdrlen[ndstoptuhdr]= hdrlen; - - if( (dstoptuhdr[ndstoptuhdr]= malloc(hdrlen)) == NULL){ - puts("Not enough memory for Destination Options Header (Unfragmentable Part)"); - exit(EXIT_FAILURE); - } - - ptrhdr= dstoptuhdr[ndstoptuhdr]+2; - ptrhdrend= dstoptuhdr[ndstoptuhdr] + hdrlen; - - while( ptrhdr < ptrhdrend){ - - if( (ptrhdrend-ptrhdr)>257) - pad= 257; - else - pad= ptrhdrend-ptrhdr; - - if(!insert_pad_opt(ptrhdr, ptrhdrend, pad)){ - puts("Destination Options Header (Unfragmentable Part) Too Big"); - exit(EXIT_FAILURE); - } - - ptrhdr = ptrhdr + pad; - } - - *(dstoptuhdr[ndstoptuhdr]+1)= (hdrlen/8) - 1; - ndstoptuhdr++; - dstoptuhdr_f=TRUE; - break; - - case 'H': /* Hop-by-Hop Options Header */ - if(nhbhopthdr >= MAX_HBH_OPT_HDR){ - puts("Too many Hop-by-Hop Options Headers"); - exit(EXIT_FAILURE); - } - - hdrlen= atoi(optarg); - - if(hdrlen <= 8){ - puts("Bad length in Hop-by-Hop Options Header"); - exit(EXIT_FAILURE); - } - - hdrlen = ((hdrlen+7)/8) * 8; - hbhopthdrlen[nhbhopthdr]= hdrlen; - - if( (hbhopthdr[nhbhopthdr]= malloc(hdrlen)) == NULL){ - puts("Not enough memory for Hop-by-Hop Options Header"); - exit(EXIT_FAILURE); - } - - ptrhdr= hbhopthdr[nhbhopthdr] + 2; - ptrhdrend= hbhopthdr[nhbhopthdr] + hdrlen; - - - while( ptrhdr < ptrhdrend){ - - if( (ptrhdrend-ptrhdr)>257) - pad= 257; - else - pad= ptrhdrend-ptrhdr; - - if(!insert_pad_opt(ptrhdr, ptrhdrend, pad)){ - puts("Hop-by-Hop Options Header Too Big"); - exit(EXIT_FAILURE); - } - - ptrhdr = ptrhdr + pad; - } - - *(hbhopthdr[nhbhopthdr]+1)= (hdrlen/8) - 1; - nhbhopthdr++; - hbhopthdr_f=TRUE; - break; - - case 'y': /* Fragment header */ - nfrags= atoi(optarg); - if(nfrags < 8){ - puts("Error in Fragmentation option: Fragment Size must be at least 8 bytes"); - exit(EXIT_FAILURE); - } - - idata.fragh_f=TRUE; - - /* XXX: To be removed when fragmentation support is added */ - puts("Error: scan6 does not currently support fragmentation"); - exit(EXIT_FAILURE); - - break; - - case 'S': /* Source Ethernet address */ - if(ether_pton(optarg, &(idata.hsrcaddr), sizeof(idata.hsrcaddr)) == 0){ - puts("Error in Source link-layer address."); - exit(EXIT_FAILURE); - } - - idata.hsrcaddr_f=TRUE; - break; - - case 'D': /* Destination Ethernet address */ - if(ether_pton(optarg, &(idata.hdstaddr), sizeof(idata.hdstaddr)) == 0){ - puts("Error in Destination Ethernet address."); - exit(EXIT_FAILURE); - } - - idata.hdstaddr_f=TRUE; - break; - - case 'L': - scan_local_f=TRUE; - break; - - case 'p': /* Probe type */ - if(strncmp(optarg, "echo", strlen("echo")) == 0){ - probe_echo_f=TRUE; - probetype= PROBE_ICMP6_ECHO; - probe_f=TRUE; - } - else if(strncmp(optarg, "unrec", strlen("unrec")) == 0){ - probe_unrec_f=TRUE; - probetype= PROBE_UNREC_OPT; - probe_f=TRUE; - } - else if(strncmp(optarg, "all", strlen("all")) == 0){ - probe_echo_f=TRUE; - probe_unrec_f=TRUE; - - /* For reote scans, we use a single probe type */ - probetype= PROBE_ICMP6_ECHO; - probe_f=TRUE; - } - else if(strncmp(optarg, "tcp", strlen("tcp")) == 0){ - probetype= PROBE_TCP; - probe_f=TRUE; - } - else{ - puts("Error in '-p' option: Unknown probe type"); - exit(EXIT_FAILURE); - } - - break; - - case 'Z': /* Payload Size*/ - rhbytes= atoi(optarg); - rhbytes_f=TRUE; - break; - - case 'o': /* TCP/UDP Source Port */ - srcport= atoi(optarg); - srcport_f=TRUE; - break; - - case 'a': /* TCP/UDP Destination Port */ - dstport= atoi(optarg); - dstport_f=TRUE; - break; - - case 'X': - charptr = optarg; - while(*charptr){ - switch(*charptr){ - case 'F': - tcpflags= tcpflags | TH_FIN; - break; - - case 'S': - tcpflags= tcpflags | TH_SYN; - break; - - case 'R': - tcpflags= tcpflags | TH_RST; - break; - - case 'P': - tcpflags= tcpflags | TH_PUSH; - break; - - case 'A': - tcpflags= tcpflags | TH_ACK; - break; - - case 'U': - tcpflags= tcpflags | TH_URG; - break; - - case 'X': /* No TCP flags */ - break; - - default: - printf("Unknown TCP flag '%c'\n", *charptr); - exit(EXIT_FAILURE); - break; - } - - if(*charptr == 'X') - break; - - charptr++; - } - - tcpflags_f=TRUE; - break; - - case 'P': /* Print type */ - if(strncmp(optarg, "local", strlen("local")) == 0){ - print_local_f=TRUE; - print_f=TRUE; - } - else if(strncmp(optarg, "global", strlen("global")) == 0){ - print_global_f=TRUE; - print_f=TRUE; - } - else if(strncmp(optarg, "all", strlen("all")) == 0){ - print_local_f=TRUE; - print_global_f=TRUE; - print_f=TRUE; - } - else{ - puts("Error in '-P' option: Unknown address type"); - exit(EXIT_FAILURE); - } - - break; - - case 'q': - print_unique_f=TRUE; - break; - - case 'e': - print_type= PRINT_ETHER_ADDR; - break; - - case 't': - timestamps_f=TRUE; - break; - - case 'x': - idata.local_retrans=atoi(optarg); - break; - - case 'O': - idata.local_timeout=atoi(optarg); - break; - - case 'f': - rand_src_f=TRUE; - break; - - case 'F': - rand_link_src_f=TRUE; - break; - - case 'A': - smart_f=TRUE; - break; - - case 'j': - if((pref = strtok_r(optarg, ":", &lasts)) == NULL){ - printf("Error in prefix option number %u. \n", i); - exit(EXIT_FAILURE); - } - - if(strncmp(pref, "udp", 3) == 0 || strncmp(pref, "udp", 3) == 0){ - port_list= &udp_port_list; - cprotocol= IPPROTO_UDP; - } - else if(strncmp(pref, "tcp", 3) == 0 || strncmp(pref, "TCP", 3) == 0){ - port_list= &tcp_port_list; - cprotocol= IPPROTO_TCP; - } - else if(strncmp(pref, "all", 3) == 0 || strncmp(pref, "ALL", 3) == 0){ - cprotocol= IPPROTO_ALL; - } - else{ - puts("Error unknown protocol in 'port-scan' option"); - exit(EXIT_FAILURE); - } - - if(strncmp(lasts, "top", 3) == 0 || strncmp(lasts, "top", 3) == 0){ - if((charptr = strtok_r(NULL, ":", &lasts)) == NULL){ - printf("Error in prefix option number %u. \n", i); - exit(EXIT_FAILURE); - } - - if(cprotocol == IPPROTO_ALL && (loadtcptopports_f || loadudptopports_f)){ - puts("Cannot specify all ports and (TCP or UDP) top ports at the same time"); - exit(EXIT_FAILURE); - } - else if(cprotocol == IPPROTO_TCP && loadtcptopports_f){ - puts("Cannot specify TCP top ports more than once"); - exit(EXIT_FAILURE); - } - else if(cprotocol == IPPROTO_UDP && loadudptopports_f){ - puts("Cannot specify TCP top ports more than once"); - exit(EXIT_FAILURE); - } - - if( strncmp(lasts, "all", 3) == 0 || strncmp(lasts, "ALL", 3) == 0){ - nalltopports= (MAX_PORT_RANGE+1)*2; /* This sets the cap for the number of entries to load */ - } - else{ - nalltopports= atoi(lasts); - } - - if(nalltopports > 0){ - if(cprotocol == IPPROTO_TCP){ - loadtcptopports_f= TRUE; - ntcptopports= nalltopports; - } - else if(cprotocol == IPPROTO_UDP){ - loadudptopports_f= TRUE; - nudptopports= nalltopports; - } - else if(cprotocol == IPPROTO_ALL){ - loadalltopports_f= TRUE; - } - else{ - /* Should never happen */ - puts("Bad protocol"); - exit(EXIT_FAILURE); - } - } - - portscan_f=TRUE; - break; - } - else if(address_contains_ranges(lasts)){ - if((pref = strtok_r(NULL, "-", &lasts)) == NULL){ - puts("Error in 'port-scan' option"); - exit(EXIT_FAILURE); - } - - portscanl=strtoul(pref, &endptr, 10); - - if(pref == endptr && portscanl == 0){ - puts("Error in port range"); - exit(EXIT_FAILURE); - } - - portscanh=strtoul(lasts, &endptr, 10); - - if(lasts == endptr && portscanh == 0){ - puts("Error in port range"); - exit(EXIT_FAILURE); - } - } - else{ - portscanl=strtoul(lasts, &endptr, 10); - - if(lasts == endptr && portscanl == 0){ - portscanl= DEFAULT_MIN_PORT; - portscanh= DEFAULT_MAX_PORT; - } - else{ - portscanh= portscanl; - } - } - - if(portscanl > portscanh){ - portscantemp= portscanl; - portscanl= portscanh; - portscanh= portscantemp; - } - - if(port_list->nport < port_list->maxport){ - if( (port_list->port[port_list->nport] = malloc(sizeof(struct port_entry))) == NULL){ - if(idata.verbose_f) - puts("scan6: Not enough memory"); - - exit(EXIT_FAILURE); - } - - port_list->port[port_list->nport]->start= portscanl; - port_list->port[port_list->nport]->end= portscanh; - (port_list->port[port_list->nport])->cur= (port_list->port[port_list->nport])->start; - port_list->nport++; - } - else{ - /* - If the number of "prots" has already been exceeded, it doesn't make sense to continue further, - since there wouldn't be space for any specific target types - */ - if(idata.verbose_f) - puts("Too many port ranges!"); - - exit(EXIT_FAILURE); - } - - portscan_f=TRUE; - break; - - case 'G': - if(strncmp(optarg, "syn", strlen("syn")) == 0 || strncmp(optarg, "SYN", strlen("SYN")) == 0){ - tcpflags= TH_SYN; - tcpflags_f=TRUE; - } - else if(strncmp(optarg, "fin", strlen("fin")) == 0 || strncmp(optarg, "FIN", strlen("FIN")) == 0){ - tcpflags= TH_FIN; - tcpflags_f=TRUE; - } - else if(strncmp(optarg, "null", strlen("null")) == 0 || strncmp(optarg, "NULL", strlen("NULL")) == 0){ - tcpflags= 0; - tcpflags_f=TRUE; - } - else if(strncmp(optarg, "xmas", strlen("xmas")) == 0 || strncmp(optarg, "XMAS", strlen("XMAS")) == 0){ - tcpflags= TH_FIN | TH_PUSH | TH_URG; - tcpflags_f=TRUE; - } - else if(strncmp(optarg, "ack", strlen("ack")) == 0 || strncmp(optarg, "ACK", strlen("ACK")) == 0){ - tcpflags= TH_ACK; - tcpflags_f=TRUE; - } - - break; - - case 'V': - if(strncmp(optarg, "vbox", strlen("vbox")) == 0 || strncmp(optarg, "virtualbox", strlen("virtualbox")) == 0){ - tgt_vm_f=TRUE; - vm_vbox_f=TRUE; - } - else if(strncmp(optarg, "vmware-esx", strlen("vmware-esx")) == 0){ - tgt_vm_f=TRUE; - vm_vmware_esx_f=TRUE; - } - else if(strncmp(optarg, "vmware-vsphere", strlen("vmware-vsphere")) == 0){ - tgt_vm_f=TRUE; - vm_vmware_vsphere_f=TRUE; - } - else if(strncmp(optarg, "vmwarem", strlen("vmwarem")) == 0 || strncmp(optarg, "vmware-manual", strlen("vmware-manual")) == 0){ - tgt_vm_f=TRUE; - vm_vmwarem_f=TRUE; - } - else if(strncmp(optarg, "vmware", strlen("vmware")) == 0){ - tgt_vm_f=TRUE; - vm_vmware_esx_f= TRUE; - vm_vmware_vsphere_f= TRUE; - vm_vmwarem_f= TRUE; - } - else if(strncmp(optarg, "all", strlen("all")) == 0){ - tgt_vm_f=TRUE; - vm_vbox_f=TRUE; - vm_vmware_esx_f= TRUE; - vm_vmware_vsphere_f= TRUE; - vm_vmwarem_f= TRUE; - } - else{ - puts("Error in '-V' option: Unknown Virtualization Technology"); - exit(EXIT_FAILURE); - } - - break; - - case 'b': - tgt_lowbyte_f=TRUE; - break; - - case 'B': - if(strncmp("ipv4-all", optarg, MAX_LINE_SIZE) == 0 || strncmp("all", optarg, MAX_LINE_SIZE) == 0){ - tgt_ipv4mapped32_f=TRUE; - tgt_ipv4mapped64_f=TRUE; - } - else if(strncmp("ipv4-32", optarg, MAX_LINE_SIZE) == 0 || strncmp("32", optarg, MAX_LINE_SIZE) == 0){ - tgt_ipv4mapped32_f=TRUE; - } - else if(strncmp("ipv4-64", optarg, MAX_LINE_SIZE) == 0 || strncmp("64", optarg, MAX_LINE_SIZE) == 0){ - tgt_ipv4mapped64_f=TRUE; - } - else{ - puts("Unknown encoding of IPv4-embedded IPv6 addresses in '-B' option"); - exit(EXIT_FAILURE); - } - - break; - - case 'g': - tgt_portembedded_f=TRUE; - break; - - case 'k': /* Target OUI */ - /* - In case the user entered an OUI as OO:UU:II:00:00:00, just copy the first 8 bytes of input - (the OUI part) - */ - strncpy(oui_ascii, optarg, 8); - oui_ascii[8]= 0; - strncat(oui_ascii, oui_end, ETHER_ADDR_PLEN-Strnlen(oui_ascii, sizeof(oui_ascii))-1); - - if(ether_pton(oui_ascii, &oui, sizeof(oui)) == 0){ - puts("Error in vendor IEEE OUI"); - exit(EXIT_FAILURE); - } - - tgt_oui_f=TRUE; - break; - - case 'K': /* Target vendor */ - /* - In case the user entered an OUI as OO:UU:II:00:00:00, just copy the first 8 bytes of input - (the OUI part) - */ - - strncpy(vendor, optarg, MAX_IEEE_OUIS_LINE_SIZE-1); - vendor[MAX_IEEE_OUIS_LINE_SIZE-1]= 0; - - tgt_vendor_f=TRUE; - break; - - case 'w': /* Target known Interface Identifiers (IIDs) */ - strncpy(knowniidsfile, optarg, MAX_FILENAME_SIZE-1); - knowniidsfile[MAX_FILENAME_SIZE-1]=0; - - tgt_knowniidsfile_f=TRUE; - break; - - - case 'W': /* Target Interface Identifier (IIDs) */ - if(iid_list.nprefix >= iid_list.maxprefix){ - puts("Too many INterface Identifiers"); - exit(EXIT_FAILURE); - } - - if( (iid_list.prefix[iid_list.nprefix] = malloc(sizeof(struct prefix_entry))) == NULL){ - puts("Not enough memory while storing Interface ID"); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, optarg, &((iid_list.prefix[iid_list.nprefix])->ip6)) <= 0){ - puts("inet_pton(): Source Address not valid"); - exit(EXIT_FAILURE); - } - - iid_list.prefix[iid_list.nprefix]->len=128; - iid_list.nprefix++; - - tgt_knowniids_f=TRUE; - break; - - case 'm': /* Known prefixes file */ - strncpy(knownprefixesfile, optarg, MAX_FILENAME_SIZE-1); - knownprefixesfile[MAX_FILENAME_SIZE-1]=0; - - knownprefixes_f=TRUE; - break; - - case 'Q': - if((charptr = strtok_r(optarg, "/", &lasts)) == NULL){ - puts("Error in Source Address"); - exit(EXIT_FAILURE); - } - - if(inet_pton(AF_INET, charptr, &(v4host.ip)) != 1){ - puts("Error in Host IPv4 Address"); - exit(EXIT_FAILURE); - } - - v4hostaddr_f=TRUE; - - if((charptr = strtok_r(NULL, " ", &lasts)) != NULL){ - v4host.len = atoi(charptr); - - if(v4host.len>32){ - puts("Prefix length error in Host IPv4 address"); - exit(EXIT_FAILURE); - } - - sanitize_ipv4_prefix(&v4host); - v4hostprefix_f=TRUE; - } - else{ - v4host.len=32; - } - - break; - - case 'T': - sort_ouis_f=TRUE; - break; - - case 'N': - rnd_probes_f=TRUE; - break; - - case 'I': - inc = atoi(optarg); - inc_f=TRUE; - break; - - case 'r': - if( Strnlen(optarg, LINE_BUFFER_SIZE-1) >= (LINE_BUFFER_SIZE-1)){ - puts("scan6: -r option is too long"); - exit(EXIT_FAILURE); - } - - sscanf(optarg, "%lu%s", &rate, line); - - line[LINE_BUFFER_SIZE-1]=0; - - if(strncmp(line, "pps", 3) == 0) - pps_f=TRUE; - else if(strncmp(line, "bps", 3) == 0) - bps_f=TRUE; - else{ - puts("scan6: Unknown unit of for the rate limit ('-r' option). Unit should be 'bps' or 'pps'"); - exit(EXIT_FAILURE); - } - - break; - - case 'l': /* "Loop mode */ - loop_f=TRUE; - break; - - case 'z': /* Sleep option */ - nsleep=atoi(optarg); - if(nsleep==0){ - puts("Invalid number of seconds in '-z' option"); - exit(EXIT_FAILURE); - } - - sleep_f=TRUE; - break; - - case 'v': /* Be verbose */ - idata.verbose_f++; - break; - - case 'h': /* Help */ - print_help(); - exit(EXIT_FAILURE); - break; - - case 'c': /* Configuration file */ - strncpy(configfile, optarg, MAX_FILENAME_SIZE-1); - configfile[MAX_FILENAME_SIZE-1]=0; - configfile_f=TRUE; - break; - - default: - usage(); - exit(EXIT_FAILURE); - break; - - } /* switch */ - } /* while(getopt) */ - - /* - XXX: This is rather ugly, but some local functions need to check for verbosity, and it was not warranted - to pass &idata as an argument - */ - verbose_f= idata.verbose_f; - - if(geteuid()){ - puts("scan6 needs superuser privileges to run"); - exit(EXIT_FAILURE); - } - - if(scan_local_f && !idata.iface_f){ - puts("Must specify the network interface with the -i option when a local scan is selected"); - exit(EXIT_FAILURE); - } - - /* Must open the "Known IIDs" file now, since it might be non-readable for the unprivileged user */ - if(tgt_knowniidsfile_f){ - if( (knowniids_fp=fopen(knowniidsfile, "r")) == NULL){ - perror("Error opening known IIDs file"); - exit(EXIT_FAILURE); - } - } - - /* Must open the "Known IIDs" file now, since it might be non-readable for the unprivileged user */ - if(knownprefixes_f){ - if( (knownprefixes_fp=fopen(knownprefixesfile, "r")) == NULL){ - perror("Error opening known prefixes file"); - exit(EXIT_FAILURE); - } - - dst_f=TRUE; - } - - if(!dst_f && !scan_local_f){ - if(idata.verbose_f) - puts("Must specify either a destination prefix ('-d'), or a local scan ('-L')"); - - exit(EXIT_FAILURE); - } - - if(!scan_local_f){ - if(load_dst_and_pcap(&idata, LOAD_SRC_NXT_HOP) == FAILURE){ - puts("Error while learning Source Address and Next Hop"); - exit(EXIT_FAILURE); - } - } - else{ - if(load_dst_and_pcap(&idata, LOAD_PCAP_ONLY) == FAILURE){ - puts("Error while learning Source Address and Next Hop"); - exit(EXIT_FAILURE); - } - } - - release_privileges(); - - /* This loads prefixes, but not scan entries */ - if(knownprefixes_f){ - if(!load_knownprefix_entries(&scan_list, &prefix_list, knownprefixes_fp)){ - puts("Couldn't load known IPv6 prefixes"); - exit(EXIT_FAILURE); - } - } - - if(!inc_f) - scan_list.inc=1; - - if(pps_f && bps_f){ - puts("Cannot specify a rate-limit in bps and pps at the same time"); - exit(EXIT_FAILURE); - } - - if(pps_f){ - if(rate < 1) - rate=1; - - pktinterval= 1000000/rate; - } - - if(bps_f){ - switch(probetype){ - case PROBE_UNREC_OPT: - packetsize= MIN_IPV6_HLEN + sizeof(struct icmp6_hdr) + ICMPV6_ECHO_PAYLOAD_SIZE; - break; - - case PROBE_ICMP6_ECHO: - packetsize= MIN_IPV6_HLEN + MIN_DST_OPT_HDR_SIZE + sizeof(struct icmp6_hdr) + ICMPV6_ECHO_PAYLOAD_SIZE; - break; - - case PROBE_TCP: - packetsize= MIN_IPV6_HLEN + sizeof(struct tcp_hdr) + rhbytes; - break; - } - - if(rate == 0 || ((packetsize * 8)/rate) <= 0) - pktinterval= 1000000; - else - pktinterval= ((packetsize * 8)/rate) * 1000000; - } - - /* We Default to 1000 pps */ - if(!pps_f && !bps_f) - pktinterval= 1000; - - - if(!configfile_f){ - strncpy(configfile, "/etc/ipv6toolkit.conf", MAX_FILENAME_SIZE); - } - - if(tgt_vendor_f || portscan_f){ - if(!process_config_file(configfile)){ - puts("Error while processing configuration file"); - exit(EXIT_FAILURE); - } - } - - - - if(portscan_f){ - if(loadalltopports_f){ - if(load_top_ports_entries(&tcp_port_list, &udp_port_list, IPPROTO_ALL, nalltopports) == FALSE){ - puts("Problem loading TCP top ports"); - exit(EXIT_FAILURE); - } - } - else{ - if(loadtcptopports_f){ - if(load_top_ports_entries(&tcp_port_list, &udp_port_list, IPPROTO_TCP, ntcptopports) == FALSE){ - puts("Problem loading TCP top ports"); - exit(EXIT_FAILURE); - } - } - if(loadudptopports_f){ - if(load_top_ports_entries(&tcp_port_list, &udp_port_list, IPPROTO_UDP, nudptopports) == FALSE){ - puts("Problem loading UDP top ports"); - exit(EXIT_FAILURE); - } - } - } - - if(tcp_port_list.nport){ - /* Load service names */ - if(!load_port_table(tcp_port_table, "tcp", MAX_PORT_RANGE)){ - puts("Error while loading port number descriptions"); - exit(EXIT_FAILURE); - } - - /* Link service names to port_list structure */ - tcp_port_list.port_table= tcp_port_table; - - /* We currently support only SYN scans for TCP */ - tcpflags_f= TRUE; - tcpflags= TH_SYN; - } - - if(udp_port_list.nport){ - /* Load service names */ - if(!load_port_table(udp_port_table, "udp", MAX_PORT_RANGE)){ - puts("Error while loading port number descriptions"); - exit(EXIT_FAILURE); - } - - /* LInk service names to port_list structure */ - udp_port_list.port_table= udp_port_table; - } - } - - if(loop_f && !dst_f){ - puts("Loop mode '-l' set, but no targets ('-d') specified!"); - puts("Note: '-l' option changed since IPv6 toolkit v1.3.4!"); - } - - if(dst_f && !(tgt_ipv4mapped32_f || tgt_ipv4mapped64_f || tgt_lowbyte_f || tgt_oui_f || tgt_vendor_f || \ - tgt_vm_f || tgt_range_f || tgt_portembedded_f || tgt_knowniids_f || tgt_knowniidsfile_f)){ - - tgt_bruteforce_f=TRUE; - } - - if( (tgt_ipv4mapped32_f || tgt_ipv4mapped64_f) && !v4hostaddr_f){ - puts("Error: Must IPv4 host address/prefix (with '--ipv4-host') if '--tgt-ipv4-embedded' is set"); - exit(EXIT_FAILURE); - } - - if(scan_local_f && (idata.type != DLT_EN10MB || (idata.flags & IFACE_TUNNEL))){ - puts("Error cannot apply local scan on a loopback or tunnel interface"); - exit(EXIT_FAILURE); - } - - if(!print_f){ - print_local_f=TRUE; - print_global_f=TRUE; - } - - if(!probe_f){ - probe_unrec_f=TRUE; - probe_echo_f=TRUE; - - /* For remote scans we use a single probe type */ - probetype=PROBE_ICMP6_ECHO; - } - - /* - If a Source Address (and *not* a "source prefix") has been specified, we need to incorporate such address - in our iface_data structure. - */ - if(idata.srcaddr_f && !idata.srcprefix_f){ - if(IN6_IS_ADDR_LINKLOCAL(&(idata.srcaddr))){ - idata.ip6_local=idata.srcaddr; - idata.ip6_local_flag=TRUE; - } - else{ - if( (idata.ip6_global.prefix[idata.ip6_global.nprefix] = malloc(sizeof(struct prefix_entry))) \ - == NULL){ - if(idata.verbose_f){ - puts("Not enough memory while saving global address"); - } - exit(EXIT_FAILURE); - } - - (idata.ip6_global.prefix[idata.ip6_global.nprefix])->ip6=idata.srcaddr; - idata.ip6_global.nprefix++; - idata.ip6_global_flag=1; - } - } - - if((idata.ip6_local_flag && idata.ip6_global_flag) && !idata.srcaddr_f) - localaddr_f=TRUE; - - if(scan_local_f){ - host_local.nhosts=0; - host_local.maxhosts= MAX_IPV6_ENTRIES; - host_local.host= host_locals; - - if(probe_echo_f){ - if(multi_scan_local(idata.pfd, &idata, &(idata.ip6_local), PROBE_ICMP6_ECHO, ALL_NODES_MULTICAST_ADDR,\ - &host_local) == -1){ - if(idata.verbose_f) - puts("Error while learning link-local addresses with ICMPv6 Echo Requests"); - - exit(EXIT_FAILURE); - } - } - - - if(probe_unrec_f){ - if(multi_scan_local(idata.pfd, &idata, &(idata.ip6_local), PROBE_UNREC_OPT, ALL_NODES_MULTICAST_ADDR,\ - &host_local) == -1){ - if(idata.verbose_f) - puts("Error while learning link-local addresses with Unrecognized options"); - - exit(EXIT_FAILURE); - } - } - - if(print_local_f){ - if(idata.verbose_f) - puts("Link-local addresses:"); - - if(print_unique_f){ - if(print_unique_host_entries(&host_local, print_type) == -1){ - if(idata.verbose_f) - puts("Error while printing link-local addresses"); - - exit(EXIT_FAILURE); - } - } - else{ - if(print_host_entries(&host_local, print_type) == -1){ - if(idata.verbose_f) - puts("Error while printing link-local addresses"); - - exit(EXIT_FAILURE); - } - } - } - - if(print_global_f){ - host_global.nhosts=0; - host_global.maxhosts= MAX_IPV6_ENTRIES; - host_global.host= host_globals; - - if(probe_echo_f){ - if(find_local_globals(idata.pfd, &idata, PROBE_ICMP6_ECHO, ALL_NODES_MULTICAST_ADDR,\ - &host_global) == -1){ - if(idata.verbose_f) - puts("Error while learning link-local addresses with ICMPv6 Echo Requests"); - - exit(EXIT_FAILURE); - } - } - - if(probe_unrec_f){ - if(find_local_globals(idata.pfd, &idata, PROBE_UNREC_OPT, ALL_NODES_MULTICAST_ADDR,\ - &host_global) == -1){ - if(idata.verbose_f) - puts("Error while learning link-local addresses with Unrecognized options"); - - exit(EXIT_FAILURE); - } - } - - host_candidate.nhosts=0; - host_candidate.maxhosts= MAX_IPV6_ENTRIES; - host_candidate.host= host_candidates; - - if(create_candidate_globals(&idata, &host_local, &host_global, &host_candidate) == -1){ - if(idata.verbose_f) - puts("Error while creating candidate global addresses"); - - exit(EXIT_FAILURE); - } - - if(validate_host_entries(idata.pfd, &idata, &host_candidate, &host_global) == -1){ - if(idata.verbose_f) - puts("Error while validating global entries"); - - exit(EXIT_FAILURE); - } - - if(idata.verbose_f) - puts("\nGlobal addresses:"); - - if(print_unique_f){ - if(print_unique_host_entries(&host_global, print_type) == -1){ - if(idata.verbose_f) - puts("Error while printing global addresses"); - - exit(EXIT_FAILURE); - } - } - else{ - if(print_host_entries(&host_global, print_type) == -1){ - if(idata.verbose_f) - puts("Error while printing global addresses"); - - exit(EXIT_FAILURE); - } - } - } - } - - /* Perform a port-scan */ - else if(portscan_f){ - /* Smart entries are the first ones to be included */ - if(smart_list.ntarget){ - if(!load_smart_entries(&scan_list, &smart_list)){ - puts("Couldn't load smart entries"); - exit(EXIT_FAILURE); - } - } - - if(tgt_knowniids_f){ - if(!load_knowniid_entries(&scan_list, &prefix_list, &iid_list)){ - puts("Couldn't load known IID IPv6 addresses"); - exit(EXIT_FAILURE); - } - } - - if(tgt_knowniidsfile_f){ - if(!load_knowniidfile_entries(&scan_list, &prefix_list, knowniids_fp)){ - puts("Couldn't load known IID IPv6 addresses"); - exit(EXIT_FAILURE); - } - - fclose(knowniids_fp); - } - - if(tgt_portembedded_f){ - for(i=0; i < prefix_list.ntarget; i++){ - if(!load_embeddedport_entries(&scan_list, prefix_list.target[i])){ - puts("Couldn't load embedded-port IPv6 addresses"); - exit(EXIT_FAILURE); - } - } - } - - if(tgt_lowbyte_f){ - for(i=0; i < prefix_list.ntarget; i++){ - if(!load_lowbyte_entries(&scan_list, prefix_list.target[i])){ - puts("Couldn't load prefixes for low-byte IPv6 addresses"); - exit(EXIT_FAILURE); - } - } - } - - if(tgt_ipv4mapped32_f){ - for(i=0; i < prefix_list.ntarget; i++){ - if(!load_ipv4mapped32_entries(&scan_list, prefix_list.target[i], &v4host)){ - puts("Couldn't load prefixes for IPv4-embeded (32-bit) IPv6 addresses"); - exit(EXIT_FAILURE); - } - } - } - - if(tgt_ipv4mapped64_f){ - for(i=0; i < prefix_list.ntarget; i++){ - if(!load_ipv4mapped64_entries(&scan_list, prefix_list.target[i], &v4host)){ - puts("Couldn't load prefixes for IPv4-embeded (64-bit) IPv6 addresses"); - exit(EXIT_FAILURE); - } - } - } - - if(tgt_vm_f){ - for(i=0; i < prefix_list.ntarget; i++){ - if(!load_vm_entries(&scan_list, prefix_list.target[i], &v4host)){ - puts("Couldn't load prefix for IEEE OUI"); - exit(EXIT_FAILURE); - } - } - } - - if(tgt_oui_f){ - for(i=0; i < prefix_list.ntarget; i++){ - if(!load_oui_entries(&scan_list, prefix_list.target[i], &oui)){ - puts("Couldn't load prefix for IEEE OUI"); - exit(EXIT_FAILURE); - } - } - } - - if(tgt_vendor_f){ - for(i=0; i < prefix_list.ntarget; i++){ - if(!load_vendor_entries(&scan_list, prefix_list.target[i], vendor)){ - puts("Couldn't load prefixes for the specified vendor"); - exit(EXIT_FAILURE); - } - } - } - - if(tgt_bruteforce_f){ - for(i=0; i < prefix_list.ntarget; i++){ - if(!load_bruteforce_entries(&scan_list, prefix_list.target[i])){ - puts("Couldn't load prefixes for the specified destination prefix"); - exit(EXIT_FAILURE); - } - } - } - - /* scan_list.ctarget= scan_list.first; */ - - puts(SI6_TOOLKIT); - puts( "scan6: An advanced IPv6 scanning tool\n"); - - if(idata.verbose_f && !bps_f && !pps_f){ - puts("Rate-limiting probe packets to 1000 pps (override with the '-r' option if necessary)"); - } - - if(idata.verbose_f){ - printf("Target address ranges (%d)\n", scan_list.ntarget); - - if(!print_scan_entries(&scan_list)){ - puts("Error while printing target address ranges"); - exit(EXIT_FAILURE); - } - } - - if(!scan_local_f && !idata.ip6_global_flag){ - if(idata.verbose_f){ - puts("Cannot obtain a global address to scan remote network"); - } - - exit(EXIT_FAILURE); - } - - if(idata.verbose_f){ - if(tcp_port_list.nport){ - printf("Target TCP ports: "); - print_port_entries(&tcp_port_list); - puts(""); - } - - if(udp_port_list.nport){ - printf("Target UDP ports: "); - print_port_entries(&udp_port_list); - puts(""); - } - } - - if(tcp_port_list.nport){ - if(udp_port_list.nport){ - /* Allow both TCP and UDP packets */ - if(pcap_compile(idata.pfd, &pcap_filter, PCAP_TCP_UDP_NSNA_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1){ - if(idata.verbose_f>1) - printf("pcap_compile(): %s\n", pcap_geterr(idata.pfd)); - - exit(EXIT_FAILURE); - } - } - else{ - /* Allow only TCP packets */ - if(pcap_compile(idata.pfd, &pcap_filter, PCAP_TCP_NSNA_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1){ - if(idata.verbose_f>1) - printf("pcap_compile(): %s\n", pcap_geterr(idata.pfd)); - - exit(EXIT_FAILURE); - } - } - } - else{ - if(udp_port_list.nport){ - /* Allow only UDP packets */ - if(pcap_compile(idata.pfd, &pcap_filter, PCAP_UDP_NSNA_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1){ - if(idata.verbose_f>1) - printf("pcap_compile(): %s\n", pcap_geterr(idata.pfd)); - - exit(EXIT_FAILURE); - } - } - /* There is no "else" here, since port scanning is triggered by specifying some proto/port */ - } - - /* Set initial contents of the attack packet */ - init_packet_data(&idata); +static sigjmp_buf env; +static unsigned int canjump; + +int main(int argc, char **argv) { + extern char *optarg; + int r; + struct addrinfo hints, *res, *aiptr; + struct target_ipv6 target; + struct timeval timeout; + char date[DATE_STR_LEN], *endptr; + uint8_t ulhtype; + struct scan_entry dummy; + + static struct option longopts[] = {{"interface", required_argument, 0, 'i'}, + {"src-addr", required_argument, 0, 's'}, + {"dst-addr", required_argument, 0, 'd'}, + {"dst-opt-hdr", required_argument, 0, 'u'}, + {"dst-opt-u-hdr", required_argument, 0, 'U'}, + {"hbh-opt-hdr", required_argument, 0, 'H'}, + {"frag-hdr", required_argument, 0, 'y'}, + {"link-src-addr", required_argument, 0, 'S'}, + {"link-dst-addr", required_argument, 0, 'D'}, + {"local-scan", no_argument, 0, 'L'}, + {"probe-type", required_argument, 0, 'p'}, + {"payload-size", required_argument, 0, 'Z'}, + {"src-port", required_argument, 0, 'o'}, + {"dst-port", required_argument, 0, 'a'}, + {"tcp-flags", required_argument, 0, 'X'}, + {"print-type", required_argument, 0, 'P'}, + {"port-scan", required_argument, 0, 'j'}, + {"tcp-scan-type", required_argument, 0, 'G'}, + {"print-unique", no_argument, 0, 'q'}, + {"print-link-addr", no_argument, 0, 'e'}, + {"print-timestamp", no_argument, 0, 't'}, + {"retrans", required_argument, 0, 'x'}, + {"timeout", required_argument, 0, 'O'}, + {"rand-src-addr", no_argument, 0, 'f'}, + {"rand-link-src-addr", no_argument, 0, 'F'}, + {"smart", no_argument, 0, 'A'}, + {"tgt-virtual-machines", required_argument, 0, 'V'}, + {"tgt-low-byte", no_argument, 0, 'b'}, + {"tgt-ipv4", required_argument, 0, 'B'}, + {"tgt-port", no_argument, 0, 'g'}, + {"tgt-ieee-oui", required_argument, 0, 'k'}, + {"tgt-vendor", required_argument, 0, 'K'}, + {"tgt-iids-file", required_argument, 0, 'w'}, + {"tgt-iid", required_argument, 0, 'W'}, + {"prefixes-file", required_argument, 0, 'm'}, + {"ipv4-host", required_argument, 0, 'Q'}, + {"sort-ouis", no_argument, 0, 'T'}, + {"random-probes", no_argument, 0, 'N'}, + {"inc-size", required_argument, 0, 'I'}, + {"rate-limit", required_argument, 0, 'r'}, + {"loop", no_argument, 0, 'l'}, + {"sleep", required_argument, 0, 'z'}, + {"config-file", required_argument, 0, 'c'}, + {"verbose", no_argument, 0, 'v'}, + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0}}; + + const char shortopts[] = "i:s:d:u:U:H:y:S:D:Lp:Z:o:a:X:P:j:G:qetx:O:fFV:bB:gk:K:w:W:m:Q:TNI:r:lz:c:vh"; + + char option; + + if (argc <= 1) { + usage(); + exit(EXIT_FAILURE); + } + + srandom(time(NULL)); + hoplimit = 64 + random() % 180; + + init_iface_data(&idata); + + /* Initialize the scan_list structure (for remote scans) */ + scan_list.target = target_list; + scan_list.ntarget = 0; + scan_list.ctarget = 0; + scan_list.maxtarget = MAX_SCAN_ENTRIES; + + /* Initialize the prefix_list structure (for remote scans) */ + prefix_list.target = tgt_pref_list; + prefix_list.ntarget = 0; + prefix_list.ctarget = 0; + prefix_list.maxtarget = MAX_PREF_ENTRIES; + + /* Initialize the smart_list structure (for remote scans) */ + smart_list.target = smrt_pref_list; + smart_list.ntarget = 0; + smart_list.ctarget = 0; + smart_list.maxtarget = MAX_PREF_ENTRIES; + + /* Initialize the TCP port struture (for port scans) */ + tcp_port_list.port = tcp_prt_list; + tcp_port_list.nport = 0; + tcp_port_list.cport = 0; + tcp_port_list.proto = IPPROTO_TCP; + tcp_port_list.maxport = MAX_PORT_ENTRIES; + + /* Initialize the UDP port struture (for port scans) */ + udp_port_list.port = udp_prt_list; + udp_port_list.nport = 0; + udp_port_list.cport = 0; + udp_port_list.proto = IPPROTO_UDP; + udp_port_list.maxport = MAX_PORT_ENTRIES; + + /* Initialize the iid_list structure (for remote scans/tracking) */ + iid_list.prefix = tgt_iid_list; + iid_list.nprefix = 0; + iid_list.maxprefix = MAX_IID_ENTRIES; + + while ((r = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { + option = r; + + switch (option) { + case 'i': /* Interface */ + strncpy(idata.iface, optarg, IFACE_LENGTH); + idata.iface[IFACE_LENGTH - 1] = 0; + idata.ifindex = if_nametoindex(idata.iface); + idata.iface_f = TRUE; + break; + + case 's': /* IPv6 Source Address */ + if ((charptr = strtok_r(optarg, "/", &lasts)) == NULL) { + puts("Error in Source Address"); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, charptr, &idata.srcaddr) <= 0) { + puts("inet_pton(): Source Address not valid"); + exit(EXIT_FAILURE); + } + + idata.srcaddr_f = TRUE; + + if ((charptr = strtok_r(NULL, " ", &lasts)) != NULL) { + idata.srcpreflen = atoi(charptr); + + if (idata.srcpreflen > 128) { + puts("Prefix length error in IPv6 Source Address"); + exit(EXIT_FAILURE); + } + + sanitize_ipv6_prefix(&(idata.srcaddr), idata.srcpreflen); + idata.srcprefix_f = TRUE; + } + + break; + + case 'd': /* IPv6 Destination Address/Prefix */ + if (!address_contains_colons(optarg)) { + /* The '-d' option contains a domain name */ + if ((charptr = strtok_r(optarg, "/", &lasts)) == NULL) { + puts("Error in Destination Address"); + exit(EXIT_FAILURE); + } + + strncpy(target.name, charptr, NI_MAXHOST); + target.name[NI_MAXHOST - 1] = 0; + + if ((charptr = strtok_r(NULL, " ", &lasts)) != NULL) { + prefix.len = atoi(charptr); + + if (prefix.len > 128) { + puts("Prefix length error in IPv6 Destination Address"); + exit(EXIT_FAILURE); + } + } + else { + prefix.len = 128; + } + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET6; + hints.ai_canonname = NULL; + hints.ai_addr = NULL; + hints.ai_next = NULL; + hints.ai_socktype = SOCK_DGRAM; + + if ((target.res = getaddrinfo(target.name, NULL, &hints, &res)) != 0) { + printf("Unknown Destination '%s': %s\n", target.name, gai_strerror(target.res)); + exit(EXIT_FAILURE); + } + + for (aiptr = res; aiptr != NULL; aiptr = aiptr->ai_next) { + if (aiptr->ai_family != AF_INET6) + continue; + + if (aiptr->ai_addrlen != sizeof(struct sockaddr_in6)) + continue; + + if (aiptr->ai_addr == NULL) + continue; + + prefix.ip6 = ((struct sockaddr_in6 *)aiptr->ai_addr)->sin6_addr; + + /* + If the prefix length is 64 bits (either implicitly or explicitly), we perform a smart scan + */ + + if (smart_f || (prefix.len == 64 && !is_iid_null(&(prefix.ip6), 64))) { + if (smart_list.ntarget <= smart_list.maxtarget) { + if ((smart_list.target[smart_list.ntarget] = malloc(sizeof(struct scan_entry))) == NULL) { + if (idata.verbose_f) + puts("scan6: Not enough memory"); + + exit(EXIT_FAILURE); + } + + prefix_to_scan(&prefix, smart_list.target[smart_list.ntarget]); + + if (IN6_IS_ADDR_MULTICAST(&(smart_list.target[smart_list.ntarget]->start.in6_addr))) { + if (idata.verbose_f) + puts("scan6: Remote scan cannot target a multicast address"); + + exit(EXIT_FAILURE); + } + + if (IN6_IS_ADDR_MULTICAST(&(smart_list.target[smart_list.ntarget]->end.in6_addr))) { + if (idata.verbose_f) + puts("scan6: Remote scan cannot target a multicast address"); + + exit(EXIT_FAILURE); + } + + idata.dstaddr = smart_list.target[smart_list.ntarget]->start.in6_addr; + smart_list.ntarget++; + } + else { + /* + If the number of "targets" has already been exceeded, it doesn't make sense to continue + further, since there wouldn't be space for any specific target types + */ + if (idata.verbose_f) + puts("Too many targets!"); + + exit(EXIT_FAILURE); + } + } + else { + sanitize_ipv6_prefix(&(prefix.ip6), prefix.len); + + if (prefix_list.ntarget <= prefix_list.maxtarget) { + if ((prefix_list.target[prefix_list.ntarget] = malloc(sizeof(struct scan_entry))) == NULL) { + if (idata.verbose_f) + puts("scan6: Not enough memory"); + + exit(EXIT_FAILURE); + } + + prefix_to_scan(&prefix, prefix_list.target[prefix_list.ntarget]); + + if (IN6_IS_ADDR_MULTICAST(&(prefix_list.target[prefix_list.ntarget]->start.in6_addr))) { + if (idata.verbose_f) + puts("scan6: Remote scan cannot target a multicast address"); + + exit(EXIT_FAILURE); + } + + if (IN6_IS_ADDR_MULTICAST(&(prefix_list.target[prefix_list.ntarget]->end.in6_addr))) { + if (idata.verbose_f) + puts("scan6: Remote scan cannot target a multicast address"); + + exit(EXIT_FAILURE); + } + + idata.dstaddr = prefix_list.target[prefix_list.ntarget]->start.in6_addr; + prefix_list.ntarget++; + } + else { + /* + If the number of "targets" has already been exceeded, it doesn't make sense to continue + further, since there wouldn't be space for any specific target types + */ + if (idata.verbose_f) + puts("Too many targets!"); + + exit(EXIT_FAILURE); + } + } + } + + freeaddrinfo(res); + } + else if ((ranges = address_contains_ranges(optarg)) == 1) { + /* + When an address range is specified, such address range is scanned, but the correspnding prefix is + also employed for generating additional addresses to be scanned (EUI-64 based, etc.) + */ + charptr = optarg; + charstart = rangestart; + charend = rangeend; + lastcolon = charend; + + while (*charptr && (optarg - charptr) <= MAX_RANGE_STR_LEN) { + if (*charptr != '-') { + /* If we do not find a dash, just copy this 16-bit word to both the range start and the range + * end */ + *charstart = *charptr; + *charend = *charptr; + charstart++; + charend++; + + /* + Record the address of the byte following the colon (in the range end), so that we know what + to "overwrite when we find a "range + */ + if (*charptr == ':') + lastcolon = charend; + + charptr++; + } + else { + /* If we found a dash, we must "overwrite" the range end with what follows the dash */ + charend = lastcolon; + charptr++; + + while (*charptr && (optarg - charptr) <= MAX_RANGE_STR_LEN && *charptr != ':' && + *charptr != '-') { + *charend = *charptr; + charend++; + charptr++; + } + } + } + + /* Zero-terminate the strings that we have generated from the option arguments */ + *charstart = 0; + *charend = 0; + tgt_range_f = TRUE; + + if (scan_list.ntarget <= scan_list.maxtarget) { + if (inet_pton(AF_INET6, rangestart, &(dummy.start.in6_addr)) <= 0) { + if (idata.verbose_f > 1) + puts("inet_pton(): Error converting IPv6 address from presentation to network format"); + + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, rangeend, &(dummy.end.in6_addr)) <= 0) { + if (idata.verbose_f > 1) + puts("inet_pton(): Error converting IPv6 address from presentation to network format"); + + exit(EXIT_FAILURE); + } + + dummy.cur.in6_addr = dummy.start.in6_addr; + + /* Check whether the start address is smaller than the end address */ + for (i = 0; i < 7; i++) + if (ntohs(dummy.start.s6addr16[i]) > ntohs(dummy.end.s6addr16[i])) { + if (idata.verbose_f) + puts("Error in Destination Address range: Start address larger than end address!"); + + exit(EXIT_FAILURE); + } + + if (IN6_IS_ADDR_MULTICAST(&(dummy.start.in6_addr))) { + if (idata.verbose_f) + puts("scan6: Remote scan cannot target a multicast address"); + + exit(EXIT_FAILURE); + } + + if (IN6_IS_ADDR_MULTICAST(&(dummy.end.in6_addr))) { + if (idata.verbose_f) + puts("scan6: Remote scan cannot target a multicast address"); + + exit(EXIT_FAILURE); + } + + idata.dstaddr = dummy.start.in6_addr; + if (add_to_scan_list(&scan_list, &dummy) == FALSE) { + if (idata.verbose_f) + puts("Couldn't add entry to scan list"); + + exit(EXIT_FAILURE); + } + } + else { + /* + If the number of "targets" has already been exceeded, it doesn't make sense to continue further, + since there wouldn't be space for any specific target types + */ + if (idata.verbose_f) + puts("Too many targets!"); + + exit(EXIT_FAILURE); + } + + if (prefix_list.ntarget <= prefix_list.maxtarget) { + if ((prefix_list.target[prefix_list.ntarget] = malloc(sizeof(struct scan_entry))) == NULL) { + if (idata.verbose_f) + puts("scan6: Not enough memory"); + + exit(EXIT_FAILURE); + } + + /* Copy the recently added target to our prefix list */ + *prefix_list.target[prefix_list.ntarget] = dummy; + prefix_list.ntarget++; + } + else { + /* + If the number of "targets" has already been exceeded, it doesn't make sense to continue further, + since there wouldn't be space for any specific target types + */ + if (idata.verbose_f) + puts("Too many targets!"); + + exit(EXIT_FAILURE); + } + } + else if (ranges == 0) { + /* The '-d' option contains a prefix with the slash notation */ + if ((charptr = strtok_r(optarg, "/", &lasts)) == NULL) { + puts("Error in Destination Address"); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, charptr, &(prefix.ip6)) <= 0) { + puts("inet_pton(): Destination Address not valid"); + exit(EXIT_FAILURE); + } + + if ((charptr = strtok_r(NULL, " ", &lasts)) != NULL) { + prefix.len = atoi(charptr); + + if (prefix.len > 128) { + puts("Prefix length error in IPv6 Destination Address"); + exit(EXIT_FAILURE); + } + + sanitize_ipv6_prefix(&(prefix.ip6), prefix.len); + } + else { + prefix.len = 128; + } + + /* If the Prefix length is /128 (explicitly set, or by omission), we do a smart scan */ + if (smart_f || (prefix.len == 64 && !is_iid_null(&(prefix.ip6), 64))) { + if (smart_list.ntarget <= smart_list.maxtarget) { + if ((smart_list.target[smart_list.ntarget] = malloc(sizeof(struct scan_entry))) == NULL) { + if (idata.verbose_f) + puts("scan6: Not enough memory"); + + exit(EXIT_FAILURE); + } + + prefix_to_scan(&prefix, smart_list.target[smart_list.ntarget]); + + if (IN6_IS_ADDR_MULTICAST(&(smart_list.target[smart_list.ntarget]->start.in6_addr))) { + if (idata.verbose_f) + puts("scan6: Remote scan cannot target a multicast address"); + + exit(EXIT_FAILURE); + } + + if (IN6_IS_ADDR_MULTICAST(&(smart_list.target[smart_list.ntarget]->end.in6_addr))) { + if (idata.verbose_f) + puts("scan6: Remote scan cannot target a multicast address"); + + exit(EXIT_FAILURE); + } + + idata.dstaddr = smart_list.target[smart_list.ntarget]->start.in6_addr; + smart_list.ntarget++; + } + else { + /* + If the number of "targets" has already been exceeded, it doesn't make sense to continue + further, since there wouldn't be space for any specific target types + */ + if (idata.verbose_f) + puts("Too many targets!"); + + exit(EXIT_FAILURE); + } + } + else { + if (prefix_list.ntarget <= prefix_list.maxtarget) { + if ((prefix_list.target[prefix_list.ntarget] = malloc(sizeof(struct scan_entry))) == NULL) { + if (idata.verbose_f) + puts("scan6: Not enough memory"); + + exit(EXIT_FAILURE); + } + + prefix_to_scan(&prefix, prefix_list.target[prefix_list.ntarget]); + + if (IN6_IS_ADDR_MULTICAST(&(prefix_list.target[prefix_list.ntarget]->start.in6_addr))) { + if (idata.verbose_f) + puts("scan6: Remote scan cannot target a multicast address"); + + exit(EXIT_FAILURE); + } + + if (IN6_IS_ADDR_MULTICAST(&(prefix_list.target[prefix_list.ntarget]->end.in6_addr))) { + if (idata.verbose_f) + puts("scan6: Remote scan cannot target a multicast address"); + + exit(EXIT_FAILURE); + } + + prefix_list.ntarget++; + idata.dstaddr = prefix_list.target[0]->start.in6_addr; + } + else { + /* + If the number of "targets" has already been exceeded, it doesn't make sense to continue + further, since there wouldn't be space for any specific target types + */ + if (idata.verbose_f) + puts("Too many targets!"); + + exit(EXIT_FAILURE); + } + } + } + + idata.dstaddr_f = TRUE; + dst_f = TRUE; + break; + + case 'u': /* Destinations Options Header */ + if (ndstopthdr >= MAX_DST_OPT_HDR) { + puts("Too many Destination Options Headers"); + exit(EXIT_FAILURE); + } + + hdrlen = atoi(optarg); + + if (hdrlen < 8) { + puts("Bad length in Destination Options Header"); + exit(EXIT_FAILURE); + } + + hdrlen = ((hdrlen + 7) / 8) * 8; + dstopthdrlen[ndstopthdr] = hdrlen; + + if ((dstopthdr[ndstopthdr] = malloc(hdrlen)) == NULL) { + puts("Not enough memory for Destination Options Header"); + exit(EXIT_FAILURE); + } + + ptrhdr = dstopthdr[ndstopthdr] + 2; + ptrhdrend = dstopthdr[ndstopthdr] + hdrlen; + + while (ptrhdr < ptrhdrend) { + + if ((ptrhdrend - ptrhdr) > 257) + pad = 257; + else + pad = ptrhdrend - ptrhdr; + + if (!insert_pad_opt(ptrhdr, ptrhdrend, pad)) { + puts("Destination Options Header Too Big"); + exit(EXIT_FAILURE); + } + + ptrhdr = ptrhdr + pad; + } + + *(dstopthdr[ndstopthdr] + 1) = (hdrlen / 8) - 1; + ndstopthdr++; + dstopthdr_f = TRUE; + break; + + case 'U': /* Destination Options Header (Unfragmentable Part) */ + if (ndstoptuhdr >= MAX_DST_OPT_U_HDR) { + puts("Too many Destination Options Headers (Unfragmentable Part)"); + exit(EXIT_FAILURE); + } + + hdrlen = atoi(optarg); + + if (hdrlen < 8) { + puts("Bad length in Destination Options Header (Unfragmentable Part)"); + exit(EXIT_FAILURE); + } + + hdrlen = ((hdrlen + 7) / 8) * 8; + dstoptuhdrlen[ndstoptuhdr] = hdrlen; + + if ((dstoptuhdr[ndstoptuhdr] = malloc(hdrlen)) == NULL) { + puts("Not enough memory for Destination Options Header (Unfragmentable Part)"); + exit(EXIT_FAILURE); + } + + ptrhdr = dstoptuhdr[ndstoptuhdr] + 2; + ptrhdrend = dstoptuhdr[ndstoptuhdr] + hdrlen; + + while (ptrhdr < ptrhdrend) { + + if ((ptrhdrend - ptrhdr) > 257) + pad = 257; + else + pad = ptrhdrend - ptrhdr; + + if (!insert_pad_opt(ptrhdr, ptrhdrend, pad)) { + puts("Destination Options Header (Unfragmentable Part) Too Big"); + exit(EXIT_FAILURE); + } + + ptrhdr = ptrhdr + pad; + } + + *(dstoptuhdr[ndstoptuhdr] + 1) = (hdrlen / 8) - 1; + ndstoptuhdr++; + dstoptuhdr_f = TRUE; + break; + + case 'H': /* Hop-by-Hop Options Header */ + if (nhbhopthdr >= MAX_HBH_OPT_HDR) { + puts("Too many Hop-by-Hop Options Headers"); + exit(EXIT_FAILURE); + } + + hdrlen = atoi(optarg); + + if (hdrlen <= 8) { + puts("Bad length in Hop-by-Hop Options Header"); + exit(EXIT_FAILURE); + } + + hdrlen = ((hdrlen + 7) / 8) * 8; + hbhopthdrlen[nhbhopthdr] = hdrlen; + + if ((hbhopthdr[nhbhopthdr] = malloc(hdrlen)) == NULL) { + puts("Not enough memory for Hop-by-Hop Options Header"); + exit(EXIT_FAILURE); + } + + ptrhdr = hbhopthdr[nhbhopthdr] + 2; + ptrhdrend = hbhopthdr[nhbhopthdr] + hdrlen; + + while (ptrhdr < ptrhdrend) { + + if ((ptrhdrend - ptrhdr) > 257) + pad = 257; + else + pad = ptrhdrend - ptrhdr; + + if (!insert_pad_opt(ptrhdr, ptrhdrend, pad)) { + puts("Hop-by-Hop Options Header Too Big"); + exit(EXIT_FAILURE); + } + + ptrhdr = ptrhdr + pad; + } + + *(hbhopthdr[nhbhopthdr] + 1) = (hdrlen / 8) - 1; + nhbhopthdr++; + hbhopthdr_f = TRUE; + break; + + case 'y': /* Fragment header */ + nfrags = atoi(optarg); + if (nfrags < 8) { + puts("Error in Fragmentation option: Fragment Size must be at least 8 bytes"); + exit(EXIT_FAILURE); + } + + idata.fragh_f = TRUE; + + /* XXX: To be removed when fragmentation support is added */ + puts("Error: scan6 does not currently support fragmentation"); + exit(EXIT_FAILURE); + + break; + + case 'S': /* Source Ethernet address */ + if (ether_pton(optarg, &(idata.hsrcaddr), sizeof(idata.hsrcaddr)) == 0) { + puts("Error in Source link-layer address."); + exit(EXIT_FAILURE); + } + + idata.hsrcaddr_f = TRUE; + break; + + case 'D': /* Destination Ethernet address */ + if (ether_pton(optarg, &(idata.hdstaddr), sizeof(idata.hdstaddr)) == 0) { + puts("Error in Destination Ethernet address."); + exit(EXIT_FAILURE); + } + + idata.hdstaddr_f = TRUE; + break; + + case 'L': + scan_local_f = TRUE; + break; + + case 'p': /* Probe type */ + if (strncmp(optarg, "echo", strlen("echo")) == 0) { + probe_echo_f = TRUE; + probetype = PROBE_ICMP6_ECHO; + probe_f = TRUE; + } + else if (strncmp(optarg, "unrec", strlen("unrec")) == 0) { + probe_unrec_f = TRUE; + probetype = PROBE_UNREC_OPT; + probe_f = TRUE; + } + else if (strncmp(optarg, "all", strlen("all")) == 0) { + probe_echo_f = TRUE; + probe_unrec_f = TRUE; + + /* For reote scans, we use a single probe type */ + probetype = PROBE_ICMP6_ECHO; + probe_f = TRUE; + } + else if (strncmp(optarg, "tcp", strlen("tcp")) == 0) { + probetype = PROBE_TCP; + probe_f = TRUE; + } + else { + puts("Error in '-p' option: Unknown probe type"); + exit(EXIT_FAILURE); + } + + break; + + case 'Z': /* Payload Size*/ + rhbytes = atoi(optarg); + rhbytes_f = TRUE; + break; + + case 'o': /* TCP/UDP Source Port */ + srcport = atoi(optarg); + srcport_f = TRUE; + break; + + case 'a': /* TCP/UDP Destination Port */ + dstport = atoi(optarg); + dstport_f = TRUE; + break; + + case 'X': + charptr = optarg; + while (*charptr) { + switch (*charptr) { + case 'F': + tcpflags = tcpflags | TH_FIN; + break; + + case 'S': + tcpflags = tcpflags | TH_SYN; + break; + + case 'R': + tcpflags = tcpflags | TH_RST; + break; + + case 'P': + tcpflags = tcpflags | TH_PUSH; + break; + + case 'A': + tcpflags = tcpflags | TH_ACK; + break; + + case 'U': + tcpflags = tcpflags | TH_URG; + break; + + case 'X': /* No TCP flags */ + break; + + default: + printf("Unknown TCP flag '%c'\n", *charptr); + exit(EXIT_FAILURE); + break; + } + + if (*charptr == 'X') + break; + + charptr++; + } + + tcpflags_f = TRUE; + break; + + case 'P': /* Print type */ + if (strncmp(optarg, "local", strlen("local")) == 0) { + print_local_f = TRUE; + print_f = TRUE; + } + else if (strncmp(optarg, "global", strlen("global")) == 0) { + print_global_f = TRUE; + print_f = TRUE; + } + else if (strncmp(optarg, "all", strlen("all")) == 0) { + print_local_f = TRUE; + print_global_f = TRUE; + print_f = TRUE; + } + else { + puts("Error in '-P' option: Unknown address type"); + exit(EXIT_FAILURE); + } + + break; + + case 'q': + print_unique_f = TRUE; + break; + + case 'e': + print_type = PRINT_ETHER_ADDR; + break; + + case 't': + timestamps_f = TRUE; + break; + + case 'x': + idata.local_retrans = atoi(optarg); + break; + + case 'O': + idata.local_timeout = atoi(optarg); + break; + + case 'f': + rand_src_f = TRUE; + break; + + case 'F': + rand_link_src_f = TRUE; + break; + + case 'A': + smart_f = TRUE; + break; + + case 'j': + if ((pref = strtok_r(optarg, ":", &lasts)) == NULL) { + printf("Error in prefix option number %u. \n", i); + exit(EXIT_FAILURE); + } + + if (strncmp(pref, "udp", 3) == 0 || strncmp(pref, "udp", 3) == 0) { + port_list = &udp_port_list; + cprotocol = IPPROTO_UDP; + } + else if (strncmp(pref, "tcp", 3) == 0 || strncmp(pref, "TCP", 3) == 0) { + port_list = &tcp_port_list; + cprotocol = IPPROTO_TCP; + } + else if (strncmp(pref, "all", 3) == 0 || strncmp(pref, "ALL", 3) == 0) { + cprotocol = IPPROTO_ALL; + } + else { + puts("Error unknown protocol in 'port-scan' option"); + exit(EXIT_FAILURE); + } + + if (strncmp(lasts, "top", 3) == 0 || strncmp(lasts, "top", 3) == 0) { + if ((charptr = strtok_r(NULL, ":", &lasts)) == NULL) { + printf("Error in prefix option number %u. \n", i); + exit(EXIT_FAILURE); + } + + if (cprotocol == IPPROTO_ALL && (loadtcptopports_f || loadudptopports_f)) { + puts("Cannot specify all ports and (TCP or UDP) top ports at the same time"); + exit(EXIT_FAILURE); + } + else if (cprotocol == IPPROTO_TCP && loadtcptopports_f) { + puts("Cannot specify TCP top ports more than once"); + exit(EXIT_FAILURE); + } + else if (cprotocol == IPPROTO_UDP && loadudptopports_f) { + puts("Cannot specify TCP top ports more than once"); + exit(EXIT_FAILURE); + } + + if (strncmp(lasts, "all", 3) == 0 || strncmp(lasts, "ALL", 3) == 0) { + nalltopports = (MAX_PORT_RANGE + 1) * 2; /* This sets the cap for the number of entries to load */ + } + else { + nalltopports = atoi(lasts); + } + + if (nalltopports > 0) { + if (cprotocol == IPPROTO_TCP) { + loadtcptopports_f = TRUE; + ntcptopports = nalltopports; + } + else if (cprotocol == IPPROTO_UDP) { + loadudptopports_f = TRUE; + nudptopports = nalltopports; + } + else if (cprotocol == IPPROTO_ALL) { + loadalltopports_f = TRUE; + } + else { + /* Should never happen */ + puts("Bad protocol"); + exit(EXIT_FAILURE); + } + } + + portscan_f = TRUE; + break; + } + else if (address_contains_ranges(lasts)) { + if ((pref = strtok_r(NULL, "-", &lasts)) == NULL) { + puts("Error in 'port-scan' option"); + exit(EXIT_FAILURE); + } + + portscanl = strtoul(pref, &endptr, 10); + + if (pref == endptr && portscanl == 0) { + puts("Error in port range"); + exit(EXIT_FAILURE); + } + + portscanh = strtoul(lasts, &endptr, 10); + + if (lasts == endptr && portscanh == 0) { + puts("Error in port range"); + exit(EXIT_FAILURE); + } + } + else { + portscanl = strtoul(lasts, &endptr, 10); + + if (lasts == endptr && portscanl == 0) { + portscanl = DEFAULT_MIN_PORT; + portscanh = DEFAULT_MAX_PORT; + } + else { + portscanh = portscanl; + } + } + + if (portscanl > portscanh) { + portscantemp = portscanl; + portscanl = portscanh; + portscanh = portscantemp; + } + + if (port_list->nport < port_list->maxport) { + if ((port_list->port[port_list->nport] = malloc(sizeof(struct port_entry))) == NULL) { + if (idata.verbose_f) + puts("scan6: Not enough memory"); + + exit(EXIT_FAILURE); + } + + port_list->port[port_list->nport]->start = portscanl; + port_list->port[port_list->nport]->end = portscanh; + (port_list->port[port_list->nport])->cur = (port_list->port[port_list->nport])->start; + port_list->nport++; + } + else { + /* + If the number of "prots" has already been exceeded, it doesn't make sense to continue further, + since there wouldn't be space for any specific target types + */ + if (idata.verbose_f) + puts("Too many port ranges!"); + + exit(EXIT_FAILURE); + } + + portscan_f = TRUE; + break; + + case 'G': + if (strncmp(optarg, "syn", strlen("syn")) == 0 || strncmp(optarg, "SYN", strlen("SYN")) == 0) { + tcpflags = TH_SYN; + tcpflags_f = TRUE; + } + else if (strncmp(optarg, "fin", strlen("fin")) == 0 || strncmp(optarg, "FIN", strlen("FIN")) == 0) { + tcpflags = TH_FIN; + tcpflags_f = TRUE; + } + else if (strncmp(optarg, "null", strlen("null")) == 0 || strncmp(optarg, "NULL", strlen("NULL")) == 0) { + tcpflags = 0; + tcpflags_f = TRUE; + } + else if (strncmp(optarg, "xmas", strlen("xmas")) == 0 || strncmp(optarg, "XMAS", strlen("XMAS")) == 0) { + tcpflags = TH_FIN | TH_PUSH | TH_URG; + tcpflags_f = TRUE; + } + else if (strncmp(optarg, "ack", strlen("ack")) == 0 || strncmp(optarg, "ACK", strlen("ACK")) == 0) { + tcpflags = TH_ACK; + tcpflags_f = TRUE; + } + + break; + + case 'V': + if (strncmp(optarg, "vbox", strlen("vbox")) == 0 || + strncmp(optarg, "virtualbox", strlen("virtualbox")) == 0) { + tgt_vm_f = TRUE; + vm_vbox_f = TRUE; + } + else if (strncmp(optarg, "vmware-esx", strlen("vmware-esx")) == 0) { + tgt_vm_f = TRUE; + vm_vmware_esx_f = TRUE; + } + else if (strncmp(optarg, "vmware-vsphere", strlen("vmware-vsphere")) == 0) { + tgt_vm_f = TRUE; + vm_vmware_vsphere_f = TRUE; + } + else if (strncmp(optarg, "vmwarem", strlen("vmwarem")) == 0 || + strncmp(optarg, "vmware-manual", strlen("vmware-manual")) == 0) { + tgt_vm_f = TRUE; + vm_vmwarem_f = TRUE; + } + else if (strncmp(optarg, "vmware", strlen("vmware")) == 0) { + tgt_vm_f = TRUE; + vm_vmware_esx_f = TRUE; + vm_vmware_vsphere_f = TRUE; + vm_vmwarem_f = TRUE; + } + else if (strncmp(optarg, "all", strlen("all")) == 0) { + tgt_vm_f = TRUE; + vm_vbox_f = TRUE; + vm_vmware_esx_f = TRUE; + vm_vmware_vsphere_f = TRUE; + vm_vmwarem_f = TRUE; + } + else { + puts("Error in '-V' option: Unknown Virtualization Technology"); + exit(EXIT_FAILURE); + } + + break; + + case 'b': + tgt_lowbyte_f = TRUE; + break; + + case 'B': + if (strncmp("ipv4-all", optarg, MAX_LINE_SIZE) == 0 || strncmp("all", optarg, MAX_LINE_SIZE) == 0) { + tgt_ipv4mapped32_f = TRUE; + tgt_ipv4mapped64_f = TRUE; + } + else if (strncmp("ipv4-32", optarg, MAX_LINE_SIZE) == 0 || strncmp("32", optarg, MAX_LINE_SIZE) == 0) { + tgt_ipv4mapped32_f = TRUE; + } + else if (strncmp("ipv4-64", optarg, MAX_LINE_SIZE) == 0 || strncmp("64", optarg, MAX_LINE_SIZE) == 0) { + tgt_ipv4mapped64_f = TRUE; + } + else { + puts("Unknown encoding of IPv4-embedded IPv6 addresses in '-B' option"); + exit(EXIT_FAILURE); + } + + break; + + case 'g': + tgt_portembedded_f = TRUE; + break; + + case 'k': /* Target OUI */ + /* + In case the user entered an OUI as OO:UU:II:00:00:00, just copy the first 8 bytes of input + (the OUI part) + */ + strncpy(oui_ascii, optarg, 8); + oui_ascii[8] = 0; + strncat(oui_ascii, oui_end, ETHER_ADDR_PLEN - Strnlen(oui_ascii, sizeof(oui_ascii)) - 1); + + if (ether_pton(oui_ascii, &oui, sizeof(oui)) == 0) { + puts("Error in vendor IEEE OUI"); + exit(EXIT_FAILURE); + } + + tgt_oui_f = TRUE; + break; + + case 'K': /* Target vendor */ + /* + In case the user entered an OUI as OO:UU:II:00:00:00, just copy the first 8 bytes of input + (the OUI part) + */ + + strncpy(vendor, optarg, MAX_IEEE_OUIS_LINE_SIZE - 1); + vendor[MAX_IEEE_OUIS_LINE_SIZE - 1] = 0; + + tgt_vendor_f = TRUE; + break; + + case 'w': /* Target known Interface Identifiers (IIDs) */ + strncpy(knowniidsfile, optarg, MAX_FILENAME_SIZE - 1); + knowniidsfile[MAX_FILENAME_SIZE - 1] = 0; + + tgt_knowniidsfile_f = TRUE; + break; + + case 'W': /* Target Interface Identifier (IIDs) */ + if (iid_list.nprefix >= iid_list.maxprefix) { + puts("Too many INterface Identifiers"); + exit(EXIT_FAILURE); + } + + if ((iid_list.prefix[iid_list.nprefix] = malloc(sizeof(struct prefix_entry))) == NULL) { + puts("Not enough memory while storing Interface ID"); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, optarg, &((iid_list.prefix[iid_list.nprefix])->ip6)) <= 0) { + puts("inet_pton(): Source Address not valid"); + exit(EXIT_FAILURE); + } + + iid_list.prefix[iid_list.nprefix]->len = 128; + iid_list.nprefix++; + + tgt_knowniids_f = TRUE; + break; + + case 'm': /* Known prefixes file */ + strncpy(knownprefixesfile, optarg, MAX_FILENAME_SIZE - 1); + knownprefixesfile[MAX_FILENAME_SIZE - 1] = 0; + + knownprefixes_f = TRUE; + break; + + case 'Q': + if ((charptr = strtok_r(optarg, "/", &lasts)) == NULL) { + puts("Error in Source Address"); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET, charptr, &(v4host.ip)) != 1) { + puts("Error in Host IPv4 Address"); + exit(EXIT_FAILURE); + } + + v4hostaddr_f = TRUE; + + if ((charptr = strtok_r(NULL, " ", &lasts)) != NULL) { + v4host.len = atoi(charptr); + + if (v4host.len > 32) { + puts("Prefix length error in Host IPv4 address"); + exit(EXIT_FAILURE); + } + + sanitize_ipv4_prefix(&v4host); + v4hostprefix_f = TRUE; + } + else { + v4host.len = 32; + } + + break; + + case 'T': + sort_ouis_f = TRUE; + break; + + case 'N': + rnd_probes_f = TRUE; + break; + + case 'I': + inc = atoi(optarg); + inc_f = TRUE; + break; + + case 'r': + if (Strnlen(optarg, LINE_BUFFER_SIZE - 1) >= (LINE_BUFFER_SIZE - 1)) { + puts("scan6: -r option is too long"); + exit(EXIT_FAILURE); + } + + sscanf(optarg, "%lu%s", &rate, line); + + line[LINE_BUFFER_SIZE - 1] = 0; + + if (strncmp(line, "pps", 3) == 0) + pps_f = TRUE; + else if (strncmp(line, "bps", 3) == 0) + bps_f = TRUE; + else { + puts("scan6: Unknown unit of for the rate limit ('-r' option). Unit should be 'bps' or 'pps'"); + exit(EXIT_FAILURE); + } + + break; + + case 'l': /* "Loop mode */ + loop_f = TRUE; + break; + + case 'z': /* Sleep option */ + nsleep = atoi(optarg); + if (nsleep == 0) { + puts("Invalid number of seconds in '-z' option"); + exit(EXIT_FAILURE); + } + + sleep_f = TRUE; + break; + + case 'v': /* Be verbose */ + idata.verbose_f++; + break; + + case 'h': /* Help */ + print_help(); + exit(EXIT_FAILURE); + break; + + case 'c': /* Configuration file */ + strncpy(configfile, optarg, MAX_FILENAME_SIZE - 1); + configfile[MAX_FILENAME_SIZE - 1] = 0; + configfile_f = TRUE; + break; + + default: + usage(); + exit(EXIT_FAILURE); + break; + + } /* switch */ + } /* while(getopt) */ + + /* + XXX: This is rather ugly, but some local functions need to check for verbosity, and it was not warranted + to pass &idata as an argument + */ + verbose_f = idata.verbose_f; + + if (geteuid()) { + puts("scan6 needs superuser privileges to run"); + exit(EXIT_FAILURE); + } + + if (scan_local_f && !idata.iface_f) { + puts("Must specify the network interface with the -i option when a local scan is selected"); + exit(EXIT_FAILURE); + } + + /* Must open the "Known IIDs" file now, since it might be non-readable for the unprivileged user */ + if (tgt_knowniidsfile_f) { + if ((knowniids_fp = fopen(knowniidsfile, "r")) == NULL) { + perror("Error opening known IIDs file"); + exit(EXIT_FAILURE); + } + } + + /* Must open the "Known IIDs" file now, since it might be non-readable for the unprivileged user */ + if (knownprefixes_f) { + if ((knownprefixes_fp = fopen(knownprefixesfile, "r")) == NULL) { + perror("Error opening known prefixes file"); + exit(EXIT_FAILURE); + } + + dst_f = TRUE; + } + + if (!dst_f && !scan_local_f) { + if (idata.verbose_f) + puts("Must specify either a destination prefix ('-d'), or a local scan ('-L')"); + + exit(EXIT_FAILURE); + } + + if (!scan_local_f) { + if (load_dst_and_pcap(&idata, LOAD_SRC_NXT_HOP) == FAILURE) { + puts("Error while learning Source Address and Next Hop"); + exit(EXIT_FAILURE); + } + } + else { + if (load_dst_and_pcap(&idata, LOAD_PCAP_ONLY) == FAILURE) { + puts("Error while learning Source Address and Next Hop"); + exit(EXIT_FAILURE); + } + } + + release_privileges(); + + /* This loads prefixes, but not scan entries */ + if (knownprefixes_f) { + if (!load_knownprefix_entries(&scan_list, &prefix_list, knownprefixes_fp)) { + puts("Couldn't load known IPv6 prefixes"); + exit(EXIT_FAILURE); + } + } + + if (!inc_f) + scan_list.inc = 1; + + if (pps_f && bps_f) { + puts("Cannot specify a rate-limit in bps and pps at the same time"); + exit(EXIT_FAILURE); + } + + if (pps_f) { + if (rate < 1) + rate = 1; + + pktinterval = 1000000 / rate; + } + + if (bps_f) { + switch (probetype) { + case PROBE_UNREC_OPT: + packetsize = MIN_IPV6_HLEN + sizeof(struct icmp6_hdr) + ICMPV6_ECHO_PAYLOAD_SIZE; + break; + + case PROBE_ICMP6_ECHO: + packetsize = MIN_IPV6_HLEN + MIN_DST_OPT_HDR_SIZE + sizeof(struct icmp6_hdr) + ICMPV6_ECHO_PAYLOAD_SIZE; + break; + + case PROBE_TCP: + packetsize = MIN_IPV6_HLEN + sizeof(struct tcp_hdr) + rhbytes; + break; + } + + if (rate == 0 || ((packetsize * 8) / rate) <= 0) + pktinterval = 1000000; + else + pktinterval = ((packetsize * 8) / rate) * 1000000; + } + + /* We Default to 1000 pps */ + if (!pps_f && !bps_f) + pktinterval = 1000; + + if (!configfile_f) { + strncpy(configfile, "/etc/ipv6toolkit.conf", MAX_FILENAME_SIZE); + } + + if (tgt_vendor_f || portscan_f) { + if (!process_config_file(configfile)) { + puts("Error while processing configuration file"); + exit(EXIT_FAILURE); + } + } + + if (portscan_f) { + if (loadalltopports_f) { + if (load_top_ports_entries(&tcp_port_list, &udp_port_list, IPPROTO_ALL, nalltopports) == FALSE) { + puts("Problem loading TCP top ports"); + exit(EXIT_FAILURE); + } + } + else { + if (loadtcptopports_f) { + if (load_top_ports_entries(&tcp_port_list, &udp_port_list, IPPROTO_TCP, ntcptopports) == FALSE) { + puts("Problem loading TCP top ports"); + exit(EXIT_FAILURE); + } + } + if (loadudptopports_f) { + if (load_top_ports_entries(&tcp_port_list, &udp_port_list, IPPROTO_UDP, nudptopports) == FALSE) { + puts("Problem loading UDP top ports"); + exit(EXIT_FAILURE); + } + } + } + + if (tcp_port_list.nport) { + /* Load service names */ + if (!load_port_table(tcp_port_table, "tcp", MAX_PORT_RANGE)) { + puts("Error while loading port number descriptions"); + exit(EXIT_FAILURE); + } + + /* Link service names to port_list structure */ + tcp_port_list.port_table = tcp_port_table; + + /* We currently support only SYN scans for TCP */ + tcpflags_f = TRUE; + tcpflags = TH_SYN; + } + + if (udp_port_list.nport) { + /* Load service names */ + if (!load_port_table(udp_port_table, "udp", MAX_PORT_RANGE)) { + puts("Error while loading port number descriptions"); + exit(EXIT_FAILURE); + } + + /* LInk service names to port_list structure */ + udp_port_list.port_table = udp_port_table; + } + } + + if (loop_f && !dst_f) { + puts("Loop mode '-l' set, but no targets ('-d') specified!"); + puts("Note: '-l' option changed since IPv6 toolkit v1.3.4!"); + } + + if (dst_f && !(tgt_ipv4mapped32_f || tgt_ipv4mapped64_f || tgt_lowbyte_f || tgt_oui_f || tgt_vendor_f || tgt_vm_f || + tgt_range_f || tgt_portembedded_f || tgt_knowniids_f || tgt_knowniidsfile_f)) { + + tgt_bruteforce_f = TRUE; + } + + if ((tgt_ipv4mapped32_f || tgt_ipv4mapped64_f) && !v4hostaddr_f) { + puts("Error: Must IPv4 host address/prefix (with '--ipv4-host') if '--tgt-ipv4-embedded' is set"); + exit(EXIT_FAILURE); + } + + if (scan_local_f && (idata.type != DLT_EN10MB || (idata.flags & IFACE_TUNNEL))) { + puts("Error cannot apply local scan on a loopback or tunnel interface"); + exit(EXIT_FAILURE); + } + + if (!print_f) { + print_local_f = TRUE; + print_global_f = TRUE; + } + + if (!probe_f) { + probe_unrec_f = TRUE; + probe_echo_f = TRUE; + + /* For remote scans we use a single probe type */ + probetype = PROBE_ICMP6_ECHO; + } + + /* + If a Source Address (and *not* a "source prefix") has been specified, we need to incorporate such address + in our iface_data structure. + */ + if (idata.srcaddr_f && !idata.srcprefix_f) { + if (IN6_IS_ADDR_LINKLOCAL(&(idata.srcaddr))) { + idata.ip6_local = idata.srcaddr; + idata.ip6_local_flag = TRUE; + } + else { + if ((idata.ip6_global.prefix[idata.ip6_global.nprefix] = malloc(sizeof(struct prefix_entry))) == NULL) { + if (idata.verbose_f) { + puts("Not enough memory while saving global address"); + } + exit(EXIT_FAILURE); + } + + (idata.ip6_global.prefix[idata.ip6_global.nprefix])->ip6 = idata.srcaddr; + idata.ip6_global.nprefix++; + idata.ip6_global_flag = 1; + } + } + + if ((idata.ip6_local_flag && idata.ip6_global_flag) && !idata.srcaddr_f) + localaddr_f = TRUE; + + if (scan_local_f) { + host_local.nhosts = 0; + host_local.maxhosts = MAX_IPV6_ENTRIES; + host_local.host = host_locals; + + if (probe_echo_f) { + if (multi_scan_local(idata.pfd, &idata, &(idata.ip6_local), PROBE_ICMP6_ECHO, ALL_NODES_MULTICAST_ADDR, + &host_local) == -1) { + if (idata.verbose_f) + puts("Error while learning link-local addresses with ICMPv6 Echo Requests"); + + exit(EXIT_FAILURE); + } + } + + if (probe_unrec_f) { + if (multi_scan_local(idata.pfd, &idata, &(idata.ip6_local), PROBE_UNREC_OPT, ALL_NODES_MULTICAST_ADDR, + &host_local) == -1) { + if (idata.verbose_f) + puts("Error while learning link-local addresses with Unrecognized options"); + + exit(EXIT_FAILURE); + } + } + + if (print_local_f) { + if (idata.verbose_f) + puts("Link-local addresses:"); + + if (print_unique_f) { + if (print_unique_host_entries(&host_local, print_type) == -1) { + if (idata.verbose_f) + puts("Error while printing link-local addresses"); + + exit(EXIT_FAILURE); + } + } + else { + if (print_host_entries(&host_local, print_type) == -1) { + if (idata.verbose_f) + puts("Error while printing link-local addresses"); + + exit(EXIT_FAILURE); + } + } + } + + if (print_global_f) { + host_global.nhosts = 0; + host_global.maxhosts = MAX_IPV6_ENTRIES; + host_global.host = host_globals; + + if (probe_echo_f) { + if (find_local_globals(idata.pfd, &idata, PROBE_ICMP6_ECHO, ALL_NODES_MULTICAST_ADDR, &host_global) == + -1) { + if (idata.verbose_f) + puts("Error while learning link-local addresses with ICMPv6 Echo Requests"); + + exit(EXIT_FAILURE); + } + } + + if (probe_unrec_f) { + if (find_local_globals(idata.pfd, &idata, PROBE_UNREC_OPT, ALL_NODES_MULTICAST_ADDR, &host_global) == + -1) { + if (idata.verbose_f) + puts("Error while learning link-local addresses with Unrecognized options"); + + exit(EXIT_FAILURE); + } + } + + host_candidate.nhosts = 0; + host_candidate.maxhosts = MAX_IPV6_ENTRIES; + host_candidate.host = host_candidates; + + if (create_candidate_globals(&idata, &host_local, &host_global, &host_candidate) == -1) { + if (idata.verbose_f) + puts("Error while creating candidate global addresses"); + + exit(EXIT_FAILURE); + } + + if (validate_host_entries(idata.pfd, &idata, &host_candidate, &host_global) == -1) { + if (idata.verbose_f) + puts("Error while validating global entries"); + + exit(EXIT_FAILURE); + } + + if (idata.verbose_f) + puts("\nGlobal addresses:"); + + if (print_unique_f) { + if (print_unique_host_entries(&host_global, print_type) == -1) { + if (idata.verbose_f) + puts("Error while printing global addresses"); + + exit(EXIT_FAILURE); + } + } + else { + if (print_host_entries(&host_global, print_type) == -1) { + if (idata.verbose_f) + puts("Error while printing global addresses"); + + exit(EXIT_FAILURE); + } + } + } + } + + /* Perform a port-scan */ + else if (portscan_f) { + /* Smart entries are the first ones to be included */ + if (smart_list.ntarget) { + if (!load_smart_entries(&scan_list, &smart_list)) { + puts("Couldn't load smart entries"); + exit(EXIT_FAILURE); + } + } + + if (tgt_knowniids_f) { + if (!load_knowniid_entries(&scan_list, &prefix_list, &iid_list)) { + puts("Couldn't load known IID IPv6 addresses"); + exit(EXIT_FAILURE); + } + } + + if (tgt_knowniidsfile_f) { + if (!load_knowniidfile_entries(&scan_list, &prefix_list, knowniids_fp)) { + puts("Couldn't load known IID IPv6 addresses"); + exit(EXIT_FAILURE); + } + + fclose(knowniids_fp); + } + + if (tgt_portembedded_f) { + for (i = 0; i < prefix_list.ntarget; i++) { + if (!load_embeddedport_entries(&scan_list, prefix_list.target[i])) { + puts("Couldn't load embedded-port IPv6 addresses"); + exit(EXIT_FAILURE); + } + } + } + + if (tgt_lowbyte_f) { + for (i = 0; i < prefix_list.ntarget; i++) { + if (!load_lowbyte_entries(&scan_list, prefix_list.target[i])) { + puts("Couldn't load prefixes for low-byte IPv6 addresses"); + exit(EXIT_FAILURE); + } + } + } + + if (tgt_ipv4mapped32_f) { + for (i = 0; i < prefix_list.ntarget; i++) { + if (!load_ipv4mapped32_entries(&scan_list, prefix_list.target[i], &v4host)) { + puts("Couldn't load prefixes for IPv4-embeded (32-bit) IPv6 addresses"); + exit(EXIT_FAILURE); + } + } + } + + if (tgt_ipv4mapped64_f) { + for (i = 0; i < prefix_list.ntarget; i++) { + if (!load_ipv4mapped64_entries(&scan_list, prefix_list.target[i], &v4host)) { + puts("Couldn't load prefixes for IPv4-embeded (64-bit) IPv6 addresses"); + exit(EXIT_FAILURE); + } + } + } + + if (tgt_vm_f) { + for (i = 0; i < prefix_list.ntarget; i++) { + if (!load_vm_entries(&scan_list, prefix_list.target[i], &v4host)) { + puts("Couldn't load prefix for IEEE OUI"); + exit(EXIT_FAILURE); + } + } + } + + if (tgt_oui_f) { + for (i = 0; i < prefix_list.ntarget; i++) { + if (!load_oui_entries(&scan_list, prefix_list.target[i], &oui)) { + puts("Couldn't load prefix for IEEE OUI"); + exit(EXIT_FAILURE); + } + } + } + + if (tgt_vendor_f) { + for (i = 0; i < prefix_list.ntarget; i++) { + if (!load_vendor_entries(&scan_list, prefix_list.target[i], vendor)) { + puts("Couldn't load prefixes for the specified vendor"); + exit(EXIT_FAILURE); + } + } + } + + if (tgt_bruteforce_f) { + for (i = 0; i < prefix_list.ntarget; i++) { + if (!load_bruteforce_entries(&scan_list, prefix_list.target[i])) { + puts("Couldn't load prefixes for the specified destination prefix"); + exit(EXIT_FAILURE); + } + } + } + + /* scan_list.ctarget= scan_list.first; */ + + puts(SI6_TOOLKIT); + puts("scan6: An advanced IPv6 scanning tool\n"); + + if (idata.verbose_f && !bps_f && !pps_f) { + puts("Rate-limiting probe packets to 1000 pps (override with the '-r' option if necessary)"); + } + + if (idata.verbose_f) { + printf("Target address ranges (%d)\n", scan_list.ntarget); + + if (!print_scan_entries(&scan_list)) { + puts("Error while printing target address ranges"); + exit(EXIT_FAILURE); + } + } + + if (!scan_local_f && !idata.ip6_global_flag) { + if (idata.verbose_f) { + puts("Cannot obtain a global address to scan remote network"); + } + + exit(EXIT_FAILURE); + } + + if (idata.verbose_f) { + if (tcp_port_list.nport) { + printf("Target TCP ports: "); + print_port_entries(&tcp_port_list); + puts(""); + } + + if (udp_port_list.nport) { + printf("Target UDP ports: "); + print_port_entries(&udp_port_list); + puts(""); + } + } + + if (tcp_port_list.nport) { + if (udp_port_list.nport) { + /* Allow both TCP and UDP packets */ + if (pcap_compile(idata.pfd, &pcap_filter, PCAP_TCP_UDP_NSNA_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == + -1) { + if (idata.verbose_f > 1) + printf("pcap_compile(): %s\n", pcap_geterr(idata.pfd)); + + exit(EXIT_FAILURE); + } + } + else { + /* Allow only TCP packets */ + if (pcap_compile(idata.pfd, &pcap_filter, PCAP_TCP_NSNA_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1) { + if (idata.verbose_f > 1) + printf("pcap_compile(): %s\n", pcap_geterr(idata.pfd)); + + exit(EXIT_FAILURE); + } + } + } + else { + if (udp_port_list.nport) { + /* Allow only UDP packets */ + if (pcap_compile(idata.pfd, &pcap_filter, PCAP_UDP_NSNA_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1) { + if (idata.verbose_f > 1) + printf("pcap_compile(): %s\n", pcap_geterr(idata.pfd)); + + exit(EXIT_FAILURE); + } + } + /* There is no "else" here, since port scanning is triggered by specifying some proto/port */ + } + + /* Set initial contents of the attack packet */ + init_packet_data(&idata); + + /* + if(pcap_setfilter(idata.pfd, &pcap_filter) == -1){ + if(idata.verbose_f>1) + printf("pcap_setfilter(): %s\n", pcap_geterr(idata.pfd)); + + exit(EXIT_FAILURE); + } + */ + pcap_freecode(&pcap_filter); + + FD_ZERO(&sset); + FD_SET(idata.fd, &sset); + + /* One loop for each address */ + + nomoreaddr_f = FALSE; + + while (!nomoreaddr_f) { + if (tcp_port_list.nport) { + pscantype = IPPROTO_TCP; + port_list = &tcp_port_list; + port_results = tcp_results; + } + else if (udp_port_list.nport) { + pscantype = IPPROTO_UDP; + port_list = &udp_port_list; + port_results = udp_results; + } + else { + /* Should never happen */ + puts("Error: Port scan selected, but no target TCP or UDP ports"); + } + + endpscan_f = FALSE; + end_f = FALSE; + donesending_f = FALSE; + + /* Check whether the current scan_entry is within range. Otherwise, get the next target */ + if (!is_target_in_range(&scan_list)) { + if (!get_next_target(&scan_list)) { + /* donesending_f=TRUE; */ + nomoreaddr_f = TRUE; + continue; + } + } + + if (tcp_port_list.nport) { + /* Initialize port scan results for TCP (default to filtered) */ + for (i = 0; i < MAX_PORT_ENTRIES; i++) + tcp_results[i] = PORT_FILTERED; + } + + if (udp_port_list.nport) { + /* Initialize port scan results for UDP (default to open) */ + for (i = 0; i < MAX_PORT_ENTRIES; i++) + udp_results[i] = PORT_OPEN; + } + + /* Reset the port entries */ + if (tcp_port_list.nport) + reset_port_list(&tcp_port_list); + + if (udp_port_list.nport) + reset_port_list(&udp_port_list); + + print_ipv6_address("\nPort scan report for: ", &(scan_list.target[scan_list.ctarget]->cur.in6_addr)); + puts("PORT STATE SERVICE"); + + /* endpscan_f is set when all protocols have been scanned */ + while (!endpscan_f) { + lastprobe.tv_sec = 0; + lastprobe.tv_usec = 0; + idata.pending_write_f = TRUE; + + /* end_f is set when donesending_f and proper time has elapsed */ + while (!end_f) { + rset = sset; + wset = sset; + eset = sset; + + if (!donesending_f) { + timeout.tv_sec = pktinterval / 1000000; + timeout.tv_usec = pktinterval % 1000000; + } + else { +#if defined(sun) || defined(__sun) || defined(__linux__) + timeout.tv_sec = pktinterval / 1000000; + timeout.tv_usec = pktinterval % 1000000; +#else + timeout.tv_usec = 0; + timeout.tv_sec = PSCAN_TIMEOUT; +#endif + } + + /* + Check for readability and exceptions. We only check for writeability if there is pending + data to send (the pcap descriptor will usually be writeable!). + */ + if ((sel = select(idata.fd + 1, &rset, (idata.pending_write_f ? &wset : NULL), &eset, &timeout)) == + -1) { + if (errno == EINTR) { + continue; + } + else { + perror("scan6:"); + exit(EXIT_FAILURE); + } + } + + if (gettimeofday(&curtime, NULL) == -1) { + if (idata.verbose_f) + perror("scan6"); + + exit(EXIT_FAILURE); + } + + /* Check whether we have finished probing all ports */ + if (donesending_f) { + if (is_time_elapsed(&curtime, &lastprobe, SELECT_TIMEOUT * 1000000)) { + end_f = TRUE; + } + } + +#if !defined(sun) && !defined(__sun) && !defined(__linux__) + /* + If we didn't check for writeability in the previous call to select(), we must do it now. + Otherwise, we might block when trying to send a packet. + */ + if (!donesending_f && !idata.pending_write_f) { + wset = sset; + + timeout.tv_usec = 0; + timeout.tv_sec = 0; + + if ((sel = select(idata.fd + 1, NULL, &wset, NULL, &timeout)) == -1) { + if (errno == EINTR) { + continue; + } + else { + perror("scan6:"); + exit(EXIT_FAILURE); + } + } + + idata.pending_write_f = TRUE; + } +#endif -/* - if(pcap_setfilter(idata.pfd, &pcap_filter) == -1){ - if(idata.verbose_f>1) - printf("pcap_setfilter(): %s\n", pcap_geterr(idata.pfd)); - - exit(EXIT_FAILURE); - } -*/ - pcap_freecode(&pcap_filter); - - FD_ZERO(&sset); - FD_SET(idata.fd, &sset); - - - /* One loop for each address */ - - nomoreaddr_f= FALSE; - - while(!nomoreaddr_f){ - if(tcp_port_list.nport){ - pscantype= IPPROTO_TCP; - port_list= &tcp_port_list; - port_results= tcp_results; - } - else if(udp_port_list.nport){ - pscantype= IPPROTO_UDP; - port_list= &udp_port_list; - port_results= udp_results; - } - else{ - /* Should never happen */ - puts("Error: Port scan selected, but no target TCP or UDP ports"); - } - - endpscan_f= FALSE; - end_f= FALSE; - donesending_f= FALSE; - - /* Check whether the current scan_entry is within range. Otherwise, get the next target */ - if( !is_target_in_range(&scan_list)){ - if(!get_next_target(&scan_list)){ - /* donesending_f=TRUE; */ - nomoreaddr_f= TRUE; - continue; - } - } - - if(tcp_port_list.nport){ - /* Initialize port scan results for TCP (default to filtered) */ - for(i=0; i< MAX_PORT_ENTRIES; i++) - tcp_results[i]= PORT_FILTERED; - } - - if(udp_port_list.nport){ - /* Initialize port scan results for UDP (default to open) */ - for(i=0; i< MAX_PORT_ENTRIES; i++) - udp_results[i]= PORT_OPEN; - } - - /* Reset the port entries */ - if(tcp_port_list.nport) - reset_port_list(&tcp_port_list); - - if(udp_port_list.nport) - reset_port_list(&udp_port_list); - - print_ipv6_address("\nPort scan report for: ", &(scan_list.target[scan_list.ctarget]->cur.in6_addr)); - puts("PORT STATE SERVICE"); - - /* endpscan_f is set when all protocols have been scanned */ - while(!endpscan_f){ - lastprobe.tv_sec= 0; - lastprobe.tv_usec=0; - idata.pending_write_f=TRUE; - - /* end_f is set when donesending_f and proper time has elapsed */ - while(!end_f){ - rset= sset; - wset= sset; - eset= sset; - - if(!donesending_f){ - timeout.tv_sec= pktinterval / 1000000 ; - timeout.tv_usec= pktinterval % 1000000; - } - else{ - #if defined(sun) || defined(__sun) || defined(__linux__) - timeout.tv_sec= pktinterval / 1000000 ; - timeout.tv_usec= pktinterval % 1000000; - #else - timeout.tv_usec=0; - timeout.tv_sec= PSCAN_TIMEOUT; - #endif - } - - /* - Check for readability and exceptions. We only check for writeability if there is pending data - to send (the pcap descriptor will usually be writeable!). - */ - if((sel=select(idata.fd+1, &rset, (idata.pending_write_f?&wset:NULL), &eset, &timeout)) == -1){ - if(errno == EINTR){ - continue; - } - else{ - perror("scan6:"); - exit(EXIT_FAILURE); - } - } - - if(gettimeofday(&curtime, NULL) == -1){ - if(idata.verbose_f) - perror("scan6"); - - exit(EXIT_FAILURE); - } - - /* Check whether we have finished probing all ports */ - if(donesending_f){ - if(is_time_elapsed(&curtime, &lastprobe, SELECT_TIMEOUT * 1000000)){ - end_f=TRUE; - } - } - - #if !defined(sun) && !defined(__sun) && !defined(__linux__) - /* - If we didn't check for writeability in the previous call to select(), we must do it now. Otherwise, we might - block when trying to send a packet. - */ - if(!donesending_f && !idata.pending_write_f){ - wset= sset; - - timeout.tv_usec=0; - timeout.tv_sec= 0; - - if( (sel=select(idata.fd+1, NULL, &wset, NULL, &timeout)) == -1){ - if(errno == EINTR){ - continue; - } - else{ - perror("scan6:"); - exit(EXIT_FAILURE); - } - } - - idata.pending_write_f= TRUE; - } - #endif - - - #if defined(sun) || defined(__sun) || defined(__linux__) - if(TRUE){ - #else - if(sel && FD_ISSET(idata.fd, &rset)){ - #endif - /* Must process incoming packet */ - error_f=FALSE; - - if((result=pcap_next_ex(idata.pfd, &pkthdr, &pktdata)) == -1){ - if(idata.verbose_f) - printf("Error while reading packet in main loop: pcap_next_ex(): %s", pcap_geterr(idata.pfd)); - - exit(EXIT_FAILURE); - } - - if(result == 1 && pktdata != NULL){ - pkt_ether = (struct ether_header *) pktdata; - pkt_ipv6 = (struct ip6_hdr *)((char *) pkt_ether + idata.linkhsize); - pkt_end = (unsigned char *) pktdata + pkthdr->caplen; - - - if( (pkt_end - pktdata) < (idata.linkhsize + MIN_IPV6_HLEN)){ - continue; - } - - /* Skip IPv6 EHs if present */ - ulhtype= pkt_ipv6->ip6_nxt; - pkt_eh= (struct ip6_eh *) ((char *) pkt_ipv6 + sizeof(struct ip6_hdr)); - - droppacket_f= FALSE; - - while(ulhtype != IPPROTO_ICMPV6 && ulhtype != IPPROTO_TCP && ulhtype != IPPROTO_UDP && !droppacket_f){ - if(ulhtype == IPPROTO_FRAGMENT){ - if( ((unsigned char *)pkt_eh + sizeof(struct ip6_frag)) > pkt_end){ - droppacket_f= TRUE; - break; - } - - fh= (struct ip6_frag *) ((char *) pkt_eh); - - if(fh->ip6f_offlg & IP6F_OFF_MASK){ - droppacket_f= TRUE; - break; - } - - ulhtype= fh->ip6f_nxt; - pkt_eh = (struct ip6_eh *) ((char *) fh + sizeof(struct ip6_frag)); - } - else{ - if( ((unsigned char *)pkt_eh + sizeof(struct ip6_eh)) > pkt_end){ - droppacket_f=TRUE; - break; - } - - ulhtype= pkt_eh->eh_nxt; - pkt_eh= (struct ip6_eh *) ( (char *) pkt_eh + (pkt_eh->eh_len + 1) * 8); - } - - if( (unsigned char *)pkt_eh >= pkt_end){ - droppacket_f= TRUE; - break; - } - } - - if(droppacket_f){ - continue; - } - - pkt_icmp6 = (struct icmp6_hdr *) ((char *) pkt_eh); - pkt_tcp= (struct tcp_hdr *) ((char *) pkt_eh); - pkt_udp= (struct udp_hdr *) ((char *) pkt_eh); - pkt_ns= (struct nd_neighbor_solicit *) ((char *) pkt_eh); - - if(ulhtype == IPPROTO_ICMPV6){ - if( idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK) && pkt_icmp6->icmp6_type == ND_NEIGHBOR_SOLICIT){ - if( (pkt_end - (unsigned char *) pkt_ns) < sizeof(struct nd_neighbor_solicit)) - continue; - - /* - If the addresses that we're using are not actually configured on the local system - (i.e., they are "spoofed", we must check whether it is a Neighbor Solicitation for - one of our addresses, and respond with a Neighbor Advertisement. Otherwise, the kernel - will take care of that. - */ - if(is_ip6_in_address_list(&(idata.ip6_global), &(pkt_ns->nd_ns_target)) || \ - is_eq_in6_addr(&(pkt_ns->nd_ns_target), &(idata.ip6_local))){ - if(send_neighbor_advert(&idata, idata.pfd, pktdata) == -1){ - if(idata.verbose_f) - puts("Error sending Neighbor Advertisement message"); - - exit(EXIT_FAILURE); - } - } - } - else if(pscantype == IPPROTO_UDP && pkt_icmp6->icmp6_type == ICMP6_DST_UNREACH && \ - pkt_icmp6->icmp6_code == ICMP6_DST_UNREACH_NOPORT){ - - /* We are interested in the embedded payload */ - pkt_ipv6= (struct ip6_hdr *) ((char *) pkt_icmp6 + sizeof(struct icmp6_hdr)); - - if( ((unsigned char *)pkt_ipv6 + sizeof(struct ip6_hdr)) > pkt_end){ - continue; - } - - if(!is_eq_in6_addr(&(pkt_ipv6->ip6_dst), &(idata.dstaddr))){ - continue; - } - - ulhtype= pkt_ipv6->ip6_nxt; - pkt_eh= (struct ip6_eh *) ((char *) pkt_ipv6 + sizeof(struct ip6_hdr)); - - droppacket_f= FALSE; - - while(ulhtype != IPPROTO_ICMPV6 && ulhtype != IPPROTO_TCP && ulhtype != IPPROTO_UDP && !droppacket_f){ - if(ulhtype == IPPROTO_FRAGMENT){ - if( ((unsigned char *)pkt_eh + sizeof(struct ip6_frag)) > pkt_end){ - droppacket_f= TRUE; - break; - } - - fh= (struct ip6_frag *) ((char *) pkt_eh); - - if(fh->ip6f_offlg & IP6F_OFF_MASK){ - droppacket_f= TRUE; - break; - } - - ulhtype= fh->ip6f_nxt; - pkt_eh = (struct ip6_eh *) ((char *) fh + sizeof(struct ip6_frag)); - } - else{ - /* If the EH is smaller than the minimum EH, we drop the packet */ - if( ((unsigned char *)pkt_eh + sizeof(struct ip6_eh)) > pkt_end){ - droppacket_f=TRUE; - break; - } - - ulhtype= pkt_eh->eh_nxt; - pkt_eh= (struct ip6_eh *) ( (char *) pkt_eh + (pkt_eh->eh_len + 1) * 8); - } - - if( (unsigned char *)pkt_eh >= pkt_end){ - droppacket_f= TRUE; - break; - } - } - - if(droppacket_f || ulhtype != IPPROTO_UDP){ - continue; - } - - pkt_udp= (struct udp_hdr *) ((char *) pkt_eh); - port_results[ntohs(pkt_udp->uh_dport)] = PORT_CLOSED; - } - } - /* We only bother to process TCP segments if we are currently sending TCP segments */ - else if(pscantype== IPPROTO_TCP && ulhtype == IPPROTO_TCP){ - if(!is_eq_in6_addr(&(idata.dstaddr), &(pkt_ipv6->ip6_src))) - continue; - - if(srcport_f){ - if(pkt_tcp->th_dport != htons(srcport)) - continue; - } - - if(in_chksum(pkt_ipv6, pkt_tcp, pkt_end-((unsigned char *)pkt_tcp), IPPROTO_TCP) != 0) - continue; - - /* Record the port number -- XXX might use the port-setting techniques from path6 */ - if(pkt_tcp->th_flags & TH_RST){ - port_results[ntohs(pkt_tcp->th_sport)] = PORT_CLOSED; - } - else if(pkt_tcp->th_flags & TH_SYN){ - port_results[ntohs(pkt_tcp->th_sport)] = PORT_OPEN; - } - } - } - } - - if(!donesending_f && !idata.pending_write_f && is_time_elapsed(&curtime, &lastprobe, pktinterval)){ - idata.pending_write_f=TRUE; - continue; - } - - #if defined(sun) || defined(__sun) || defined(__linux__) - if(!donesending_f && idata.pending_write_f){ - #else - if(!donesending_f && idata.pending_write_f && FD_ISSET(idata.fd, &wset)){ - #endif - idata.pending_write_f=FALSE; - - /* Check whether the current scan_entry is within range. Otherwise, get the next target */ - if( !is_port_in_range(port_list)){ - if(!get_next_port(port_list)){ - if(gettimeofday(&lastprobe, NULL) == -1){ - if(idata.verbose_f) - perror("scan6"); - - exit(EXIT_FAILURE); - } - - donesending_f=TRUE; - continue; - } - } - - if(!send_pscan_probe(&idata, &scan_list, port_list, &(idata.srcaddr), pscantype)){ - exit(EXIT_FAILURE); - } - - if(gettimeofday(&lastprobe, NULL) == -1){ - if(idata.verbose_f) - perror("scan6"); - - exit(EXIT_FAILURE); - } - - if(!get_next_port(port_list)){ - donesending_f=TRUE; - continue; - } - } - - if(FD_ISSET(idata.fd, &eset)){ - if(idata.verbose_f) - puts("scan6: Found exception on libpcap descriptor"); - - exit(EXIT_FAILURE); - } - } - - if(pscantype== IPPROTO_TCP){ - /* Result types can be PORT_OPEN, PORT_CLOSED, and PORT_FILTERED */ - print_port_scan(port_list, port_results, PORT_OPEN); - } - else{ - print_port_scan(port_list, port_results, PORT_OPEN); - } - - /* We always start with TCP scans (if there are any target ports) */ - if(pscantype== IPPROTO_TCP){ - if(udp_port_list.nport){ - pscantype= IPPROTO_UDP; - port_list= &udp_port_list; - port_results= udp_results; - } - else{ - endpscan_f= TRUE; - } - } - else{ - endpscan_f= TRUE; - } - } - - - if(!get_next_target(&scan_list)){ - nomoreaddr_f=TRUE; - continue; - } - - puts(""); - } - - exit(EXIT_SUCCESS); - } - /* Remote scan */ - else{ - /* Smart entries are the first ones to be included */ - if(smart_list.ntarget){ - if(!load_smart_entries(&scan_list, &smart_list)){ - puts("Couldn't load smart entries"); - exit(EXIT_FAILURE); - } - } - - if(tgt_knowniids_f){ - if(!load_knowniid_entries(&scan_list, &prefix_list, &iid_list)){ - puts("Couldn't load known IID IPv6 addresses"); - exit(EXIT_FAILURE); - } - } - - if(tgt_knowniidsfile_f){ - if(!load_knowniidfile_entries(&scan_list, &prefix_list, knowniids_fp)){ - puts("Couldn't load known IID IPv6 addresses"); - exit(EXIT_FAILURE); - } - - fclose(knowniids_fp); - } - - if(tgt_portembedded_f){ - for(i=0; i < prefix_list.ntarget; i++){ - if(!load_embeddedport_entries(&scan_list, prefix_list.target[i])){ - puts("Couldn't load embedded-port IPv6 addresses"); - exit(EXIT_FAILURE); - } - } - } - - if(tgt_lowbyte_f){ - for(i=0; i < prefix_list.ntarget; i++){ - if(!load_lowbyte_entries(&scan_list, prefix_list.target[i])){ - puts("Couldn't load prefixes for low-byte IPv6 addresses"); - exit(EXIT_FAILURE); - } - } - } - - if(tgt_ipv4mapped32_f){ - for(i=0; i < prefix_list.ntarget; i++){ - if(!load_ipv4mapped32_entries(&scan_list, prefix_list.target[i], &v4host)){ - puts("Couldn't load prefixes for IPv4-embeded (32-bit) IPv6 addresses"); - exit(EXIT_FAILURE); - } - } - } - - if(tgt_ipv4mapped64_f){ - for(i=0; i < prefix_list.ntarget; i++){ - if(!load_ipv4mapped64_entries(&scan_list, prefix_list.target[i], &v4host)){ - puts("Couldn't load prefixes for IPv4-embeded (64-bit) IPv6 addresses"); - exit(EXIT_FAILURE); - } - } - } - - if(tgt_vm_f){ - for(i=0; i < prefix_list.ntarget; i++){ - if(!load_vm_entries(&scan_list, prefix_list.target[i], &v4host)){ - puts("Couldn't load prefix for IEEE OUI"); - exit(EXIT_FAILURE); - } - } - } - - if(tgt_oui_f){ - for(i=0; i < prefix_list.ntarget; i++){ - if(!load_oui_entries(&scan_list, prefix_list.target[i], &oui)){ - puts("Couldn't load prefix for IEEE OUI"); - exit(EXIT_FAILURE); - } - } - } - - if(tgt_vendor_f){ - for(i=0; i < prefix_list.ntarget; i++){ - if(!load_vendor_entries(&scan_list, prefix_list.target[i], vendor)){ - puts("Couldn't load prefixes for the specified vendor"); - exit(EXIT_FAILURE); - } - } - } - - if(tgt_bruteforce_f){ - for(i=0; i < prefix_list.ntarget; i++){ - if(!load_bruteforce_entries(&scan_list, prefix_list.target[i])){ - puts("Couldn't load prefixes for the specified destination prefix"); - exit(EXIT_FAILURE); - } - } - } - - /* scan_list.ctarget= scan_list.first; */ - - if(idata.verbose_f && !bps_f && !pps_f){ - puts("Rate-limiting probe packets to 1000 pps (override with the '-r' option if necessary)"); - } - - if(idata.verbose_f){ - printf("Target address ranges (%d)\n", scan_list.ntarget); - - if(!print_scan_entries(&scan_list)){ - puts("Error while printing target address ranges"); - exit(EXIT_FAILURE); - } - } - - if(!scan_local_f && !idata.ip6_global_flag){ - if(idata.verbose_f){ - puts("Cannot obtain a global address to scan remote network"); - } - - exit(EXIT_FAILURE); - } - - switch(probetype){ - case PROBE_ICMP6_ECHO: - if(pcap_compile(idata.pfd, &pcap_filter, PCAP_ICMPV6_ERQNSNA_FILTER, 0, PCAP_NETMASK_UNKNOWN) == -1){ - if(idata.verbose_f>1) - printf("pcap_compile(): %s\n", pcap_geterr(idata.pfd)); - - exit(EXIT_FAILURE); - } - break; - - case PROBE_UNREC_OPT: - if(pcap_compile(idata.pfd, &pcap_filter, PCAP_ICMPV6_ERRORNSNA_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1){ - if(idata.verbose_f>1) - printf("pcap_compile(): %s\n", pcap_geterr(idata.pfd)); - - exit(EXIT_FAILURE); - } - break; - - case PROBE_TCP: - if(pcap_compile(idata.pfd, &pcap_filter, PCAP_TCP_NSNA_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1){ - if(idata.verbose_f>1) - printf("pcap_compile(): %s\n", pcap_geterr(idata.pfd)); - - exit(EXIT_FAILURE); - } - break; - } - - if(pcap_setfilter(idata.pfd, &pcap_filter) == -1){ - if(idata.verbose_f>1) - printf("pcap_setfilter(): %s\n", pcap_geterr(idata.pfd)); - - exit(EXIT_FAILURE); - } - - pcap_freecode(&pcap_filter); - - if(idata.verbose_f) - puts("\nAlive nodes:"); - - FD_ZERO(&sset); - FD_SET(idata.fd, &sset); - - lastprobe.tv_sec= 0; - lastprobe.tv_usec=0; - idata.pending_write_f=TRUE; - - while(!end_f){ - rset= sset; - wset= sset; - eset= sset; - - if(!donesending_f){ - timeout.tv_sec= pktinterval / 1000000 ; - timeout.tv_usec= pktinterval % 1000000; - } - else{ #if defined(sun) || defined(__sun) || defined(__linux__) - timeout.tv_sec= pktinterval / 1000000 ; - timeout.tv_usec= pktinterval % 1000000; + if (TRUE) { +#else + if (sel && FD_ISSET(idata.fd, &rset)) { +#endif + /* Must process incoming packet */ + error_f = FALSE; + + if ((result = pcap_next_ex(idata.pfd, &pkthdr, &pktdata)) == -1) { + if (idata.verbose_f) + printf("Error while reading packet in main loop: pcap_next_ex(): %s", + pcap_geterr(idata.pfd)); + + exit(EXIT_FAILURE); + } + + if (result == 1 && pktdata != NULL) { + pkt_ether = (struct ether_header *)pktdata; + pkt_ipv6 = (struct ip6_hdr *)((char *)pkt_ether + idata.linkhsize); + pkt_end = (unsigned char *)pktdata + pkthdr->caplen; + + if ((pkt_end - pktdata) < (idata.linkhsize + MIN_IPV6_HLEN)) { + continue; + } + + /* Skip IPv6 EHs if present */ + ulhtype = pkt_ipv6->ip6_nxt; + pkt_eh = (struct ip6_eh *)((char *)pkt_ipv6 + sizeof(struct ip6_hdr)); + + droppacket_f = FALSE; + + while (ulhtype != IPPROTO_ICMPV6 && ulhtype != IPPROTO_TCP && ulhtype != IPPROTO_UDP && + !droppacket_f) { + if (ulhtype == IPPROTO_FRAGMENT) { + if (((unsigned char *)pkt_eh + sizeof(struct ip6_frag)) > pkt_end) { + droppacket_f = TRUE; + break; + } + + fh = (struct ip6_frag *)((char *)pkt_eh); + + if (fh->ip6f_offlg & IP6F_OFF_MASK) { + droppacket_f = TRUE; + break; + } + + ulhtype = fh->ip6f_nxt; + pkt_eh = (struct ip6_eh *)((char *)fh + sizeof(struct ip6_frag)); + } + else { + if (((unsigned char *)pkt_eh + sizeof(struct ip6_eh)) > pkt_end) { + droppacket_f = TRUE; + break; + } + + ulhtype = pkt_eh->eh_nxt; + pkt_eh = (struct ip6_eh *)((char *)pkt_eh + (pkt_eh->eh_len + 1) * 8); + } + + if ((unsigned char *)pkt_eh >= pkt_end) { + droppacket_f = TRUE; + break; + } + } + + if (droppacket_f) { + continue; + } + + pkt_icmp6 = (struct icmp6_hdr *)((char *)pkt_eh); + pkt_tcp = (struct tcp_hdr *)((char *)pkt_eh); + pkt_udp = (struct udp_hdr *)((char *)pkt_eh); + pkt_ns = (struct nd_neighbor_solicit *)((char *)pkt_eh); + + if (ulhtype == IPPROTO_ICMPV6) { + if (idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK) && + pkt_icmp6->icmp6_type == ND_NEIGHBOR_SOLICIT) { + if ((pkt_end - (unsigned char *)pkt_ns) < sizeof(struct nd_neighbor_solicit)) + continue; + + /* + If the addresses that we're using are not actually configured on the local + system (i.e., they are "spoofed", we must check whether it is a Neighbor + Solicitation for one of our addresses, and respond with a Neighbor Advertisement. + Otherwise, the kernel will take care of that. + */ + if (is_ip6_in_address_list(&(idata.ip6_global), &(pkt_ns->nd_ns_target)) || + is_eq_in6_addr(&(pkt_ns->nd_ns_target), &(idata.ip6_local))) { + if (send_neighbor_advert(&idata, idata.pfd, pktdata) == -1) { + if (idata.verbose_f) + puts("Error sending Neighbor Advertisement message"); + + exit(EXIT_FAILURE); + } + } + } + else if (pscantype == IPPROTO_UDP && pkt_icmp6->icmp6_type == ICMP6_DST_UNREACH && + pkt_icmp6->icmp6_code == ICMP6_DST_UNREACH_NOPORT) { + + /* We are interested in the embedded payload */ + pkt_ipv6 = (struct ip6_hdr *)((char *)pkt_icmp6 + sizeof(struct icmp6_hdr)); + + if (((unsigned char *)pkt_ipv6 + sizeof(struct ip6_hdr)) > pkt_end) { + continue; + } + + if (!is_eq_in6_addr(&(pkt_ipv6->ip6_dst), &(idata.dstaddr))) { + continue; + } + + ulhtype = pkt_ipv6->ip6_nxt; + pkt_eh = (struct ip6_eh *)((char *)pkt_ipv6 + sizeof(struct ip6_hdr)); + + droppacket_f = FALSE; + + while (ulhtype != IPPROTO_ICMPV6 && ulhtype != IPPROTO_TCP && + ulhtype != IPPROTO_UDP && !droppacket_f) { + if (ulhtype == IPPROTO_FRAGMENT) { + if (((unsigned char *)pkt_eh + sizeof(struct ip6_frag)) > pkt_end) { + droppacket_f = TRUE; + break; + } + + fh = (struct ip6_frag *)((char *)pkt_eh); + + if (fh->ip6f_offlg & IP6F_OFF_MASK) { + droppacket_f = TRUE; + break; + } + + ulhtype = fh->ip6f_nxt; + pkt_eh = (struct ip6_eh *)((char *)fh + sizeof(struct ip6_frag)); + } + else { + /* If the EH is smaller than the minimum EH, we drop the packet */ + if (((unsigned char *)pkt_eh + sizeof(struct ip6_eh)) > pkt_end) { + droppacket_f = TRUE; + break; + } + + ulhtype = pkt_eh->eh_nxt; + pkt_eh = (struct ip6_eh *)((char *)pkt_eh + (pkt_eh->eh_len + 1) * 8); + } + + if ((unsigned char *)pkt_eh >= pkt_end) { + droppacket_f = TRUE; + break; + } + } + + if (droppacket_f || ulhtype != IPPROTO_UDP) { + continue; + } + + pkt_udp = (struct udp_hdr *)((char *)pkt_eh); + port_results[ntohs(pkt_udp->uh_dport)] = PORT_CLOSED; + } + } + /* We only bother to process TCP segments if we are currently sending TCP segments */ + else if (pscantype == IPPROTO_TCP && ulhtype == IPPROTO_TCP) { + if (!is_eq_in6_addr(&(idata.dstaddr), &(pkt_ipv6->ip6_src))) + continue; + + if (srcport_f) { + if (pkt_tcp->th_dport != htons(srcport)) + continue; + } + + if (in_chksum(pkt_ipv6, pkt_tcp, pkt_end - ((unsigned char *)pkt_tcp), IPPROTO_TCP) != + 0) + continue; + + /* Record the port number -- XXX might use the port-setting techniques from path6 */ + if (pkt_tcp->th_flags & TH_RST) { + port_results[ntohs(pkt_tcp->th_sport)] = PORT_CLOSED; + } + else if (pkt_tcp->th_flags & TH_SYN) { + port_results[ntohs(pkt_tcp->th_sport)] = PORT_OPEN; + } + } + } + } + + if (!donesending_f && !idata.pending_write_f && + is_time_elapsed(&curtime, &lastprobe, pktinterval)) { + idata.pending_write_f = TRUE; + continue; + } + +#if defined(sun) || defined(__sun) || defined(__linux__) + if (!donesending_f && idata.pending_write_f) { +#else + if (!donesending_f && idata.pending_write_f && FD_ISSET(idata.fd, &wset)) { +#endif + idata.pending_write_f = FALSE; + + /* Check whether the current scan_entry is within range. Otherwise, get the next target */ + if (!is_port_in_range(port_list)) { + if (!get_next_port(port_list)) { + if (gettimeofday(&lastprobe, NULL) == -1) { + if (idata.verbose_f) + perror("scan6"); + + exit(EXIT_FAILURE); + } + + donesending_f = TRUE; + continue; + } + } + + if (!send_pscan_probe(&idata, &scan_list, port_list, &(idata.srcaddr), pscantype)) { + exit(EXIT_FAILURE); + } + + if (gettimeofday(&lastprobe, NULL) == -1) { + if (idata.verbose_f) + perror("scan6"); + + exit(EXIT_FAILURE); + } + + if (!get_next_port(port_list)) { + donesending_f = TRUE; + continue; + } + } + + if (FD_ISSET(idata.fd, &eset)) { + if (idata.verbose_f) + puts("scan6: Found exception on libpcap descriptor"); + + exit(EXIT_FAILURE); + } + } + + if (pscantype == IPPROTO_TCP) { + /* Result types can be PORT_OPEN, PORT_CLOSED, and PORT_FILTERED */ + print_port_scan(port_list, port_results, PORT_OPEN); + } + else { + print_port_scan(port_list, port_results, PORT_OPEN); + } + + /* We always start with TCP scans (if there are any target ports) */ + if (pscantype == IPPROTO_TCP) { + if (udp_port_list.nport) { + pscantype = IPPROTO_UDP; + port_list = &udp_port_list; + port_results = udp_results; + } + else { + endpscan_f = TRUE; + } + } + else { + endpscan_f = TRUE; + } + } + + if (!get_next_target(&scan_list)) { + nomoreaddr_f = TRUE; + continue; + } + + puts(""); + } + + exit(EXIT_SUCCESS); + } + /* Remote scan */ + else { + /* Smart entries are the first ones to be included */ + if (smart_list.ntarget) { + if (!load_smart_entries(&scan_list, &smart_list)) { + puts("Couldn't load smart entries"); + exit(EXIT_FAILURE); + } + } + + if (tgt_knowniids_f) { + if (!load_knowniid_entries(&scan_list, &prefix_list, &iid_list)) { + puts("Couldn't load known IID IPv6 addresses"); + exit(EXIT_FAILURE); + } + } + + if (tgt_knowniidsfile_f) { + if (!load_knowniidfile_entries(&scan_list, &prefix_list, knowniids_fp)) { + puts("Couldn't load known IID IPv6 addresses"); + exit(EXIT_FAILURE); + } + + fclose(knowniids_fp); + } + + if (tgt_portembedded_f) { + for (i = 0; i < prefix_list.ntarget; i++) { + if (!load_embeddedport_entries(&scan_list, prefix_list.target[i])) { + puts("Couldn't load embedded-port IPv6 addresses"); + exit(EXIT_FAILURE); + } + } + } + + if (tgt_lowbyte_f) { + for (i = 0; i < prefix_list.ntarget; i++) { + if (!load_lowbyte_entries(&scan_list, prefix_list.target[i])) { + puts("Couldn't load prefixes for low-byte IPv6 addresses"); + exit(EXIT_FAILURE); + } + } + } + + if (tgt_ipv4mapped32_f) { + for (i = 0; i < prefix_list.ntarget; i++) { + if (!load_ipv4mapped32_entries(&scan_list, prefix_list.target[i], &v4host)) { + puts("Couldn't load prefixes for IPv4-embeded (32-bit) IPv6 addresses"); + exit(EXIT_FAILURE); + } + } + } + + if (tgt_ipv4mapped64_f) { + for (i = 0; i < prefix_list.ntarget; i++) { + if (!load_ipv4mapped64_entries(&scan_list, prefix_list.target[i], &v4host)) { + puts("Couldn't load prefixes for IPv4-embeded (64-bit) IPv6 addresses"); + exit(EXIT_FAILURE); + } + } + } + + if (tgt_vm_f) { + for (i = 0; i < prefix_list.ntarget; i++) { + if (!load_vm_entries(&scan_list, prefix_list.target[i], &v4host)) { + puts("Couldn't load prefix for IEEE OUI"); + exit(EXIT_FAILURE); + } + } + } + + if (tgt_oui_f) { + for (i = 0; i < prefix_list.ntarget; i++) { + if (!load_oui_entries(&scan_list, prefix_list.target[i], &oui)) { + puts("Couldn't load prefix for IEEE OUI"); + exit(EXIT_FAILURE); + } + } + } + + if (tgt_vendor_f) { + for (i = 0; i < prefix_list.ntarget; i++) { + if (!load_vendor_entries(&scan_list, prefix_list.target[i], vendor)) { + puts("Couldn't load prefixes for the specified vendor"); + exit(EXIT_FAILURE); + } + } + } + + if (tgt_bruteforce_f) { + for (i = 0; i < prefix_list.ntarget; i++) { + if (!load_bruteforce_entries(&scan_list, prefix_list.target[i])) { + puts("Couldn't load prefixes for the specified destination prefix"); + exit(EXIT_FAILURE); + } + } + } + + /* scan_list.ctarget= scan_list.first; */ + + if (idata.verbose_f && !bps_f && !pps_f) { + puts("Rate-limiting probe packets to 1000 pps (override with the '-r' option if necessary)"); + } + + if (idata.verbose_f) { + printf("Target address ranges (%d)\n", scan_list.ntarget); + + if (!print_scan_entries(&scan_list)) { + puts("Error while printing target address ranges"); + exit(EXIT_FAILURE); + } + } + + if (!scan_local_f && !idata.ip6_global_flag) { + if (idata.verbose_f) { + puts("Cannot obtain a global address to scan remote network"); + } + + exit(EXIT_FAILURE); + } + + switch (probetype) { + case PROBE_ICMP6_ECHO: + if (pcap_compile(idata.pfd, &pcap_filter, PCAP_ICMPV6_ERQNSNA_FILTER, 0, PCAP_NETMASK_UNKNOWN) == -1) { + if (idata.verbose_f > 1) + printf("pcap_compile(): %s\n", pcap_geterr(idata.pfd)); + + exit(EXIT_FAILURE); + } + break; + + case PROBE_UNREC_OPT: + if (pcap_compile(idata.pfd, &pcap_filter, PCAP_ICMPV6_ERRORNSNA_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == + -1) { + if (idata.verbose_f > 1) + printf("pcap_compile(): %s\n", pcap_geterr(idata.pfd)); + + exit(EXIT_FAILURE); + } + break; + + case PROBE_TCP: + if (pcap_compile(idata.pfd, &pcap_filter, PCAP_TCP_NSNA_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1) { + if (idata.verbose_f > 1) + printf("pcap_compile(): %s\n", pcap_geterr(idata.pfd)); + + exit(EXIT_FAILURE); + } + break; + } + + if (pcap_setfilter(idata.pfd, &pcap_filter) == -1) { + if (idata.verbose_f > 1) + printf("pcap_setfilter(): %s\n", pcap_geterr(idata.pfd)); + + exit(EXIT_FAILURE); + } + + pcap_freecode(&pcap_filter); + + if (idata.verbose_f) + puts("\nAlive nodes:"); + + FD_ZERO(&sset); + FD_SET(idata.fd, &sset); + + lastprobe.tv_sec = 0; + lastprobe.tv_usec = 0; + idata.pending_write_f = TRUE; + + while (!end_f) { + rset = sset; + wset = sset; + eset = sset; + + if (!donesending_f) { + timeout.tv_sec = pktinterval / 1000000; + timeout.tv_usec = pktinterval % 1000000; + } + else { +#if defined(sun) || defined(__sun) || defined(__linux__) + timeout.tv_sec = pktinterval / 1000000; + timeout.tv_usec = pktinterval % 1000000; #else - timeout.tv_usec=0; - timeout.tv_sec= SELECT_TIMEOUT; + timeout.tv_usec = 0; + timeout.tv_sec = SELECT_TIMEOUT; #endif - } + } #ifdef DEBUG -puts("Prior to select()"); + puts("Prior to select()"); #endif - /* - Check for readability and exceptions. We only check for writeability if there is pending data - to send (the pcap descriptor will usually be writeable!). - */ + /* + Check for readability and exceptions. We only check for writeability if there is pending data + to send (the pcap descriptor will usually be writeable!). + */ #if defined(sun) || defined(__sun) || defined(__linux__) - if((sel=select(0, NULL, NULL, NULL, &timeout)) == -1){ + if ((sel = select(0, NULL, NULL, NULL, &timeout)) == -1) { #else - if((sel=select(idata.fd+1, &rset, (idata.pending_write_f?&wset:NULL), &eset, &timeout)) == -1){ + if ((sel = select(idata.fd + 1, &rset, (idata.pending_write_f ? &wset : NULL), &eset, &timeout)) == -1) { #endif - if(errno == EINTR){ - continue; - } - else{ - perror("scan6:"); - exit(EXIT_FAILURE); - } - } + if (errno == EINTR) { + continue; + } + else { + perror("scan6:"); + exit(EXIT_FAILURE); + } + } #ifdef DEBUG -puts("After select()"); + puts("After select()"); #endif - if(gettimeofday(&curtime, NULL) == -1){ - if(idata.verbose_f) - perror("scan6"); - - exit(EXIT_FAILURE); - } - - /* Check whether we have finished probing all targets */ - if(donesending_f){ - /* - If we're not looping, just wait for SELECT_TIMEOUT seconds for any incoming responses. - If we are looping (most likely because we're doing host-tracking, wait for nsleep seconds, and - reset the targets. - */ - if(!loop_f){ - if(is_time_elapsed(&curtime, &lastprobe, SELECT_TIMEOUT * 1000000)){ - end_f=TRUE; - } - } - else{ - if(is_time_elapsed(&curtime, &lastprobe, nsleep * 1000000)){ - reset_scan_list(&scan_list); - donesending_f=FALSE; - continue; - } - } - } - - /* - If we didn't check for writeability in the previous call to select(), we must do it now. Otherwise, we might - block when trying to send a packet. - */ + if (gettimeofday(&curtime, NULL) == -1) { + if (idata.verbose_f) + perror("scan6"); + + exit(EXIT_FAILURE); + } + + /* Check whether we have finished probing all targets */ + if (donesending_f) { + /* + If we're not looping, just wait for SELECT_TIMEOUT seconds for any incoming responses. + If we are looping (most likely because we're doing host-tracking, wait for nsleep seconds, and + reset the targets. + */ + if (!loop_f) { + if (is_time_elapsed(&curtime, &lastprobe, SELECT_TIMEOUT * 1000000)) { + end_f = TRUE; + } + } + else { + if (is_time_elapsed(&curtime, &lastprobe, nsleep * 1000000)) { + reset_scan_list(&scan_list); + donesending_f = FALSE; + continue; + } + } + } + + /* + If we didn't check for writeability in the previous call to select(), we must do it now. Otherwise, we + might block when trying to send a packet. + */ #if !(defined(sun) || defined(__sun) || defined(__linux__)) #ifdef DEBUG -puts("Prior secondary select()"); + puts("Prior secondary select()"); #endif - if(!donesending_f && !idata.pending_write_f){ - wset= sset; - - timeout.tv_usec=0; - timeout.tv_sec= 0; - - if( (sel=select(idata.fd+1, NULL, &wset, NULL, &timeout)) == -1){ - if(errno == EINTR){ - continue; - } - else{ - perror("scan6:"); - exit(EXIT_FAILURE); - } - } - - idata.pending_write_f= TRUE; - continue; - } + if (!donesending_f && !idata.pending_write_f) { + wset = sset; + + timeout.tv_usec = 0; + timeout.tv_sec = 0; + + if ((sel = select(idata.fd + 1, NULL, &wset, NULL, &timeout)) == -1) { + if (errno == EINTR) { + continue; + } + else { + perror("scan6:"); + exit(EXIT_FAILURE); + } + } + + idata.pending_write_f = TRUE; + continue; + } #ifdef DEBUG -puts("After secondary select()"); + puts("After secondary select()"); #endif #endif #if defined(sun) || defined(__sun) || defined(__linux__) - if(TRUE){ + if (TRUE) { #else - if(sel && FD_ISSET(idata.fd, &rset)){ + if (sel && FD_ISSET(idata.fd, &rset)) { #endif - error_f=FALSE; + error_f = FALSE; #ifdef DEBUG -puts("Prior to pcap_next_ex()"); + puts("Prior to pcap_next_ex()"); #endif - if((result=pcap_next_ex(idata.pfd, &pkthdr, &pktdata)) == -1){ - if(idata.verbose_f) - printf("Error while reading packet in main loop: pcap_next_ex(): %s", pcap_geterr(idata.pfd)); + if ((result = pcap_next_ex(idata.pfd, &pkthdr, &pktdata)) == -1) { + if (idata.verbose_f) + printf("Error while reading packet in main loop: pcap_next_ex(): %s", pcap_geterr(idata.pfd)); - exit(EXIT_FAILURE); - } + exit(EXIT_FAILURE); + } #ifdef DEBUG -puts("After to pcap_next_ex()"); + puts("After to pcap_next_ex()"); #endif - if(result == 1 && pktdata != NULL){ - pkt_ether = (struct ether_header *) pktdata; - pkt_ipv6 = (struct ip6_hdr *)((char *) pkt_ether + idata.linkhsize); - pkt_icmp6 = (struct icmp6_hdr *) ((char *) pkt_ipv6 + sizeof(struct ip6_hdr)); - pkt_tcp = (struct tcp_hdr *) ((char *) pkt_ipv6 + sizeof(struct ip6_hdr)); - pkt_ns= (struct nd_neighbor_solicit *) pkt_icmp6; - pkt_end = (unsigned char *) pktdata + pkthdr->caplen; - - if( (pkt_end - pktdata) < (idata.linkhsize + MIN_IPV6_HLEN)) - continue; - - if(pkt_ipv6->ip6_nxt == IPPROTO_ICMPV6){ - if( idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK) && pkt_icmp6->icmp6_type == ND_NEIGHBOR_SOLICIT){ - if( (pkt_end - (unsigned char *) pkt_ns) < sizeof(struct nd_neighbor_solicit)) - continue; - - /* - If the addresses that we're using are not actually configured on the local system - (i.e., they are "spoofed", we must check whether it is a Neighbor Solicitation for - one of our addresses, and respond with a Neighbor Advertisement. Otherwise, the kernel - will take care of that. - */ - if(is_ip6_in_address_list(&(idata.ip6_global), &(pkt_ns->nd_ns_target)) || \ - is_eq_in6_addr(&(pkt_ns->nd_ns_target), &(idata.ip6_local))){ + if (result == 1 && pktdata != NULL) { + pkt_ether = (struct ether_header *)pktdata; + pkt_ipv6 = (struct ip6_hdr *)((char *)pkt_ether + idata.linkhsize); + pkt_icmp6 = (struct icmp6_hdr *)((char *)pkt_ipv6 + sizeof(struct ip6_hdr)); + pkt_tcp = (struct tcp_hdr *)((char *)pkt_ipv6 + sizeof(struct ip6_hdr)); + pkt_ns = (struct nd_neighbor_solicit *)pkt_icmp6; + pkt_end = (unsigned char *)pktdata + pkthdr->caplen; + + if ((pkt_end - pktdata) < (idata.linkhsize + MIN_IPV6_HLEN)) + continue; + + if (pkt_ipv6->ip6_nxt == IPPROTO_ICMPV6) { + if (idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK) && + pkt_icmp6->icmp6_type == ND_NEIGHBOR_SOLICIT) { + if ((pkt_end - (unsigned char *)pkt_ns) < sizeof(struct nd_neighbor_solicit)) + continue; + + /* + If the addresses that we're using are not actually configured on the local system + (i.e., they are "spoofed", we must check whether it is a Neighbor Solicitation for + one of our addresses, and respond with a Neighbor Advertisement. Otherwise, the + kernel will take care of that. + */ + if (is_ip6_in_address_list(&(idata.ip6_global), &(pkt_ns->nd_ns_target)) || + is_eq_in6_addr(&(pkt_ns->nd_ns_target), &(idata.ip6_local))) { #ifdef DEBUG -puts("Prior to send_neighbor_advert()"); + puts("Prior to send_neighbor_advert()"); #endif - if(send_neighbor_advert(&idata, idata.pfd, pktdata) == -1){ - if(idata.verbose_f) - puts("Error sending Neighbor Advertisement message"); + if (send_neighbor_advert(&idata, idata.pfd, pktdata) == -1) { + if (idata.verbose_f) + puts("Error sending Neighbor Advertisement message"); - exit(EXIT_FAILURE); - } + exit(EXIT_FAILURE); + } #ifdef DEBUG -puts("After to send_neighbor_advert()"); + puts("After to send_neighbor_advert()"); #endif - } - } - else if( (probetype == PROBE_ICMP6_ECHO && pkt_icmp6->icmp6_type == ICMP6_ECHO_REPLY) ||\ - (probetype == PROBE_UNREC_OPT && pkt_icmp6->icmp6_type == ICMP6_PARAM_PROB)){ - if(!is_ip6_in_scan_list(&scan_list, &(pkt_ipv6->ip6_src))) - continue; - - if( (pkt_end - (unsigned char *) pkt_icmp6) < sizeof(struct icmp6_hdr)) - continue; - - if(valid_icmp6_response_remote(&idata, &scan_list, probetype, pkthdr, pktdata, buffer)){ - /* Print the Source Address of the incoming packet */ - if(inet_ntop(AF_INET6, &(pkt_ipv6->ip6_src), pv6addr, sizeof(pv6addr)) == NULL){ - if(idata.verbose_f>1) - puts("inet_ntop(): Error converting IPv6 address to presentation format"); - - exit(EXIT_FAILURE); - } - - if(timestamps_f){ - if(gettimeofday(&pcurtime, NULL) == -1){ - if(idata.verbose_f) - perror("scan6"); - - exit(EXIT_FAILURE); - } - - if(localtime_r( (time_t *) &(pcurtime.tv_sec), &pcurtimetm) == NULL){ - if(idata.verbose_f>1) - puts("localtime_r(): Error obtaining local time."); - - exit(EXIT_FAILURE); - } - - if(strftime(date, DATE_STR_LEN, "%a %b %d %T %Y", &pcurtimetm) == 0){ - if(idata.verbose_f>1) - puts("strftime(): Error converting current time to text"); - - exit(EXIT_FAILURE); - } - - printf("%s (%s)\n", pv6addr, date); - } - else{ - printf("%s\n", pv6addr); - } - } - } - } - else if(probetype == PROBE_TCP && pkt_ipv6->ip6_nxt == IPPROTO_TCP){ - if(!is_ip6_in_scan_list(&scan_list, &(pkt_ipv6->ip6_src))) - continue; - - if(srcport_f) - if(pkt_tcp->th_dport != htons(srcport)) - continue; - - if(dstport_f) - if(pkt_tcp->th_sport != htons(dstport)) - continue; - - if(in_chksum(pkt_ipv6, pkt_tcp, pkt_end-((unsigned char *)pkt_tcp), IPPROTO_TCP) != 0) - continue; - - if(inet_ntop(AF_INET6, &(pkt_ipv6->ip6_src), pv6addr, sizeof(pv6addr)) == NULL){ - if(idata.verbose_f>1) - puts("inet_ntop(): Error converting IPv6 address to presentation format"); - - exit(EXIT_FAILURE); - } - - if(timestamps_f){ - if(gettimeofday(&pcurtime, NULL) == -1){ - if(idata.verbose_f) - perror("scan6"); - - exit(EXIT_FAILURE); - } - - if(localtime_r((time_t *) &(pcurtime.tv_sec), &pcurtimetm) == NULL){ - if(idata.verbose_f>1) - puts("localtime_r(): Error obtaining local time."); - - exit(EXIT_FAILURE); - } - - if(strftime(date, DATE_STR_LEN, "%a %b %d %T %Y", &pcurtimetm) == 0){ - if(idata.verbose_f>1) - puts("strftime(): Error converting current time to text"); - - exit(EXIT_FAILURE); - } - - printf("%s (%s)\n", pv6addr, date); - } - else{ - printf("%s\n", pv6addr); - } - } - } - } - - - if(!donesending_f && !idata.pending_write_f && is_time_elapsed(&curtime, &lastprobe, pktinterval)){ - idata.pending_write_f=TRUE; - continue; - } + } + } + else if ((probetype == PROBE_ICMP6_ECHO && pkt_icmp6->icmp6_type == ICMP6_ECHO_REPLY) || + (probetype == PROBE_UNREC_OPT && pkt_icmp6->icmp6_type == ICMP6_PARAM_PROB)) { + if (!is_ip6_in_scan_list(&scan_list, &(pkt_ipv6->ip6_src))) + continue; + + if ((pkt_end - (unsigned char *)pkt_icmp6) < sizeof(struct icmp6_hdr)) + continue; + + if (valid_icmp6_response_remote(&idata, &scan_list, probetype, pkthdr, pktdata, buffer)) { + /* Print the Source Address of the incoming packet */ + if (inet_ntop(AF_INET6, &(pkt_ipv6->ip6_src), pv6addr, sizeof(pv6addr)) == NULL) { + if (idata.verbose_f > 1) + puts("inet_ntop(): Error converting IPv6 address to presentation format"); + + exit(EXIT_FAILURE); + } + + if (timestamps_f) { + if (gettimeofday(&pcurtime, NULL) == -1) { + if (idata.verbose_f) + perror("scan6"); + + exit(EXIT_FAILURE); + } + + if (localtime_r((time_t *)&(pcurtime.tv_sec), &pcurtimetm) == NULL) { + if (idata.verbose_f > 1) + puts("localtime_r(): Error obtaining local time."); + + exit(EXIT_FAILURE); + } + + if (strftime(date, DATE_STR_LEN, "%a %b %d %T %Y", &pcurtimetm) == 0) { + if (idata.verbose_f > 1) + puts("strftime(): Error converting current time to text"); + + exit(EXIT_FAILURE); + } + + printf("%s (%s)\n", pv6addr, date); + } + else { + printf("%s\n", pv6addr); + } + } + } + } + else if (probetype == PROBE_TCP && pkt_ipv6->ip6_nxt == IPPROTO_TCP) { + if (!is_ip6_in_scan_list(&scan_list, &(pkt_ipv6->ip6_src))) + continue; + + if (srcport_f) + if (pkt_tcp->th_dport != htons(srcport)) + continue; + + if (dstport_f) + if (pkt_tcp->th_sport != htons(dstport)) + continue; + + if (in_chksum(pkt_ipv6, pkt_tcp, pkt_end - ((unsigned char *)pkt_tcp), IPPROTO_TCP) != 0) + continue; + + if (inet_ntop(AF_INET6, &(pkt_ipv6->ip6_src), pv6addr, sizeof(pv6addr)) == NULL) { + if (idata.verbose_f > 1) + puts("inet_ntop(): Error converting IPv6 address to presentation format"); + + exit(EXIT_FAILURE); + } + + if (timestamps_f) { + if (gettimeofday(&pcurtime, NULL) == -1) { + if (idata.verbose_f) + perror("scan6"); + + exit(EXIT_FAILURE); + } + + if (localtime_r((time_t *)&(pcurtime.tv_sec), &pcurtimetm) == NULL) { + if (idata.verbose_f > 1) + puts("localtime_r(): Error obtaining local time."); + + exit(EXIT_FAILURE); + } + + if (strftime(date, DATE_STR_LEN, "%a %b %d %T %Y", &pcurtimetm) == 0) { + if (idata.verbose_f > 1) + puts("strftime(): Error converting current time to text"); + + exit(EXIT_FAILURE); + } + + printf("%s (%s)\n", pv6addr, date); + } + else { + printf("%s\n", pv6addr); + } + } + } + } + + if (!donesending_f && !idata.pending_write_f && is_time_elapsed(&curtime, &lastprobe, pktinterval)) { + idata.pending_write_f = TRUE; + continue; + } #if defined(sun) || defined(__sun) || defined(__linux__) - if(!donesending_f && idata.pending_write_f){ + if (!donesending_f && idata.pending_write_f) { #else - if(!donesending_f && idata.pending_write_f && FD_ISSET(idata.fd, &wset)){ + if (!donesending_f && idata.pending_write_f && FD_ISSET(idata.fd, &wset)) { #endif - idata.pending_write_f=FALSE; - - /* Check whether the current scan_entry is within range. Otherwise, get the next target */ - if( !is_target_in_range(&scan_list)){ - if(!get_next_target(&scan_list)){ - if(gettimeofday(&lastprobe, NULL) == -1){ - if(idata.verbose_f) - perror("scan6"); + idata.pending_write_f = FALSE; - exit(EXIT_FAILURE); - } + /* Check whether the current scan_entry is within range. Otherwise, get the next target */ + if (!is_target_in_range(&scan_list)) { + if (!get_next_target(&scan_list)) { + if (gettimeofday(&lastprobe, NULL) == -1) { + if (idata.verbose_f) + perror("scan6"); - donesending_f=TRUE; - continue; - } - } + exit(EXIT_FAILURE); + } - if(!send_probe_remote(&idata, &scan_list, &(idata.srcaddr), probetype)){ - puts("Error while sending probe packet"); - exit(EXIT_FAILURE); - } + donesending_f = TRUE; + continue; + } + } - if(gettimeofday(&lastprobe, NULL) == -1){ - if(idata.verbose_f) - perror("scan6"); + if (!send_probe_remote(&idata, &scan_list, &(idata.srcaddr), probetype)) { + puts("Error while sending probe packet"); + exit(EXIT_FAILURE); + } - exit(EXIT_FAILURE); - } + if (gettimeofday(&lastprobe, NULL) == -1) { + if (idata.verbose_f) + perror("scan6"); - if(!get_next_target(&scan_list)){ - donesending_f=TRUE; - continue; - } + exit(EXIT_FAILURE); + } - } + if (!get_next_target(&scan_list)) { + donesending_f = TRUE; + continue; + } + } #ifdef DEBUG -puts("Prior to checking eset"); + puts("Prior to checking eset"); #endif #if !(defined(sun) || defined(__sun) || defined(__linux__)) - if(FD_ISSET(idata.fd, &eset)){ - if(idata.verbose_f) - puts("scan6: Found exception on libpcap descriptor"); + if (FD_ISSET(idata.fd, &eset)) { + if (idata.verbose_f) + puts("scan6: Found exception on libpcap descriptor"); - exit(EXIT_FAILURE); - } + exit(EXIT_FAILURE); + } #endif #ifdef DEBUG -puts("After checking eset"); + puts("After checking eset"); #endif - } - } + } + } - exit(EXIT_SUCCESS); + exit(EXIT_SUCCESS); } - /* * Function: reset_scan_list() * * Resets each scan_list.target[]->cur to scan_list.target[]->start. */ -void reset_scan_list(struct scan_list *scan){ - unsigned int i; +void reset_scan_list(struct scan_list *scan) { + unsigned int i; - for(i=0; i < scan->ntarget; i++) - (scan->target[i])->cur = (scan->target[i])->start; + for (i = 0; i < scan->ntarget; i++) + (scan->target[i])->cur = (scan->target[i])->start; - scan->ctarget=0; + scan->ctarget = 0; - return; + return; } - /* * Function: reset_port_list() * * Resets each port_list.port[]->cur to port_list.port[]->start. */ -void reset_port_list(struct port_list *port){ - unsigned int i; +void reset_port_list(struct port_list *port) { + unsigned int i; - for(i=0; i < port->nport; i++) - (port->port[i])->cur = (port->port[i])->start; + for (i = 0; i < port->nport; i++) + (port->port[i])->cur = (port->port[i])->start; - port->cport=0; + port->cport = 0; - return; + return; } - - /* * Function: is_port_in_range() * * Checks whether a port_entry->cur is >= scan_entry->start && <= scan_entry->end */ -int is_port_in_range(struct port_list *port_list){ - struct port_entry *port_entry; +int is_port_in_range(struct port_list *port_list) { + struct port_entry *port_entry; - if(port_list->cport >=port_list->nport || port_list->cport >= port_list->maxport){ - return(0); - } + if (port_list->cport >= port_list->nport || port_list->cport >= port_list->maxport) { + return (0); + } - port_entry= port_list->port[port_list->cport]; + port_entry = port_list->port[port_list->cport]; - if( port_entry->cur < port_entry->start || port_entry->cur > port_entry->end){ - return(0); - } + if (port_entry->cur < port_entry->start || port_entry->cur > port_entry->end) { + return (0); + } - return(1); + return (1); } - /* * Function: get_next_port() * * "Increments" a scan_entry structure to obtain the next target to scan. */ -int get_next_port(struct port_list *port_list){ - if((port_list->port[port_list->cport])->cur >= (port_list->port[port_list->cport])->end){ - port_list->cport++; - - if(port_list->cport < port_list->nport && port_list->cport < port_list->maxport){ - return(1); - } - else{ - return(0); - } - } - else{ - (port_list->port[port_list->cport])->cur++; - } - - return(1); +int get_next_port(struct port_list *port_list) { + if ((port_list->port[port_list->cport])->cur >= (port_list->port[port_list->cport])->end) { + port_list->cport++; + + if (port_list->cport < port_list->nport && port_list->cport < port_list->maxport) { + return (1); + } + else { + return (0); + } + } + else { + (port_list->port[port_list->cport])->cur++; + } + + return (1); } - /* * Function: print_port_scan() * * Prints the result of a port scan */ -void print_port_scan(struct port_list *port_list, unsigned int *res, int types){ - int i, j; - char portstring[10]; - - for(i=0; i< port_list->nport; i++){ - for(j= (port_list->port[i])->start; j <= (port_list->port[i])->end; j++){ - snprintf(portstring, sizeof(portstring), "%u/%s", j, (port_list->proto == IPPROTO_TCP)?"tcp":"udp"); - portstring[sizeof(portstring)-1]=0; - - switch(res[j]){ - case PORT_FILTERED: - if(types & PORT_FILTERED) - printf("%-9s filtered %s\n", portstring, port_list->port_table[j].name); - break; - - case PORT_OPEN: - if(types & PORT_OPEN) - printf("%-9s open %s\n", portstring, port_list->port_table[j].name); - break; - - case PORT_CLOSED: - if(types & PORT_CLOSED) - printf("%-9s closed %s\n", portstring, port_list->port_table[j].name); - break; - } - } - } +void print_port_scan(struct port_list *port_list, unsigned int *res, int types) { + int i, j; + char portstring[10]; + + for (i = 0; i < port_list->nport; i++) { + for (j = (port_list->port[i])->start; j <= (port_list->port[i])->end; j++) { + snprintf(portstring, sizeof(portstring), "%u/%s", j, (port_list->proto == IPPROTO_TCP) ? "tcp" : "udp"); + portstring[sizeof(portstring) - 1] = 0; + + switch (res[j]) { + case PORT_FILTERED: + if (types & PORT_FILTERED) + printf("%-9s filtered %s\n", portstring, port_list->port_table[j].name); + break; + + case PORT_OPEN: + if (types & PORT_OPEN) + printf("%-9s open %s\n", portstring, port_list->port_table[j].name); + break; + + case PORT_CLOSED: + if (types & PORT_CLOSED) + printf("%-9s closed %s\n", portstring, port_list->port_table[j].name); + break; + } + } + } } - - /* * Function: is_target_in_range() * * Checks whether a scan_entry->cur is >= scan_entry->start && <= scan_entry->end */ -int is_target_in_range(struct scan_list *scan_list){ - unsigned int i; - struct scan_entry *scan_entry; +int is_target_in_range(struct scan_list *scan_list) { + unsigned int i; + struct scan_entry *scan_entry; - if(scan_list->ctarget >= scan_list->ntarget || scan_list->ctarget >= scan_list->maxtarget){ - return(FALSE); - } + if (scan_list->ctarget >= scan_list->ntarget || scan_list->ctarget >= scan_list->maxtarget) { + return (FALSE); + } - scan_entry= scan_list->target[scan_list->ctarget]; + scan_entry = scan_list->target[scan_list->ctarget]; - for(i=0; i<=7; i++){ - if( ntohs((scan_entry->cur).s6addr16[i]) < ntohs((scan_entry->start).s6addr16[i]) || \ - ( ntohs((scan_entry->cur).s6addr16[i]) > ntohs((scan_entry->end).s6addr16[i])) ){ - return(FALSE); - } - } + for (i = 0; i <= 7; i++) { + if (ntohs((scan_entry->cur).s6addr16[i]) < ntohs((scan_entry->start).s6addr16[i]) || + (ntohs((scan_entry->cur).s6addr16[i]) > ntohs((scan_entry->end).s6addr16[i]))) { + return (FALSE); + } + } - return(TRUE); + return (TRUE); } - - /* * Function: get_next_target() * * "Increments" a scan_entry structure to obtain the next target to scan. */ -int get_next_target(struct scan_list *scan_list){ - int i; - unsigned int cind; - - - for(i=7; i>=0; i--){ - /* - Increment scan_entry according to scan_entry->start and scan_entry->end, starting with the low-order word - */ - - if( ntohs((scan_list->target[scan_list->ctarget])->cur.s6addr16[i]) >= \ - ntohs((scan_list->target[scan_list->ctarget])->end.s6addr16[i])){ - if(i==0){ - scan_list->ctarget++; - - if(scan_list->ctarget < scan_list->ntarget && scan_list->ctarget < scan_list->maxtarget){ - return(TRUE); - } - else{ - return(FALSE); - } - } - - (scan_list->target[scan_list->ctarget])->cur.s6addr16[i]= (scan_list->target[scan_list->ctarget])->start.s6addr16[i]; - - } - else{ - /* We must increment the current word */ - - cind= scan_list->ctarget; - - /* - If we're incrementing the lowest-order word, and the scan range is larger than MIN_INC_RANGE, we increment - the word by scan_list->inc. Otherwise, we increment the word by 1. - */ - if(i==7 && ( ntohs((scan_list->target[cind])->end.s6addr16[7]) - ntohs( (scan_list->target[cind])->start.s6addr16[7]) ) \ - >= MIN_INC_RANGE ){ - - /* If the increment would exceed scan_entry->end, we make it "wrap around" */ - if( ((unsigned int) ntohs((scan_list->target[cind])->cur.s6addr16[7]) + scan_list->inc) > \ - ntohs((scan_list->target[scan_list->ctarget])->end.s6addr16[7]) ){ - - (scan_list->target[cind])->cur.s6addr16[i]= htons((uint16_t)((unsigned int) - ntohs((scan_list->target[cind])->start.s6addr16[i]) + \ - ( (unsigned int) ntohs((scan_list->target[cind])->cur.s6addr16[i]) + \ - scan_list->inc - ntohs((scan_list->target[cind])->start.s6addr16[i])) % \ - ( ntohs((scan_list->target[cind])->end.s6addr16[i]) - \ - ntohs((scan_list->target[cind])->start.s6addr16[i])))); - } - else{ - /* Otherwise we simply increment the word with scan_list->inc */ - scan_list->target[cind]->cur.s6addr16[i] = htons(ntohs(scan_list->target[cind]->cur.s6addr16[i]) + scan_list->inc); - return(TRUE); - } - } - else{ - /* - If the scan range is smaller than MIN_IN_RANGE, or we are incrementing a word other than the lowest-order one, - we try to increment in by 1. If this would exceed scan_entry->end, we set it to scan_entry->start and cause the - next word to be incremented - */ - if( ((unsigned int) ntohs((scan_list->target[cind])->cur.s6addr16[i]) + 1) > ntohs(scan_list->target[cind]->end.s6addr16[i])){ - (scan_list->target[cind])->cur.s6addr16[i]= (scan_list->target[cind])->start.s6addr16[i]; - } - else{ - scan_list->target[cind]->cur.s6addr16[i] = htons(ntohs(scan_list->target[cind]->cur.s6addr16[i]) + 1); - return(TRUE); - } - } - } - } - - return(TRUE); -} +int get_next_target(struct scan_list *scan_list) { + int i; + unsigned int cind; + for (i = 7; i >= 0; i--) { + /* + Increment scan_entry according to scan_entry->start and scan_entry->end, starting with the low-order + word + */ + if (ntohs((scan_list->target[scan_list->ctarget])->cur.s6addr16[i]) >= + ntohs((scan_list->target[scan_list->ctarget])->end.s6addr16[i])) { + if (i == 0) { + scan_list->ctarget++; + + if (scan_list->ctarget < scan_list->ntarget && scan_list->ctarget < scan_list->maxtarget) { + return (TRUE); + } + else { + return (FALSE); + } + } + + (scan_list->target[scan_list->ctarget])->cur.s6addr16[i] = + (scan_list->target[scan_list->ctarget])->start.s6addr16[i]; + } + else { + /* We must increment the current word */ + + cind = scan_list->ctarget; + + /* + If we're incrementing the lowest-order word, and the scan range is larger than MIN_INC_RANGE, we + increment the word by scan_list->inc. Otherwise, we increment the word by 1. + */ + if (i == 7 && (ntohs((scan_list->target[cind])->end.s6addr16[7]) - + ntohs((scan_list->target[cind])->start.s6addr16[7])) >= MIN_INC_RANGE) { + + /* If the increment would exceed scan_entry->end, we make it "wrap around" */ + if (((unsigned int)ntohs((scan_list->target[cind])->cur.s6addr16[7]) + scan_list->inc) > + ntohs((scan_list->target[scan_list->ctarget])->end.s6addr16[7])) { + + (scan_list->target[cind])->cur.s6addr16[i] = + htons((uint16_t)((unsigned int)ntohs((scan_list->target[cind])->start.s6addr16[i]) + + ((unsigned int)ntohs((scan_list->target[cind])->cur.s6addr16[i]) + + scan_list->inc - ntohs((scan_list->target[cind])->start.s6addr16[i])) % + (ntohs((scan_list->target[cind])->end.s6addr16[i]) - + ntohs((scan_list->target[cind])->start.s6addr16[i])))); + } + else { + /* Otherwise we simply increment the word with scan_list->inc */ + scan_list->target[cind]->cur.s6addr16[i] = + htons(ntohs(scan_list->target[cind]->cur.s6addr16[i]) + scan_list->inc); + return (TRUE); + } + } + else { + /* + If the scan range is smaller than MIN_IN_RANGE, or we are incrementing a word other than the + lowest-order one, we try to increment in by 1. If this would exceed scan_entry->end, we set it to + scan_entry->start and cause the next word to be incremented + */ + if (((unsigned int)ntohs((scan_list->target[cind])->cur.s6addr16[i]) + 1) > + ntohs(scan_list->target[cind]->end.s6addr16[i])) { + (scan_list->target[cind])->cur.s6addr16[i] = (scan_list->target[cind])->start.s6addr16[i]; + } + else { + scan_list->target[cind]->cur.s6addr16[i] = + htons(ntohs(scan_list->target[cind]->cur.s6addr16[i]) + 1); + return (TRUE); + } + } + } + } + + return (TRUE); +} /* * Function: print_scan_entries() @@ -3165,890 +3153,865 @@ int get_next_target(struct scan_list *scan_list){ * Print address ranges to scan */ -int print_scan_entries(struct scan_list *scan){ - unsigned int i, j; +int print_scan_entries(struct scan_list *scan) { + unsigned int i, j; - for(i=0; i< scan->ntarget; i++){ - for(j=0; j<8; j++){ - if((scan->target[i])->start.s6addr16[j] == (scan->target[i])->end.s6addr16[j]) - printf("%x", ntohs((scan->target[i])->start.s6addr16[j])); - else - printf("%x-%x", ntohs((scan->target[i])->start.s6addr16[j]), ntohs((scan->target[i])->end.s6addr16[j])); + for (i = 0; i < scan->ntarget; i++) { + for (j = 0; j < 8; j++) { + if ((scan->target[i])->start.s6addr16[j] == (scan->target[i])->end.s6addr16[j]) + printf("%x", ntohs((scan->target[i])->start.s6addr16[j])); + else + printf("%x-%x", ntohs((scan->target[i])->start.s6addr16[j]), ntohs((scan->target[i])->end.s6addr16[j])); - if(j<7) - printf(":"); - else - puts(""); - } - } + if (j < 7) + printf(":"); + else + puts(""); + } + } - return(1); + return (1); } - /* * Function: load_ipv4mapped32_prefixes() * * Generate scan_entry's for IPv4-mapped (32-bits) addresses */ -int load_ipv4mapped32_entries(struct scan_list *scan, struct scan_entry *dst, struct prefix4_entry *v4host){ - unsigned int i; - uint32_t mask32; - struct scan_entry dummy; +int load_ipv4mapped32_entries(struct scan_list *scan, struct scan_entry *dst, struct prefix4_entry *v4host) { + unsigned int i; + uint32_t mask32; + struct scan_entry dummy; - dummy.start= dst->start; + dummy.start = dst->start; - for(i=4; i<=5; i++) - dummy.start.s6addr16[i]= htons(0); + for (i = 4; i <= 5; i++) + dummy.start.s6addr16[i] = htons(0); - dummy.start.s6addr16[6]= htons( (uint16_t) (ntohl(v4host->ip.s_addr) >> 16)); - dummy.start.s6addr16[7]= htons( (uint16_t) (ntohl(v4host->ip.s_addr) & 0x0000ffff)); - dummy.cur= dummy.start; + dummy.start.s6addr16[6] = htons((uint16_t)(ntohl(v4host->ip.s_addr) >> 16)); + dummy.start.s6addr16[7] = htons((uint16_t)(ntohl(v4host->ip.s_addr) & 0x0000ffff)); + dummy.cur = dummy.start; - dummy.end= dst->end; + dummy.end = dst->end; - for(i=4; i<=7; i++) - dummy.end.s6addr16[i]= dummy.start.s6addr16[i]; + for (i = 4; i <= 7; i++) + dummy.end.s6addr16[i] = dummy.start.s6addr16[i]; - mask32= 0xffffffff; + mask32 = 0xffffffff; - for(i=0; i< v4host->len; i++) - mask32=mask32<<1; + for (i = 0; i < v4host->len; i++) + mask32 = mask32 << 1; - for(i=0; i< v4host->len; i++) - mask32=mask32>>1; + for (i = 0; i < v4host->len; i++) + mask32 = mask32 >> 1; - dummy.end.s6addr16[6]= dummy.end.s6addr16[6] | htons( (uint16_t)(mask32>>16)); - dummy.end.s6addr16[7]= dummy.end.s6addr16[7] | htons((uint16_t)(mask32 & 0x0000ffff)); + dummy.end.s6addr16[6] = dummy.end.s6addr16[6] | htons((uint16_t)(mask32 >> 16)); + dummy.end.s6addr16[7] = dummy.end.s6addr16[7] | htons((uint16_t)(mask32 & 0x0000ffff)); - return(add_to_scan_list(scan, &dummy)); + return (add_to_scan_list(scan, &dummy)); } - /* * Function: load_ipv4mapped64_prefixes() * * Generate scan_entry's for IPv4-mapped (64-bits) addresses */ -int load_ipv4mapped64_entries(struct scan_list *scan, struct scan_entry *dst, struct prefix4_entry *v4host){ - unsigned int i; - uint32_t mask32; - struct scan_entry dummy; +int load_ipv4mapped64_entries(struct scan_list *scan, struct scan_entry *dst, struct prefix4_entry *v4host) { + unsigned int i; + uint32_t mask32; + struct scan_entry dummy; - dummy.start= dst->start; + dummy.start = dst->start; - dummy.start.s6addr16[4]= htons( (uint16_t) (ntohl(v4host->ip.s_addr) >> 24)); - dummy.start.s6addr16[5]= htons( ((uint16_t) (ntohl(v4host->ip.s_addr) >> 16)) & 0x00ff); - dummy.start.s6addr16[6]= htons( (uint16_t) ((ntohl(v4host->ip.s_addr) >> 8) & 0x000000ff)); - dummy.start.s6addr16[7]= htons( (uint16_t) (ntohl(v4host->ip.s_addr) & 0x000000ff)); - dummy.cur= dummy.start; + dummy.start.s6addr16[4] = htons((uint16_t)(ntohl(v4host->ip.s_addr) >> 24)); + dummy.start.s6addr16[5] = htons(((uint16_t)(ntohl(v4host->ip.s_addr) >> 16)) & 0x00ff); + dummy.start.s6addr16[6] = htons((uint16_t)((ntohl(v4host->ip.s_addr) >> 8) & 0x000000ff)); + dummy.start.s6addr16[7] = htons((uint16_t)(ntohl(v4host->ip.s_addr) & 0x000000ff)); + dummy.cur = dummy.start; - dummy.end= dst->end; + dummy.end = dst->end; - for(i=4; i<=7; i++) - dummy.end.s6addr16[i]= dummy.start.s6addr16[i]; + for (i = 4; i <= 7; i++) + dummy.end.s6addr16[i] = dummy.start.s6addr16[i]; - mask32= 0xffffffff; + mask32 = 0xffffffff; - for(i=0; i< v4host->len; i++) - mask32=mask32<<1; + for (i = 0; i < v4host->len; i++) + mask32 = mask32 << 1; - for(i=0; i< v4host->len; i++) - mask32=mask32>>1; + for (i = 0; i < v4host->len; i++) + mask32 = mask32 >> 1; - dummy.end.s6addr16[4]= dummy.end.s6addr16[4] | htons( (uint16_t)(mask32>>24)); - dummy.end.s6addr16[5]= dummy.end.s6addr16[5] | htons( (uint16_t)(mask32>>16 & 0x000000ff)); - dummy.end.s6addr16[6]= dummy.end.s6addr16[6] | htons( (uint16_t)(mask32>>8 & 0x000000ff)); - dummy.end.s6addr16[7]= dummy.end.s6addr16[7] | htons((uint16_t)(mask32 & 0x000000ff)); + dummy.end.s6addr16[4] = dummy.end.s6addr16[4] | htons((uint16_t)(mask32 >> 24)); + dummy.end.s6addr16[5] = dummy.end.s6addr16[5] | htons((uint16_t)(mask32 >> 16 & 0x000000ff)); + dummy.end.s6addr16[6] = dummy.end.s6addr16[6] | htons((uint16_t)(mask32 >> 8 & 0x000000ff)); + dummy.end.s6addr16[7] = dummy.end.s6addr16[7] | htons((uint16_t)(mask32 & 0x000000ff)); - for(i=4; i<=7; i++){ - dummy.start.s6addr16[i]= htons( dec_to_hex(ntohs(dummy.start.s6addr16[i]))); - dummy.end.s6addr16[i]= htons( dec_to_hex(ntohs(dummy.end.s6addr16[i]))); - } + for (i = 4; i <= 7; i++) { + dummy.start.s6addr16[i] = htons(dec_to_hex(ntohs(dummy.start.s6addr16[i]))); + dummy.end.s6addr16[i] = htons(dec_to_hex(ntohs(dummy.end.s6addr16[i]))); + } - return(add_to_scan_list(scan, &dummy)); + return (add_to_scan_list(scan, &dummy)); } - /* * Function: load_knownprefix_entries() * * Generate prefix_entry's for known prefixes (populate the prefix_list) */ -int load_knownprefix_entries(struct scan_list *scan_list, struct scan_list *prefix_list, FILE *fp){ - unsigned int i; - int r; - char line[MAX_LINE_SIZE], *ptr, *charptr, *charstart, *charend, *lastcolon; - char rangestart[MAX_RANGE_STR_LEN+1], rangeend[MAX_RANGE_STR_LEN+1]; - struct prefix_entry prefix; - struct scan_entry dummy; - - while(fgets(line, sizeof(line), fp) != NULL){ - r= read_prefix(line, Strnlen(line, MAX_LINE_SIZE), &ptr); - - if(r == 1){ - if( (ranges= address_contains_ranges(ptr)) == 1){ - charptr= ptr; - charstart= rangestart; - charend= rangeend; - lastcolon= charend; - - while(*charptr && (ptr - charptr) <= MAX_RANGE_STR_LEN){ - if(*charptr != '-'){ - *charstart= *charptr; - *charend= *charptr; - charstart++; - charend++; - - if(*charptr==':') - lastcolon= charend; - - charptr++; - } - else{ - charend= lastcolon; - charptr++; - - while(*charptr && (ptr - charptr) <= MAX_RANGE_STR_LEN && *charptr !=':' && *charptr !='-'){ - *charend= *charptr; - charend++; - charptr++; - } - } - } - - *charstart=0; - *charend=0; - tgt_range_f=TRUE; - - if(scan_list->ntarget <= scan_list->maxtarget){ - - if ( inet_pton(AF_INET6, rangestart, &(dummy.start)) <= 0){ - if(verbose_f>1) - puts("inet_pton(): Error converting IPv6 address from presentation to network format"); - - return(0); - } - - if ( inet_pton(AF_INET6, rangeend, &(dummy.end)) <= 0){ - if(verbose_f>1) - puts("inet_pton(): Error converting IPv6 address from presentation to network format"); - - return(0); - } - - dummy.cur= dummy.start; - - /* Check whether the start address is smaller than the end address */ - for(i=0;i<7; i++) - if( ntohs(dummy.start.s6addr16[i]) > - ntohs(dummy.end.s6addr16[i])){ - if(verbose_f > 1) - puts("Error in Destination Address range: Start address larger than end address!"); - - return(0); - } - - if(IN6_IS_ADDR_MULTICAST(&(dummy.start.in6_addr))){ - if(verbose_f > 1) - puts("scan6: Remote scan cannot target a multicast address"); - - return(0); - } - - if(IN6_IS_ADDR_MULTICAST(&(dummy.end.in6_addr))){ - if(verbose_f > 1) - puts("scan6: Remote scan cannot target a multicast address"); - - return(0); - } - - if(add_to_scan_list(scan_list, &dummy) == FALSE) - return(FALSE); - } - else{ - /* - If the number of "targets" has already been exceeded, it doesn't make sense to continue further, - since there wouldn't be space for any specific target types - */ - if(verbose_f > 1) - puts("Too many targets!"); - - return(0); - } - - if(prefix_list->ntarget <= prefix_list->maxtarget){ - if( (prefix_list->target[prefix_list->ntarget] = malloc(sizeof(struct scan_entry))) == NULL){ - if(verbose_f > 1) - puts("scan6: Not enough memory"); - - return(0); - } - - /* Copy the recently added target to our prefix list */ - *(prefix_list->target[prefix_list->ntarget])= dummy; - prefix_list->ntarget++; - } - else{ - /* - If the number of "targets" has already been exceeded, it doesn't make sense to continue further, - since there wouldn't be space for any specific target types - */ - if(verbose_f > 1) - puts("Too many targets!"); - - return(0); - } - } - else if(ranges == 0){ - if((charptr = strtok_r(ptr, "/", &lasts)) == NULL){ - if(verbose_f > 1) - puts("Error in Destination Address"); - - return(0); - } - - if ( inet_pton(AF_INET6, charptr, &(prefix.ip6)) <= 0){ - if(verbose_f > 1) - puts("inet_pton(): Destination Address not valid"); - - return(0); - } - - if((charptr = strtok_r(NULL, " ", &lasts)) != NULL){ - prefix.len = atoi(charptr); - - if(prefix.len>128){ - if(verbose_f > 1) - puts("Prefix length error in IPv6 Destination Address"); - - return(0); - } - - sanitize_ipv6_prefix(&(prefix.ip6), prefix.len); - } - else{ - prefix.len= 128; - } - - if(prefix_list->ntarget <= prefix_list->maxtarget){ - if( (prefix_list->target[prefix_list->ntarget] = malloc(sizeof(struct scan_entry))) == NULL){ - if(verbose_f) - puts("scan6: Not enough memory"); - - return(0); - } - - prefix_to_scan(&prefix, prefix_list->target[prefix_list->ntarget]); - - if(IN6_IS_ADDR_MULTICAST(&((prefix_list->target[prefix_list->ntarget])->start.in6_addr))){ - if(verbose_f > 1) - puts("scan6: Remote scan cannot target a multicast address"); - - return(0); - } - - if(IN6_IS_ADDR_MULTICAST(&((prefix_list->target[prefix_list->ntarget])->end.in6_addr))){ - if(verbose_f > 1) - puts("scan6: Remote scan cannot target a multicast address"); - - return(0); - } - - prefix_list->ntarget++; - } - else{ - /* - If the number of "targets" has already been exceeded, it doesn't make sense to continue further, - since there wouldn't be space for any specific target types - */ - if(verbose_f > 1) - puts("Too many targets!"); - - return(0); - } - } - - dst_f=TRUE; - } - else if(r == -1){ - if(verbose_f){ - printf("Error in 'known prefixes' file %s\n", knownprefixesfile); - } - - fclose(fp); - return(0); - } - } - - return(1); +int load_knownprefix_entries(struct scan_list *scan_list, struct scan_list *prefix_list, FILE *fp) { + unsigned int i; + int r; + char line[MAX_LINE_SIZE], *ptr, *charptr, *charstart, *charend, *lastcolon; + char rangestart[MAX_RANGE_STR_LEN + 1], rangeend[MAX_RANGE_STR_LEN + 1]; + struct prefix_entry prefix; + struct scan_entry dummy; + + while (fgets(line, sizeof(line), fp) != NULL) { + r = read_prefix(line, Strnlen(line, MAX_LINE_SIZE), &ptr); + + if (r == 1) { + if ((ranges = address_contains_ranges(ptr)) == 1) { + charptr = ptr; + charstart = rangestart; + charend = rangeend; + lastcolon = charend; + + while (*charptr && (ptr - charptr) <= MAX_RANGE_STR_LEN) { + if (*charptr != '-') { + *charstart = *charptr; + *charend = *charptr; + charstart++; + charend++; + + if (*charptr == ':') + lastcolon = charend; + + charptr++; + } + else { + charend = lastcolon; + charptr++; + + while (*charptr && (ptr - charptr) <= MAX_RANGE_STR_LEN && *charptr != ':' && *charptr != '-') { + *charend = *charptr; + charend++; + charptr++; + } + } + } + + *charstart = 0; + *charend = 0; + tgt_range_f = TRUE; + + if (scan_list->ntarget <= scan_list->maxtarget) { + + if (inet_pton(AF_INET6, rangestart, &(dummy.start)) <= 0) { + if (verbose_f > 1) + puts("inet_pton(): Error converting IPv6 address from presentation to network format"); + + return (0); + } + + if (inet_pton(AF_INET6, rangeend, &(dummy.end)) <= 0) { + if (verbose_f > 1) + puts("inet_pton(): Error converting IPv6 address from presentation to network format"); + + return (0); + } + + dummy.cur = dummy.start; + + /* Check whether the start address is smaller than the end address */ + for (i = 0; i < 7; i++) + if (ntohs(dummy.start.s6addr16[i]) > ntohs(dummy.end.s6addr16[i])) { + if (verbose_f > 1) + puts("Error in Destination Address range: Start address larger than end address!"); + + return (0); + } + + if (IN6_IS_ADDR_MULTICAST(&(dummy.start.in6_addr))) { + if (verbose_f > 1) + puts("scan6: Remote scan cannot target a multicast address"); + + return (0); + } + + if (IN6_IS_ADDR_MULTICAST(&(dummy.end.in6_addr))) { + if (verbose_f > 1) + puts("scan6: Remote scan cannot target a multicast address"); + + return (0); + } + + if (add_to_scan_list(scan_list, &dummy) == FALSE) + return (FALSE); + } + else { + /* + If the number of "targets" has already been exceeded, it doesn't make sense to continue further, + since there wouldn't be space for any specific target types + */ + if (verbose_f > 1) + puts("Too many targets!"); + + return (0); + } + + if (prefix_list->ntarget <= prefix_list->maxtarget) { + if ((prefix_list->target[prefix_list->ntarget] = malloc(sizeof(struct scan_entry))) == NULL) { + if (verbose_f > 1) + puts("scan6: Not enough memory"); + + return (0); + } + + /* Copy the recently added target to our prefix list */ + *(prefix_list->target[prefix_list->ntarget]) = dummy; + prefix_list->ntarget++; + } + else { + /* + If the number of "targets" has already been exceeded, it doesn't make sense to continue further, + since there wouldn't be space for any specific target types + */ + if (verbose_f > 1) + puts("Too many targets!"); + + return (0); + } + } + else if (ranges == 0) { + if ((charptr = strtok_r(ptr, "/", &lasts)) == NULL) { + if (verbose_f > 1) + puts("Error in Destination Address"); + + return (0); + } + + if (inet_pton(AF_INET6, charptr, &(prefix.ip6)) <= 0) { + if (verbose_f > 1) + puts("inet_pton(): Destination Address not valid"); + + return (0); + } + + if ((charptr = strtok_r(NULL, " ", &lasts)) != NULL) { + prefix.len = atoi(charptr); + + if (prefix.len > 128) { + if (verbose_f > 1) + puts("Prefix length error in IPv6 Destination Address"); + + return (0); + } + + sanitize_ipv6_prefix(&(prefix.ip6), prefix.len); + } + else { + prefix.len = 128; + } + + if (prefix_list->ntarget <= prefix_list->maxtarget) { + if ((prefix_list->target[prefix_list->ntarget] = malloc(sizeof(struct scan_entry))) == NULL) { + if (verbose_f) + puts("scan6: Not enough memory"); + + return (0); + } + + prefix_to_scan(&prefix, prefix_list->target[prefix_list->ntarget]); + + if (IN6_IS_ADDR_MULTICAST(&((prefix_list->target[prefix_list->ntarget])->start.in6_addr))) { + if (verbose_f > 1) + puts("scan6: Remote scan cannot target a multicast address"); + + return (0); + } + + if (IN6_IS_ADDR_MULTICAST(&((prefix_list->target[prefix_list->ntarget])->end.in6_addr))) { + if (verbose_f > 1) + puts("scan6: Remote scan cannot target a multicast address"); + + return (0); + } + + prefix_list->ntarget++; + } + else { + /* + If the number of "targets" has already been exceeded, it doesn't make sense to continue further, + since there wouldn't be space for any specific target types + */ + if (verbose_f > 1) + puts("Too many targets!"); + + return (0); + } + } + + dst_f = TRUE; + } + else if (r == -1) { + if (verbose_f) { + printf("Error in 'known prefixes' file %s\n", knownprefixesfile); + } + + fclose(fp); + return (0); + } + } + + return (1); } - /* * Function: load_knowniid_entries() * * Generate scan_entry's for known Interface IDs */ -int load_knowniid_entries(struct scan_list *scan, struct scan_list *prefix, struct prefix_list *iid){ - unsigned int i, j, k; - struct scan_entry dummy; +int load_knowniid_entries(struct scan_list *scan, struct scan_list *prefix, struct prefix_list *iid) { + unsigned int i, j, k; + struct scan_entry dummy; - for(i=0; i< iid->nprefix; i++){ - for(j=0; j < prefix->ntarget; j++){ - dummy.start= (prefix->target[j])->start; + for (i = 0; i < iid->nprefix; i++) { + for (j = 0; j < prefix->ntarget; j++) { + dummy.start = (prefix->target[j])->start; - for(k=2; k<=3; k++) - dummy.start.in6_addr.s6_addr32[k]= (iid->prefix[i])->ip6.s6_addr32[k]; + for (k = 2; k <= 3; k++) + dummy.start.in6_addr.s6_addr32[k] = (iid->prefix[i])->ip6.s6_addr32[k]; - dummy.cur= dummy.start; + dummy.cur = dummy.start; - dummy.end= (prefix->target[j])->end; + dummy.end = (prefix->target[j])->end; - for(k=2; k<=3; k++) - dummy.end.in6_addr.s6_addr32[k]= (iid->prefix[i])->ip6.s6_addr32[k]; + for (k = 2; k <= 3; k++) + dummy.end.in6_addr.s6_addr32[k] = (iid->prefix[i])->ip6.s6_addr32[k]; - if(add_to_scan_list(scan, &dummy) == FALSE) - return(FALSE); - } - } + if (add_to_scan_list(scan, &dummy) == FALSE) + return (FALSE); + } + } - return(TRUE); + return (TRUE); } - - /* * Function: load_knowniidfile_entries() * * Generate scan_entry's for known Interface IDs */ -int load_knowniidfile_entries(struct scan_list *scan, struct scan_list *prefix, FILE *fp){ - unsigned int i; - int r; - char line[MAX_LINE_SIZE]; - struct in6_addr iid; - struct scan_entry dummy; +int load_knowniidfile_entries(struct scan_list *scan, struct scan_list *prefix, FILE *fp) { + unsigned int i; + int r; + char line[MAX_LINE_SIZE]; + struct in6_addr iid; + struct scan_entry dummy; - while(fgets(line, sizeof(line), fp) != NULL){ - r= read_ipv6_address(line, Strnlen(line, MAX_LINE_SIZE), &iid); + while (fgets(line, sizeof(line), fp) != NULL) { + r = read_ipv6_address(line, Strnlen(line, MAX_LINE_SIZE), &iid); - if(r == 1){ - for(i=0; i< prefix->ntarget; i++){ - dummy.start= (prefix->target[i])->start; + if (r == 1) { + for (i = 0; i < prefix->ntarget; i++) { + dummy.start = (prefix->target[i])->start; - for(j=2; j<=3; j++) - dummy.start.in6_addr.s6_addr32[j]= iid.s6_addr32[j]; + for (j = 2; j <= 3; j++) + dummy.start.in6_addr.s6_addr32[j] = iid.s6_addr32[j]; - dummy.cur= dummy.start; + dummy.cur = dummy.start; - dummy.end= (prefix->target[i])->end; + dummy.end = (prefix->target[i])->end; - for(j=2; j<=3; j++) - dummy.end.in6_addr.s6_addr32[j]= iid.s6_addr32[j]; + for (j = 2; j <= 3; j++) + dummy.end.in6_addr.s6_addr32[j] = iid.s6_addr32[j]; - if(add_to_scan_list(scan, &dummy) == FALSE) - return(FALSE); - } + if (add_to_scan_list(scan, &dummy) == FALSE) + return (FALSE); + } + } + else if (r == -1) { + if (verbose_f) { + printf("Error in 'known IIDs' file %s\n", knowniidsfile); + } - } - else if(r == -1){ - if(verbose_f){ - printf("Error in 'known IIDs' file %s\n", knowniidsfile); - } + fclose(fp); + return (0); + } + } - fclose(fp); - return(0); - } - - } - - return(1); + return (1); } - /* * Function: load_embeddedport_entries() * * Generate scan_entry's for IPv6 addresses with embedded service ports */ -int load_embeddedport_entries(struct scan_list *scan, struct scan_entry *dst){ - unsigned int i; - struct scan_entry dummy; - - for(i=0; i < (sizeof(service_ports_hex)/sizeof(uint16_t)); i++){ - dummy.start= dst->start; - dummy.start.s6addr16[4]= htons(0); - dummy.start.s6addr16[5]= htons(0); - dummy.start.s6addr16[6]= htons(0); - dummy.start.s6addr16[7]= htons(service_ports_hex[i]); - dummy.cur= dummy.start; - - dummy.end= dst->end; - dummy.end.s6addr16[4]= htons(0); - dummy.end.s6addr16[5]= htons(0); - dummy.end.s6addr16[6]= htons(EMBEDDED_PORT_2ND_WORD); - dummy.end.s6addr16[7]= htons(service_ports_hex[i]); - - if(add_to_scan_list(scan, &dummy) == FALSE) - return(FALSE); - - dummy.start= dst->start; - dummy.start.s6addr16[4]= htons(0); - dummy.start.s6addr16[5]= htons(0); - dummy.start.s6addr16[6]= htons(service_ports_hex[i]); - dummy.start.s6addr16[7]= htons(0); - dummy.cur= dummy.start; - - dummy.end= dst->end; - dummy.end.s6addr16[4]= htons(0); - dummy.end.s6addr16[5]= htons(0); - dummy.end.s6addr16[6]= htons(service_ports_hex[i]); - dummy.end.s6addr16[7]= htons(EMBEDDED_PORT_2ND_WORD); - - if(add_to_scan_list(scan, &dummy) == FALSE) - return(FALSE); - } - - for(i=0; i < (sizeof(service_ports_dec)/sizeof(uint16_t)); i++){ - dummy.start= dst->start; - dummy.start.s6addr16[4]= htons(0); - dummy.start.s6addr16[5]= htons(0); - dummy.start.s6addr16[6]= htons(0); - dummy.start.s6addr16[7]= htons(service_ports_dec[i]); - dummy.cur= dummy.start; - - dummy.end= dst->end; - dummy.end.s6addr16[4]= htons(0); - dummy.end.s6addr16[5]= htons(0); - dummy.end.s6addr16[6]= htons(EMBEDDED_PORT_2ND_WORD); - dummy.end.s6addr16[7]= htons(service_ports_dec[i]); - - if(add_to_scan_list(scan, &dummy) == FALSE) - return(FALSE); - - dummy.start= dst->start; - dummy.start.s6addr16[4]= htons(0); - dummy.start.s6addr16[5]= htons(0); - dummy.start.s6addr16[6]= htons(service_ports_dec[i]); - dummy.start.s6addr16[7]= htons(0); - dummy.cur= dummy.start; - - dummy.end= dst->end; - dummy.end.s6addr16[4]= htons(0); - dummy.end.s6addr16[5]= htons(0); - dummy.end.s6addr16[6]= htons(service_ports_dec[i]); - dummy.end.s6addr16[7]= htons(EMBEDDED_PORT_2ND_WORD); - - if(add_to_scan_list(scan, &dummy) == FALSE) - return(FALSE); - } - - return(TRUE); +int load_embeddedport_entries(struct scan_list *scan, struct scan_entry *dst) { + unsigned int i; + struct scan_entry dummy; + + for (i = 0; i < (sizeof(service_ports_hex) / sizeof(uint16_t)); i++) { + dummy.start = dst->start; + dummy.start.s6addr16[4] = htons(0); + dummy.start.s6addr16[5] = htons(0); + dummy.start.s6addr16[6] = htons(0); + dummy.start.s6addr16[7] = htons(service_ports_hex[i]); + dummy.cur = dummy.start; + + dummy.end = dst->end; + dummy.end.s6addr16[4] = htons(0); + dummy.end.s6addr16[5] = htons(0); + dummy.end.s6addr16[6] = htons(EMBEDDED_PORT_2ND_WORD); + dummy.end.s6addr16[7] = htons(service_ports_hex[i]); + + if (add_to_scan_list(scan, &dummy) == FALSE) + return (FALSE); + + dummy.start = dst->start; + dummy.start.s6addr16[4] = htons(0); + dummy.start.s6addr16[5] = htons(0); + dummy.start.s6addr16[6] = htons(service_ports_hex[i]); + dummy.start.s6addr16[7] = htons(0); + dummy.cur = dummy.start; + + dummy.end = dst->end; + dummy.end.s6addr16[4] = htons(0); + dummy.end.s6addr16[5] = htons(0); + dummy.end.s6addr16[6] = htons(service_ports_hex[i]); + dummy.end.s6addr16[7] = htons(EMBEDDED_PORT_2ND_WORD); + + if (add_to_scan_list(scan, &dummy) == FALSE) + return (FALSE); + } + + for (i = 0; i < (sizeof(service_ports_dec) / sizeof(uint16_t)); i++) { + dummy.start = dst->start; + dummy.start.s6addr16[4] = htons(0); + dummy.start.s6addr16[5] = htons(0); + dummy.start.s6addr16[6] = htons(0); + dummy.start.s6addr16[7] = htons(service_ports_dec[i]); + dummy.cur = dummy.start; + + dummy.end = dst->end; + dummy.end.s6addr16[4] = htons(0); + dummy.end.s6addr16[5] = htons(0); + dummy.end.s6addr16[6] = htons(EMBEDDED_PORT_2ND_WORD); + dummy.end.s6addr16[7] = htons(service_ports_dec[i]); + + if (add_to_scan_list(scan, &dummy) == FALSE) + return (FALSE); + + dummy.start = dst->start; + dummy.start.s6addr16[4] = htons(0); + dummy.start.s6addr16[5] = htons(0); + dummy.start.s6addr16[6] = htons(service_ports_dec[i]); + dummy.start.s6addr16[7] = htons(0); + dummy.cur = dummy.start; + + dummy.end = dst->end; + dummy.end.s6addr16[4] = htons(0); + dummy.end.s6addr16[5] = htons(0); + dummy.end.s6addr16[6] = htons(service_ports_dec[i]); + dummy.end.s6addr16[7] = htons(EMBEDDED_PORT_2ND_WORD); + + if (add_to_scan_list(scan, &dummy) == FALSE) + return (FALSE); + } + + return (TRUE); } - /* * Function: load_lowbyte_entries() * * Generate scan_entry's for low-byte addresses */ -int load_lowbyte_entries(struct scan_list *scan, struct scan_entry *dst){ - unsigned int i; - struct scan_entry dummy; +int load_lowbyte_entries(struct scan_list *scan, struct scan_entry *dst) { + unsigned int i; + struct scan_entry dummy; - dummy.start= dst->start; + dummy.start = dst->start; - for(i=4; i<=7; i++) - dummy.start.s6addr16[i]= htons(0); + for (i = 4; i <= 7; i++) + dummy.start.s6addr16[i] = htons(0); - dummy.cur= dummy.start; - dummy.end= dst->end; + dummy.cur = dummy.start; + dummy.end = dst->end; - for(i=4; i<=5; i++) - dummy.end.s6addr16[i]= htons(0); + for (i = 4; i <= 5; i++) + dummy.end.s6addr16[i] = htons(0); - dummy.end.s6addr16[6]= htons(LOW_BYTE_2ND_WORD_UPPER); - dummy.end.s6addr16[7]= htons(LOW_BYTE_1ST_WORD_UPPER); + dummy.end.s6addr16[6] = htons(LOW_BYTE_2ND_WORD_UPPER); + dummy.end.s6addr16[7] = htons(LOW_BYTE_1ST_WORD_UPPER); - if(add_to_scan_list(scan, &dummy) == FALSE) - return(FALSE); + if (add_to_scan_list(scan, &dummy) == FALSE) + return (FALSE); - return(TRUE); + return (TRUE); } - - /* * Function: load_oui_entries() * * Generate scan_entry's based on a specific IEEE OUI */ -int load_oui_entries(struct scan_list *scan, struct scan_entry *dst, struct ether_addr *oui){ - unsigned int i; - struct scan_entry dummy; +int load_oui_entries(struct scan_list *scan, struct scan_entry *dst, struct ether_addr *oui) { + unsigned int i; + struct scan_entry dummy; - generate_slaac_address(&(dst->start.in6_addr), oui, &(dummy.start.in6_addr)); - dummy.cur= dummy.start; + generate_slaac_address(&(dst->start.in6_addr), oui, &(dummy.start.in6_addr)); + dummy.cur = dummy.start; - for(i=0; i<4; i++) - dummy.end.s6addr16[i]= dst->end.s6addr16[i]; + for (i = 0; i < 4; i++) + dummy.end.s6addr16[i] = dst->end.s6addr16[i]; - for(i=4; i<=7; i++) - dummy.end.s6addr16[i]= dummy.start.s6addr16[i]; + for (i = 4; i <= 7; i++) + dummy.end.s6addr16[i] = dummy.start.s6addr16[i]; - /* - The three low-order bytes must vary from 0x000000 to 0xffffff - */ - dummy.end.s6addr16[6]= dummy.end.s6addr16[6] | htons(0x00ff); - dummy.end.s6addr16[7]= dummy.end.s6addr16[7] | htons(0xffff); + /* + The three low-order bytes must vary from 0x000000 to 0xffffff + */ + dummy.end.s6addr16[6] = dummy.end.s6addr16[6] | htons(0x00ff); + dummy.end.s6addr16[7] = dummy.end.s6addr16[7] | htons(0xffff); - if(add_to_scan_list(scan, &dummy) == FALSE) - return(FALSE); + if (add_to_scan_list(scan, &dummy) == FALSE) + return (FALSE); - return(TRUE); + return (TRUE); } - /* * Function: load_vm_entries() * * Generate scan_entry's based on virtualization prefixes, and scan modes */ -int load_vm_entries(struct scan_list *scan, struct scan_entry *dst, struct prefix4_entry *v4host){ - unsigned int i; - uint32_t mask32; - struct ether_addr ether; - struct scan_entry dummy; - - /* VirtualBOX */ - if(vm_vbox_f){ - if(ether_pton("08:00:27:00:00:00", ðer, sizeof(ether)) == 0){ - if(verbose_f) - puts("scan6: ether_pton(): Error converting Ethernet Address to presentation format"); - - return(0); - } - - generate_slaac_address(&(dst->start.in6_addr), ðer, &(dummy.start.in6_addr)); - dummy.cur= dummy.start; - dummy.end= dst->end; - - for(i=4; i<=7; i++) - dummy.end.s6addr16[i]= dummy.start.s6addr16[i]; - - /* - The three low-order bytes must vary from 0x000000 to 0xffffff - */ - dummy.end.s6addr16[6]= dummy.end.s6addr16[6] | htons(0x00ff); - dummy.end.s6addr16[7]= dummy.end.s6addr16[7] | htons(0xffff); - - if(add_to_scan_list(scan, &dummy) == FALSE) - return(FALSE); - } - - if(vm_vmware_vsphere_f){ - /* - Add scan entry for VMWare vSphere. First, include addresses assigned vy vCenter Server. - Then include addresses assigned by the ESXi host. - */ +int load_vm_entries(struct scan_list *scan, struct scan_entry *dst, struct prefix4_entry *v4host) { + unsigned int i; + uint32_t mask32; + struct ether_addr ether; + struct scan_entry dummy; - /* - By default, MAC addresses assigned by the vCenter server use the OUI - 00:50:56, and have the format 00:50:56:XX:YY:ZZ, where XX is - calculated as (0x80 + vCenter Server ID (in the range 0x00-0x3F)), - and XX and YY are random two-digit hexadecimal numbers. Thus, the - possible IID range is 00:50:56:80:00:00-00:50:56:BF:FF:FF, and - therefore the search space for the resulting SLAAC addresses will be - 24 bits. - */ - - if(ether_pton("00:50:56:80:00:00", ðer, sizeof(ether)) == 0){ - if(verbose_f) - puts("scan6: ether_pton(): Error converting Ethernet Address to presentation format"); - - return(0); - } - - generate_slaac_address(&(dst->start.in6_addr), ðer, &(dummy.start.in6_addr)); - dummy.cur= dummy.start; - - - if(ether_pton("00:50:56:BF:FF:FF", ðer, sizeof(ether)) == 0){ - if(verbose_f) - puts("scan6: ether_pton(): Error converting Ethernet Address to presentation format"); - - return(0); - } - - generate_slaac_address(&(dst->end.in6_addr), ðer, &(dummy.end.in6_addr)); - - if(add_to_scan_list(scan, &dummy) == FALSE) - return(FALSE); - - if(ether_pton("00:0C:29:00:00:00", ðer, sizeof(ether)) == 0){ - if(verbose_f) - puts("scan6: ether_pton(): Error converting Ethernet Address to presentation format"); - - return(0); - } - - generate_slaac_address(&(dst->start.in6_addr), ðer, &(dummy.start.in6_addr)); - dummy.cur= dummy.start; - dummy.end= dst->end; - - for(i=4; i<=7; i++) - dummy.end.s6addr16[i]= dummy.start.s6addr16[i]; - - /* - The three low-order bytes must vary from 0x000000 to 0xffffff - */ - dummy.end.s6addr16[6]= dummy.end.s6addr16[6] | htons(0x00ff); - dummy.end.s6addr16[7]= dummy.end.s6addr16[7] | htons(0xffff); - - if(add_to_scan_list(scan, &dummy) == FALSE) - return(FALSE); - } - - if(vm_vmware_esx_f){ - /* Add scan entry for VMWare ESX Server */ - - if(ether_pton("00:05:69:00:00:00", ðer, sizeof(ether)) == 0){ - if(verbose_f) - puts("scan6: ether_pton(): Error converting Ethernet Address to presentation format"); - - return(0); - } - - generate_slaac_address(&(dst->start.in6_addr), ðer, &(dummy.start.in6_addr)); - dummy.cur= dummy.start; - dummy.end= dst->end; - - for(i=4; i<=7; i++) - dummy.end.s6addr16[i]= dummy.start.s6addr16[i]; - - - /* - If we know the host system IPv4 address, we can narrow down the search space. Otherwise - the three low-order bytes must vary in the range 0x000000 to 0xffffff - */ - if(v4hostaddr_f){ - if(v4hostprefix_f){ - mask32= 0xffffffff; - - for(i=0; i< v4host->len; i++) - mask32=mask32>>1; - } - else{ - mask32= 0; - } - - dummy.start.s6addr16[6]= dummy.start.s6addr16[6] | \ - htons((ntohl(v4host->ip.s_addr) & 0x0000ff00)>>8); - dummy.start.s6addr16[7]= dummy.start.s6addr16[7] | \ - htons((ntohl(v4host->ip.s_addr) & 0x000000ff)<<8); - - dummy.end.s6addr16[6]= dummy.end.s6addr16[6] | \ - htons((ntohl(v4host->ip.s_addr) & 0x0000ff00)>>8) | \ - htonl((mask32 & 0x0000ff00)>>8); - dummy.end.s6addr16[7]= dummy.end.s6addr16[7] | \ - htons((ntohl(v4host->ip.s_addr) & 0x000000ff)<<8) | \ - htonl((mask32 & 0x000000ff)<<8) | htons(0x00ff); - } - else{ - dummy.end.s6addr16[6]= dummy.end.s6addr16[6] | htons(0x00ff); - dummy.end.s6addr16[7]= dummy.end.s6addr16[7] | htons(0xffff); - } + /* VirtualBOX */ + if (vm_vbox_f) { + if (ether_pton("08:00:27:00:00:00", ðer, sizeof(ether)) == 0) { + if (verbose_f) + puts("scan6: ether_pton(): Error converting Ethernet Address to presentation format"); - if(add_to_scan_list(scan, &dummy) == FALSE) - return(FALSE); - } + return (0); + } - if(vm_vmwarem_f){ - if(ether_pton("00:50:56:00:00:00", ðer, sizeof(ether)) == 0){ - if(verbose_f) - puts("scan6: ether_pton(): Error converting Ethernet Address to presentation format"); + generate_slaac_address(&(dst->start.in6_addr), ðer, &(dummy.start.in6_addr)); + dummy.cur = dummy.start; + dummy.end = dst->end; - return(0); - } + for (i = 4; i <= 7; i++) + dummy.end.s6addr16[i] = dummy.start.s6addr16[i]; - generate_slaac_address(&(dst->start.in6_addr), ðer, &(dummy.start.in6_addr)); - dummy.cur= dummy.start; - dummy.end= dst->end; - - for(i=4; i<=7; i++) - dummy.end.s6addr16[i]= dummy.start.s6addr16[i]; - - /* - The three low-order bytes must vary from 0x000000 to 0x3fffff - */ - dummy.end.s6addr16[6]= dummy.end.s6addr16[6] | htons(0x003f); - dummy.end.s6addr16[7]= dummy.end.s6addr16[7] | htons(0xffff); - - if(add_to_scan_list(scan, &dummy) == FALSE) - return(FALSE); - } - - return(TRUE); -} + /* + The three low-order bytes must vary from 0x000000 to 0xffffff + */ + dummy.end.s6addr16[6] = dummy.end.s6addr16[6] | htons(0x00ff); + dummy.end.s6addr16[7] = dummy.end.s6addr16[7] | htons(0xffff); + if (add_to_scan_list(scan, &dummy) == FALSE) + return (FALSE); + } -/* - * Function: load_vendor_entries() - * - * Lookup vendor's IEEE OUIs + if (vm_vmware_vsphere_f) { + /* + Add scan entry for VMWare vSphere. First, include addresses assigned vy vCenter Server. + Then include addresses assigned by the ESXi host. */ -int load_vendor_entries(struct scan_list *scan, struct scan_entry *dst, char *vendor){ - FILE *fp; - struct ether_addr aux_oui, oui_list[MAX_IEEE_OUIS]; - char oui_ascii[ETHER_ADDR_PLEN]; - char *oui_end=":00:00:00"; - char *oui_hex_string="(hex)"; - char line[MAX_IEEE_OUIS_LINE_SIZE]; - char *charptr; - unsigned int lines=0, ouis; - int i; - struct scan_entry dummy; + /* + By default, MAC addresses assigned by the vCenter server use the OUI + 00:50:56, and have the format 00:50:56:XX:YY:ZZ, where XX is + calculated as (0x80 + vCenter Server ID (in the range 0x00-0x3F)), + and XX and YY are random two-digit hexadecimal numbers. Thus, the + possible IID range is 00:50:56:80:00:00-00:50:56:BF:FF:FF, and + therefore the search space for the resulting SLAAC addresses will be + 24 bits. + */ + + if (ether_pton("00:50:56:80:00:00", ðer, sizeof(ether)) == 0) { + if (verbose_f) + puts("scan6: ether_pton(): Error converting Ethernet Address to presentation format"); + + return (0); + } + + generate_slaac_address(&(dst->start.in6_addr), ðer, &(dummy.start.in6_addr)); + dummy.cur = dummy.start; - ouis=0; - - if( (fp=fopen(fname, "r")) == NULL){ - perror("scan6:"); - return(0); - } + if (ether_pton("00:50:56:BF:FF:FF", ðer, sizeof(ether)) == 0) { + if (verbose_f) + puts("scan6: ether_pton(): Error converting Ethernet Address to presentation format"); - while( ouis <= MAX_IEEE_OUIS && fgets(line, MAX_IEEE_OUIS_LINE_SIZE, fp) != NULL){ - /* - We ship a minimalistic IEEE OUI "database" containing only the first "line" for each IEEE OUI. - However, in order to handle the case of users employing the OUI database directly downloaded - from the IEEE site, we perform a simple check to skip those lines that do not start with - the pattern XX-XX-XX - */ + return (0); + } - if( (lines=Strnlen(line, MAX_IEEE_OUIS_LINE_SIZE)) <= 9) - continue; + generate_slaac_address(&(dst->end.in6_addr), ðer, &(dummy.end.in6_addr)); - if(line[2] != '-' || line[5] != '-' || line[8] != ' ') - continue; + if (add_to_scan_list(scan, &dummy) == FALSE) + return (FALSE); - charptr= (char *)line + 9; + if (ether_pton("00:0C:29:00:00:00", ðer, sizeof(ether)) == 0) { + if (verbose_f) + puts("scan6: ether_pton(): Error converting Ethernet Address to presentation format"); - /* Skip any whitespaces */ - while(charptr < ( (char *)line + lines) && *charptr == ' ') - charptr++; + return (0); + } - /* - The database we ship contains the complete first line for each OUI, which includes the string "(hex)". - If we find that string, we should skip it. - */ + generate_slaac_address(&(dst->start.in6_addr), ðer, &(dummy.start.in6_addr)); + dummy.cur = dummy.start; + dummy.end = dst->end; - if( (( (char *)line + lines) - charptr) >= OUI_HEX_STRING_SIZE){ + for (i = 4; i <= 7; i++) + dummy.end.s6addr16[i] = dummy.start.s6addr16[i]; - /* If we find the "(hex)" string, we must skip it */ - if( memcmp(oui_hex_string, charptr, OUI_HEX_STRING_SIZE) == 0) - charptr+= OUI_HEX_STRING_SIZE; + /* + The three low-order bytes must vary from 0x000000 to 0xffffff + */ + dummy.end.s6addr16[6] = dummy.end.s6addr16[6] | htons(0x00ff); + dummy.end.s6addr16[7] = dummy.end.s6addr16[7] | htons(0xffff); - /* Now we mst skip any whitespaces between the "(hex)" string and the vendor name */ - while(charptr < ( (char *)line + lines) && *charptr == ' ') - charptr++; + if (add_to_scan_list(scan, &dummy) == FALSE) + return (FALSE); + } - if(charptr >= ( (char *)line + lines)) - continue; - } + if (vm_vmware_esx_f) { + /* Add scan entry for VMWare ESX Server */ + if (ether_pton("00:05:69:00:00:00", ðer, sizeof(ether)) == 0) { + if (verbose_f) + puts("scan6: ether_pton(): Error converting Ethernet Address to presentation format"); - if(match_strings(vendor, charptr)){ - /* Copy the actual OUI to our array */ - memcpy(oui_ascii, line, 8); + return (0); + } - /* Patch the dashes with colons (i.e., s/-/:/ */ - oui_ascii[2]=':'; - oui_ascii[5]=':'; + generate_slaac_address(&(dst->start.in6_addr), ðer, &(dummy.start.in6_addr)); + dummy.cur = dummy.start; + dummy.end = dst->end; - /* zero-terminate the string */ - oui_ascii[8]= 0; + for (i = 4; i <= 7; i++) + dummy.end.s6addr16[i] = dummy.start.s6addr16[i]; - strncat(oui_ascii, oui_end, ETHER_ADDR_PLEN-Strnlen(oui_ascii, sizeof(oui_ascii))-1); + /* + If we know the host system IPv4 address, we can narrow down the search space. Otherwise + the three low-order bytes must vary in the range 0x000000 to 0xffffff + */ + if (v4hostaddr_f) { + if (v4hostprefix_f) { + mask32 = 0xffffffff; + + for (i = 0; i < v4host->len; i++) + mask32 = mask32 >> 1; + } + else { + mask32 = 0; + } + + dummy.start.s6addr16[6] = dummy.start.s6addr16[6] | htons((ntohl(v4host->ip.s_addr) & 0x0000ff00) >> 8); + dummy.start.s6addr16[7] = dummy.start.s6addr16[7] | htons((ntohl(v4host->ip.s_addr) & 0x000000ff) << 8); + + dummy.end.s6addr16[6] = dummy.end.s6addr16[6] | htons((ntohl(v4host->ip.s_addr) & 0x0000ff00) >> 8) | + htonl((mask32 & 0x0000ff00) >> 8); + dummy.end.s6addr16[7] = dummy.end.s6addr16[7] | htons((ntohl(v4host->ip.s_addr) & 0x000000ff) << 8) | + htonl((mask32 & 0x000000ff) << 8) | htons(0x00ff); + } + else { + dummy.end.s6addr16[6] = dummy.end.s6addr16[6] | htons(0x00ff); + dummy.end.s6addr16[7] = dummy.end.s6addr16[7] | htons(0xffff); + } + + if (add_to_scan_list(scan, &dummy) == FALSE) + return (FALSE); + } + + if (vm_vmwarem_f) { + if (ether_pton("00:50:56:00:00:00", ðer, sizeof(ether)) == 0) { + if (verbose_f) + puts("scan6: ether_pton(): Error converting Ethernet Address to presentation format"); + + return (0); + } + + generate_slaac_address(&(dst->start.in6_addr), ðer, &(dummy.start.in6_addr)); + dummy.cur = dummy.start; + dummy.end = dst->end; + + for (i = 4; i <= 7; i++) + dummy.end.s6addr16[i] = dummy.start.s6addr16[i]; + + /* + The three low-order bytes must vary from 0x000000 to 0x3fffff + */ + dummy.end.s6addr16[6] = dummy.end.s6addr16[6] | htons(0x003f); + dummy.end.s6addr16[7] = dummy.end.s6addr16[7] | htons(0xffff); - if(ether_pton(oui_ascii, &oui_list[ouis], sizeof(oui_list[ouis])) == 0){ - if(verbose_f) - puts("scan6: ether_pton(): Error converting Ethernet Address to presentation format"); + if (add_to_scan_list(scan, &dummy) == FALSE) + return (FALSE); + } - return(0); - } + return (TRUE); +} - ouis++; - } - } +/* + * Function: load_vendor_entries() + * + * Lookup vendor's IEEE OUIs + */ +int load_vendor_entries(struct scan_list *scan, struct scan_entry *dst, char *vendor) { + FILE *fp; + struct ether_addr aux_oui, oui_list[MAX_IEEE_OUIS]; + char oui_ascii[ETHER_ADDR_PLEN]; + char *oui_end = ":00:00:00"; + char *oui_hex_string = "(hex)"; + char line[MAX_IEEE_OUIS_LINE_SIZE]; + char *charptr; + unsigned int lines = 0, ouis; + int i; + struct scan_entry dummy; + + ouis = 0; + + if ((fp = fopen(fname, "r")) == NULL) { + perror("scan6:"); + return (0); + } + + while (ouis <= MAX_IEEE_OUIS && fgets(line, MAX_IEEE_OUIS_LINE_SIZE, fp) != NULL) { + /* + We ship a minimalistic IEEE OUI "database" containing only the first "line" for each IEEE OUI. + However, in order to handle the case of users employing the OUI database directly downloaded + from the IEEE site, we perform a simple check to skip those lines that do not start with + the pattern XX-XX-XX + */ - if(ferror(fp)){ - if(verbose_f) - perror("scan6:"); + if ((lines = Strnlen(line, MAX_IEEE_OUIS_LINE_SIZE)) <= 9) + continue; - return(0); - } + if (line[2] != '-' || line[5] != '-' || line[8] != ' ') + continue; - fclose(fp); + charptr = (char *)line + 9; - /* - * If the target is a list of IEEE OUIs, we want to start trying from the newest OUIs, - * to the older OUIs. The older OUIs are left for the end, since they have probably been - * used for NICs used by legacy systems that are no longer online. Similarly, the very - * newest OUI is left for the end, since it has probably not been used (yet) for any - * commercialized Network Interface cards. - */ + /* Skip any whitespaces */ + while (charptr < ((char *)line + lines) && *charptr == ' ') + charptr++; - if(sort_ouis_f && ouis >= 4){ - aux_oui= oui_list[ouis-1]; + /* + The database we ship contains the complete first line for each OUI, which includes the string "(hex)". + If we find that string, we should skip it. + */ - for(i=ouis-2; i>=1; i--){ - oui_list[i+1]= oui_list[i]; - } + if ((((char *)line + lines) - charptr) >= OUI_HEX_STRING_SIZE) { - oui_list[1] = aux_oui; - } + /* If we find the "(hex)" string, we must skip it */ + if (memcmp(oui_hex_string, charptr, OUI_HEX_STRING_SIZE) == 0) + charptr += OUI_HEX_STRING_SIZE; - if(ouis == 0){ - if(verbose_f) - puts("scan6: Couldn't find any IEEE OUI for the target vendor"); + /* Now we mst skip any whitespaces between the "(hex)" string and the vendor name */ + while (charptr < ((char *)line + lines) && *charptr == ' ') + charptr++; - return(0); - } + if (charptr >= ((char *)line + lines)) + continue; + } + if (match_strings(vendor, charptr)) { + /* Copy the actual OUI to our array */ + memcpy(oui_ascii, line, 8); - /* We walk the IEEE OUI list backwards: from newer to older OUIs */ - for(i=ouis-1; i>=0; i--){ - if(scan->ntarget >= scan->maxtarget) - return(0); + /* Patch the dashes with colons (i.e., s/-/:/ */ + oui_ascii[2] = ':'; + oui_ascii[5] = ':'; - generate_slaac_address(&(dst->start.in6_addr), &oui_list[i], &(dummy.start.in6_addr)); - dummy.cur= dummy.start; - generate_slaac_address(&(dst->end.in6_addr), &oui_list[i], &(dummy.end.in6_addr)); + /* zero-terminate the string */ + oui_ascii[8] = 0; - /* - The three low-order bytes must vary from 0x000000 to 0xffffff - */ - dummy.end.s6addr16[6]= dummy.end.s6addr16[6] | htons(0x00ff); - dummy.end.s6addr16[7]= dummy.end.s6addr16[6] | htons(0xffff); + strncat(oui_ascii, oui_end, ETHER_ADDR_PLEN - Strnlen(oui_ascii, sizeof(oui_ascii)) - 1); - if(add_to_scan_list(scan, &dummy) == FALSE) - return(FALSE); - } + if (ether_pton(oui_ascii, &oui_list[ouis], sizeof(oui_list[ouis])) == 0) { + if (verbose_f) + puts("scan6: ether_pton(): Error converting Ethernet Address to presentation format"); - return(1); -} + return (0); + } + ouis++; + } + } + + if (ferror(fp)) { + if (verbose_f) + perror("scan6:"); + + return (0); + } + + fclose(fp); + + /* + * If the target is a list of IEEE OUIs, we want to start trying from the newest OUIs, + * to the older OUIs. The older OUIs are left for the end, since they have probably been + * used for NICs used by legacy systems that are no longer online. Similarly, the very + * newest OUI is left for the end, since it has probably not been used (yet) for any + * commercialized Network Interface cards. + */ + + if (sort_ouis_f && ouis >= 4) { + aux_oui = oui_list[ouis - 1]; + + for (i = ouis - 2; i >= 1; i--) { + oui_list[i + 1] = oui_list[i]; + } + + oui_list[1] = aux_oui; + } + + if (ouis == 0) { + if (verbose_f) + puts("scan6: Couldn't find any IEEE OUI for the target vendor"); + + return (0); + } + + /* We walk the IEEE OUI list backwards: from newer to older OUIs */ + for (i = ouis - 1; i >= 0; i--) { + if (scan->ntarget >= scan->maxtarget) + return (0); + + generate_slaac_address(&(dst->start.in6_addr), &oui_list[i], &(dummy.start.in6_addr)); + dummy.cur = dummy.start; + generate_slaac_address(&(dst->end.in6_addr), &oui_list[i], &(dummy.end.in6_addr)); + + /* + The three low-order bytes must vary from 0x000000 to 0xffffff + */ + dummy.end.s6addr16[6] = dummy.end.s6addr16[6] | htons(0x00ff); + dummy.end.s6addr16[7] = dummy.end.s6addr16[6] | htons(0xffff); + + if (add_to_scan_list(scan, &dummy) == FALSE) + return (FALSE); + } + + return (1); +} /* * Function: match_strings() @@ -4056,1043 +4019,1029 @@ int load_vendor_entries(struct scan_list *scan, struct scan_entry *dst, char *ve * Checks whether one string "matches" within another string */ -int match_strings(char *buscar, char *buffer){ - unsigned int buscars, buffers; - unsigned int i=0, j=0; +int match_strings(char *buscar, char *buffer) { + unsigned int buscars, buffers; + unsigned int i = 0, j = 0; - buscars= Strnlen(buscar, MAX_IEEE_OUIS_LINE_SIZE); - buffers= Strnlen(buffer, MAX_IEEE_OUIS_LINE_SIZE); + buscars = Strnlen(buscar, MAX_IEEE_OUIS_LINE_SIZE); + buffers = Strnlen(buffer, MAX_IEEE_OUIS_LINE_SIZE); - if(buscars > buffers) - return(0); + if (buscars > buffers) + return (0); - while(i <= (buffers - buscars)){ - j=0; + while (i <= (buffers - buscars)) { + j = 0; - while(j < buscars){ - if(toupper((int) ((unsigned char)buscar[j])) != toupper((int) ((unsigned char)buffer[i+j]))) - break; + while (j < buscars) { + if (toupper((int)((unsigned char)buscar[j])) != toupper((int)((unsigned char)buffer[i + j]))) + break; - j++; - } + j++; + } - if(j >= buscars) - return(1); + if (j >= buscars) + return (1); - i++; - } + i++; + } - return(0); + return (0); } - /* * Function: load_bruteforce_entries() * * Converts a target prefix to scan_entry format */ -int load_bruteforce_entries(struct scan_list *scan, struct scan_entry *dst){ - if(scan->ntarget >= scan->maxtarget) - return(0); +int load_bruteforce_entries(struct scan_list *scan, struct scan_entry *dst) { + if (scan->ntarget >= scan->maxtarget) + return (0); - return(add_to_scan_list(scan, dst)); + return (add_to_scan_list(scan, dst)); } - /* * Function: load_smart_entries() * * Loads targets based on IID type */ -int load_smart_entries(struct scan_list *scan, struct scan_list *smart){ - struct decode6 decode; - unsigned int i, j; - struct scan_entry dummy; - - for(i=0; i < smart->ntarget; i++){ - decode.ip6= (smart->target[i])->start.in6_addr; - decode_ipv6_address(&decode); - - dummy= *(smart->target[i]); - - switch(decode.iidtype){ - case IID_MACDERIVED: - dummy.start.s6addr32[3]= dummy.start.s6addr32[3] & htonl(0xff000000); - dummy.end= dummy.start; - dummy.end.s6addr32[3]= dummy.end.s6addr32[3] | htonl(0x00ffffff); - dummy.cur= dummy.start; - - if(add_to_scan_list(scan, &dummy) == FALSE) - return(FALSE); - break; - - case IID_ISATAP: - dummy.start.s6addr32[3]= dummy.start.s6addr32[3] & htonl(0xffff0000); - dummy.end= dummy.start; - dummy.end.s6addr32[3]= dummy.end.s6addr32[3] | htonl(0x0000ffff); - dummy.cur= dummy.start; - - if(add_to_scan_list(scan, &dummy) == FALSE) - return(FALSE); - break; - - case IID_LOWBYTE: - case IID_EMBEDDEDPORT: - case IID_EMBEDDEDPORTREV: - case IID_UNSPECIFIED: - case IID_RANDOM: - /* - Embedded-port addresses are rather unlikely, and usully a false-positive resulting from low-byte - addresses. Hence we scan for low-byte addresses when "embedded port" addresses are detected. - */ - - for(j=4; j<=7; j++) - dummy.start.s6addr16[j]= 0; - - dummy.end= dummy.start; - dummy.end.s6addr16[6]= htons(LOW_BYTE_2ND_WORD_UPPER); - dummy.end.s6addr16[7]= htons(LOW_BYTE_1ST_WORD_UPPER); - dummy.cur= dummy.start; - - if(add_to_scan_list(scan, &dummy) == FALSE) - return(FALSE); - break; - - case IID_EMBEDDEDIPV4: - switch(decode.iidsubtype){ - case IID_EMBEDDEDIPV4_32: - dummy.start.s6addr32[2]= htonl(0x00000000); - dummy.start.s6addr32[3]= dummy.start.s6addr32[3] & htonl(0xffff0000); - dummy.end= dummy.start; - dummy.end.s6addr32[3]= dummy.end.s6addr32[3] | htonl(0x0000ffff); - dummy.cur= dummy.start; - - if(add_to_scan_list(scan, &dummy) == FALSE) - return(FALSE); - break; - - case IID_EMBEDDEDIPV4_64: - dummy.start.s6addr32[2]= dummy.start.s6addr32[2] & htonl(0x00ff00ff); - dummy.start.s6addr32[3]= htonl(0x00000000); - dummy.end= dummy.start; - dummy.end.s6addr32[3]= dummy.end.s6addr32[3] | htonl(0x00ff00ff); - dummy.cur= dummy.start; - - if(add_to_scan_list(scan, &dummy) == FALSE) - return(FALSE); - break; - } - - break; - - case IID_PATTERN_BYTES: - dummy.end= dummy.start; - - for(j=8; j<16; j++) - dummy.end.s6addr[j]= (dummy.start.s6addr[j])?0xff:0x00; - - for(j=8; j<16; j++) - dummy.start.s6addr[j]= 0x00; - - dummy.cur= dummy.start; - - if(add_to_scan_list(scan, &dummy) == FALSE) - return(FALSE); - break; - - case IID_TEREDO_RFC5991: - case IID_TEREDO_RFC4380: - case IID_TEREDO_UNKNOWN: - for(j=8; j<=11; j++) - dummy.start.s6addr[j]= 0x00; - - dummy.end= dummy.start; - - dummy.start.s6addr[8]= 0xbc; - - for(j=9; j<=11; j++) - dummy.start.s6addr[8]= 0xff; - - dummy.cur= dummy.start; - - if(add_to_scan_list(scan, &dummy) == FALSE) - return(FALSE); - break; - - default: - /* By default we scan for low-byte-addresses (same code as above) */ - for(j=8; j<16; j++) - dummy.start.s6addr[j]= 0x00; - - for(j=8; j<16; j++) - dummy.end.s6addr[j]= 0xff; - - dummy.cur= dummy.start; - - if(add_to_scan_list(scan, &dummy) == FALSE) - return(FALSE); - break; - } - } +int load_smart_entries(struct scan_list *scan, struct scan_list *smart) { + struct decode6 decode; + unsigned int i, j; + struct scan_entry dummy; + + for (i = 0; i < smart->ntarget; i++) { + decode.ip6 = (smart->target[i])->start.in6_addr; + decode_ipv6_address(&decode); + + dummy = *(smart->target[i]); + + switch (decode.iidtype) { + case IID_MACDERIVED: + dummy.start.s6addr32[3] = dummy.start.s6addr32[3] & htonl(0xff000000); + dummy.end = dummy.start; + dummy.end.s6addr32[3] = dummy.end.s6addr32[3] | htonl(0x00ffffff); + dummy.cur = dummy.start; + + if (add_to_scan_list(scan, &dummy) == FALSE) + return (FALSE); + break; + + case IID_ISATAP: + dummy.start.s6addr32[3] = dummy.start.s6addr32[3] & htonl(0xffff0000); + dummy.end = dummy.start; + dummy.end.s6addr32[3] = dummy.end.s6addr32[3] | htonl(0x0000ffff); + dummy.cur = dummy.start; + + if (add_to_scan_list(scan, &dummy) == FALSE) + return (FALSE); + break; + + case IID_LOWBYTE: + case IID_EMBEDDEDPORT: + case IID_EMBEDDEDPORTREV: + case IID_UNSPECIFIED: + case IID_RANDOM: + /* + Embedded-port addresses are rather unlikely, and usully a false-positive resulting from low-byte + addresses. Hence we scan for low-byte addresses when "embedded port" addresses are detected. + */ + + for (j = 4; j <= 7; j++) + dummy.start.s6addr16[j] = 0; + + dummy.end = dummy.start; + dummy.end.s6addr16[6] = htons(LOW_BYTE_2ND_WORD_UPPER); + dummy.end.s6addr16[7] = htons(LOW_BYTE_1ST_WORD_UPPER); + dummy.cur = dummy.start; + + if (add_to_scan_list(scan, &dummy) == FALSE) + return (FALSE); + break; + + case IID_EMBEDDEDIPV4: + switch (decode.iidsubtype) { + case IID_EMBEDDEDIPV4_32: + dummy.start.s6addr32[2] = htonl(0x00000000); + dummy.start.s6addr32[3] = dummy.start.s6addr32[3] & htonl(0xffff0000); + dummy.end = dummy.start; + dummy.end.s6addr32[3] = dummy.end.s6addr32[3] | htonl(0x0000ffff); + dummy.cur = dummy.start; + + if (add_to_scan_list(scan, &dummy) == FALSE) + return (FALSE); + break; + + case IID_EMBEDDEDIPV4_64: + dummy.start.s6addr32[2] = dummy.start.s6addr32[2] & htonl(0x00ff00ff); + dummy.start.s6addr32[3] = htonl(0x00000000); + dummy.end = dummy.start; + dummy.end.s6addr32[3] = dummy.end.s6addr32[3] | htonl(0x00ff00ff); + dummy.cur = dummy.start; + + if (add_to_scan_list(scan, &dummy) == FALSE) + return (FALSE); + break; + } + + break; + + case IID_PATTERN_BYTES: + dummy.end = dummy.start; + + for (j = 8; j < 16; j++) + dummy.end.s6addr[j] = (dummy.start.s6addr[j]) ? 0xff : 0x00; + + for (j = 8; j < 16; j++) + dummy.start.s6addr[j] = 0x00; + + dummy.cur = dummy.start; + + if (add_to_scan_list(scan, &dummy) == FALSE) + return (FALSE); + break; + + case IID_TEREDO_RFC5991: + case IID_TEREDO_RFC4380: + case IID_TEREDO_UNKNOWN: + for (j = 8; j <= 11; j++) + dummy.start.s6addr[j] = 0x00; + + dummy.end = dummy.start; + + dummy.start.s6addr[8] = 0xbc; + + for (j = 9; j <= 11; j++) + dummy.start.s6addr[8] = 0xff; + + dummy.cur = dummy.start; + + if (add_to_scan_list(scan, &dummy) == FALSE) + return (FALSE); + break; + + default: + /* By default we scan for low-byte-addresses (same code as above) */ + for (j = 8; j < 16; j++) + dummy.start.s6addr[j] = 0x00; + + for (j = 8; j < 16; j++) + dummy.end.s6addr[j] = 0xff; + + dummy.cur = dummy.start; + + if (add_to_scan_list(scan, &dummy) == FALSE) + return (FALSE); + break; + } + } - return(TRUE); + return (TRUE); } - /* * Function: prefix_to_scan() * * Converts a target prefix to scan_entry format */ -void prefix_to_scan(struct prefix_entry *pref, struct scan_entry *scan){ - uint32_t mask; - uint8_t words; - unsigned int i; +void prefix_to_scan(struct prefix_entry *pref, struct scan_entry *scan) { + uint32_t mask; + uint8_t words; + unsigned int i; - scan->start.in6_addr= pref->ip6; - scan->cur.in6_addr= pref->ip6; - words= pref->len/32; + scan->start.in6_addr = pref->ip6; + scan->cur.in6_addr = pref->ip6; + words = pref->len / 32; - for(i=0; i< words; i++) - (scan->end).in6_addr.s6_addr32[i]= (pref->ip6).s6_addr32[i]; + for (i = 0; i < words; i++) + (scan->end).in6_addr.s6_addr32[i] = (pref->ip6).s6_addr32[i]; - for(i= (words+1); i<4; i++){ - (scan->end).in6_addr.s6_addr32[i]= htonl(0xffffffff); - } + for (i = (words + 1); i < 4; i++) { + (scan->end).in6_addr.s6_addr32[i] = htonl(0xffffffff); + } - mask=0xffffffff; + mask = 0xffffffff; - for(i=0; i< (pref->len % 32); i++) - mask= mask>>1; + for (i = 0; i < (pref->len % 32); i++) + mask = mask >> 1; - if(pref->len % 32) - (scan->end).in6_addr.s6_addr32[words]= (scan->start).in6_addr.s6_addr32[words] | htonl(mask); + if (pref->len % 32) + (scan->end).in6_addr.s6_addr32[words] = (scan->start).in6_addr.s6_addr32[words] | htonl(mask); } - - - /* * Function: usage() * * Prints the syntax of the scan6 tool */ -void usage(void){ - puts("usage: scan6 (-L | -d) [-i INTERFACE] [-s SRC_ADDR[/LEN] | -f] \n" - " [-S LINK_SRC_ADDR | -F] [-p PROBE_TYPE] [-Z PAYLOAD_SIZE] [-o SRC_PORT]\n" - " [-a DST_PORT] [-X TCP_FLAGS] [-P ADDRESS_TYPE] [-q] [-e] [-t]\n" - " [-x RETRANS] [-o TIMEOUT] [-V VM_TYPE] [-b] [-B ENCODING] [-g]\n" - " [-k IEEE_OUI] [-K VENDOR] [-m PREFIXES_FILE] [-w IIDS_FILE] [-W IID]\n" - " [-Q IPV4_PREFIX[/LEN]] [-T] [-I INC_SIZE] [-r RATE(bps|pps)] [-l]\n" - " [-z SECONDS] [-c CONFIG_FILE] [-v] [-h]"); +void usage(void) { + puts("usage: scan6 (-L | -d) [-i INTERFACE] [-s SRC_ADDR[/LEN] | -f] \n" + " [-S LINK_SRC_ADDR | -F] [-p PROBE_TYPE] [-Z PAYLOAD_SIZE] [-o SRC_PORT]\n" + " [-a DST_PORT] [-X TCP_FLAGS] [-P ADDRESS_TYPE] [-q] [-e] [-t]\n" + " [-x RETRANS] [-o TIMEOUT] [-V VM_TYPE] [-b] [-B ENCODING] [-g]\n" + " [-k IEEE_OUI] [-K VENDOR] [-m PREFIXES_FILE] [-w IIDS_FILE] [-W IID]\n" + " [-Q IPV4_PREFIX[/LEN]] [-T] [-I INC_SIZE] [-r RATE(bps|pps)] [-l]\n" + " [-z SECONDS] [-c CONFIG_FILE] [-v] [-h]"); } - /* * Function: print_help() * * Prints help information for the scan6 tool */ -void print_help(void){ - puts(SI6_TOOLKIT); - puts( "scan6: An advanced IPv6 scanning tool\n"); - usage(); - - puts("\nOPTIONS:\n" - " --interface, -i Network interface\n" - " --src-addr, -s IPv6 Source Address\n" - " --dst-addr, -d IPv6 Destination Range or Prefix\n" - " --prefixes-file, -m Prefixes file\n" - " --link-src-addr, -S Link-layer Destination Address\n" - " --probe-type, -p Probe type for host scanning {echo, unrec, all}\n" - " --port-scan, -j Port scan type and range {tcp,udp}:port_low[-port_hi]\n" - " --tcp-scan-type, -G TCP port-scanning type {syn,fin,null,xmas,ack}\n" - " --payload-size, -Z TCP/UDP Payload Size\n" - " --src-port, -o TCP/UDP Source Port\n" - " --dst-port, -a TCP/UDP Destination Port\n" - " --tcp-flags, -X TCP Flags\n" - " --print-type, -P Print address type {local, global, all}\n" - " --print-unique, -q Print only one IPv6 addresses per Ethernet address\n" - " --print-link-addr, -e Print link-layer addresses\n" - " --print-timestamp, -t Print timestamp for each alive node\n" - " --retrans, -x Number of retransmissions of each probe\n" - " --timeout, -O Timeout in seconds (default: 1 second)\n" - " --local-scan, -L Scan the local subnet\n" - " --rand-src-addr, -f Randomize the IPv6 Source Address\n" - " --rand-link-src-addr, -F Randomize the Ethernet Source Address\n" - " --tgt-virtual-machines, -V Target virtual machines\n" - " --tgt-low-byte, -b Target low-byte addresses\n" - " --tgt-ipv4, -B Target embedded-IPv4 addresses\n" - " --tgt-port, -g Target embedded-port addresses\n" - " --tgt-ieee-oui, -k Target IPv6 addresses embedding IEEE OUI\n" - " --tgt-vendor, -K Target IPv6 addresses for vendor's IEEE OUIs\n" - " --tgt-iids-file, -w Target Interface IDs (IIDs) in specified file\n" - " --tgt-iid, -W Target Interface IDs (IIDs)\n" - " --ipv4-host, -Q Host IPv4 Address/Prefix\n" - " --sort-ouis, -T Sort IEEE OUIs\n" - " --inc-size, -I Increments size\n" - " --rate-limit, -r Rate limit the address scan to specified rate\n" - " --loop, -l Send periodic probes to the specified targets\n" - " --sleep, -z Pause between periodic probes\n" - " --config-file, -c Use alternate configuration file\n" - " --help, -h Print help for the scan6 tool\n" - " --verbose, -v Be verbose\n" - "\n" - " Programmed by Fernando Gont for SI6 Networks \n" - " Please send any bug reports to \n" - ); +void print_help(void) { + puts(SI6_TOOLKIT); + puts("scan6: An advanced IPv6 scanning tool\n"); + usage(); + + puts("\nOPTIONS:\n" + " --interface, -i Network interface\n" + " --src-addr, -s IPv6 Source Address\n" + " --dst-addr, -d IPv6 Destination Range or Prefix\n" + " --prefixes-file, -m Prefixes file\n" + " --link-src-addr, -S Link-layer Destination Address\n" + " --probe-type, -p Probe type for host scanning {echo, unrec, all}\n" + " --port-scan, -j Port scan type and range {tcp,udp}:port_low[-port_hi]\n" + " --tcp-scan-type, -G TCP port-scanning type {syn,fin,null,xmas,ack}\n" + " --payload-size, -Z TCP/UDP Payload Size\n" + " --src-port, -o TCP/UDP Source Port\n" + " --dst-port, -a TCP/UDP Destination Port\n" + " --tcp-flags, -X TCP Flags\n" + " --print-type, -P Print address type {local, global, all}\n" + " --print-unique, -q Print only one IPv6 addresses per Ethernet address\n" + " --print-link-addr, -e Print link-layer addresses\n" + " --print-timestamp, -t Print timestamp for each alive node\n" + " --retrans, -x Number of retransmissions of each probe\n" + " --timeout, -O Timeout in seconds (default: 1 second)\n" + " --local-scan, -L Scan the local subnet\n" + " --rand-src-addr, -f Randomize the IPv6 Source Address\n" + " --rand-link-src-addr, -F Randomize the Ethernet Source Address\n" + " --tgt-virtual-machines, -V Target virtual machines\n" + " --tgt-low-byte, -b Target low-byte addresses\n" + " --tgt-ipv4, -B Target embedded-IPv4 addresses\n" + " --tgt-port, -g Target embedded-port addresses\n" + " --tgt-ieee-oui, -k Target IPv6 addresses embedding IEEE OUI\n" + " --tgt-vendor, -K Target IPv6 addresses for vendor's IEEE OUIs\n" + " --tgt-iids-file, -w Target Interface IDs (IIDs) in specified file\n" + " --tgt-iid, -W Target Interface IDs (IIDs)\n" + " --ipv4-host, -Q Host IPv4 Address/Prefix\n" + " --sort-ouis, -T Sort IEEE OUIs\n" + " --inc-size, -I Increments size\n" + " --rate-limit, -r Rate limit the address scan to specified rate\n" + " --loop, -l Send periodic probes to the specified targets\n" + " --sleep, -z Pause between periodic probes\n" + " --config-file, -c Use alternate configuration file\n" + " --help, -h Print help for the scan6 tool\n" + " --verbose, -v Be verbose\n" + "\n" + " Programmed by Fernando Gont for SI6 Networks \n" + " Please send any bug reports to \n"); } - - /* * Function: send_probe_remote() * * Sends a probe packet to a remote target */ -int send_probe_remote(struct iface_data *idata, struct scan_list *scan, struct in6_addr *srcaddr, unsigned char type){ - unsigned char *ptr; - unsigned int i; - struct ether_header *ether; - struct dlt_null *dlt_null; +int send_probe_remote(struct iface_data *idata, struct scan_list *scan, struct in6_addr *srcaddr, unsigned char type) { + unsigned char *ptr; + unsigned int i; + struct ether_header *ether; + struct dlt_null *dlt_null; #if defined(__linux__) - struct sll_linux *sll_linux; + struct sll_linux *sll_linux; #endif - unsigned char *v6buffer; - struct ip6_hdr *ipv6; - struct tcp_hdr *tcp; - struct ip6_dest *destopth; - struct ip6_option *opt; - uint32_t *uint32; - - ether = (struct ether_header *) buffer; - dlt_null= (struct dlt_null *) buffer; + unsigned char *v6buffer; + struct ip6_hdr *ipv6; + struct tcp_hdr *tcp; + struct ip6_dest *destopth; + struct ip6_option *opt; + uint32_t *uint32; + + ether = (struct ether_header *)buffer; + dlt_null = (struct dlt_null *)buffer; #if defined(__linux__) - sll_linux= (struct sll_linux *) buffer; + sll_linux = (struct sll_linux *)buffer; #endif - v6buffer = buffer + idata->linkhsize; - ipv6 = (struct ip6_hdr *) v6buffer; - - if(idata->type == DLT_EN10MB){ - ether->ether_type = htons(ETHERTYPE_IPV6); - - if(!(idata->flags & IFACE_LOOPBACK)){ - ether->src = idata->ether; - - if(!onlink_f){ - ether->dst = idata->nhhaddr; - }else{ - if(ipv6_to_ether(idata->pfd, idata, &(scan->target[scan->ctarget])->cur.in6_addr, &(idata->hdstaddr)) != 1){ - return(1); - } - } - } - } - else if(idata->type == DLT_NULL){ - dlt_null->family= PF_INET6; - } -#if defined (__OpenBSD__) - else if(idata->type == DLT_LOOP){ - dlt_null->family= htonl(PF_INET6); - } + v6buffer = buffer + idata->linkhsize; + ipv6 = (struct ip6_hdr *)v6buffer; + + if (idata->type == DLT_EN10MB) { + ether->ether_type = htons(ETHERTYPE_IPV6); + + if (!(idata->flags & IFACE_LOOPBACK)) { + ether->src = idata->ether; + + if (!onlink_f) { + ether->dst = idata->nhhaddr; + } + else { + if (ipv6_to_ether(idata->pfd, idata, &(scan->target[scan->ctarget])->cur.in6_addr, + &(idata->hdstaddr)) != 1) { + return (1); + } + } + } + } + else if (idata->type == DLT_NULL) { + dlt_null->family = PF_INET6; + } +#if defined(__OpenBSD__) + else if (idata->type == DLT_LOOP) { + dlt_null->family = htonl(PF_INET6); + } #elif defined(__linux__) - else if(idata->type == DLT_LINUX_SLL){ - sll_linux->sll_pkttype= htons(0x0004); - sll_linux->sll_hatype= htons(0xffff); - sll_linux->sll_halen= htons(0x0000); - sll_linux->sll_protocol= htons(ETHERTYPE_IPV6); - } + else if (idata->type == DLT_LINUX_SLL) { + sll_linux->sll_pkttype = htons(0x0004); + sll_linux->sll_hatype = htons(0xffff); + sll_linux->sll_halen = htons(0x0000); + sll_linux->sll_protocol = htons(ETHERTYPE_IPV6); + } #endif - ipv6->ip6_flow=0; - ipv6->ip6_vfc= 0x60; - ipv6->ip6_hlim= 255; + ipv6->ip6_flow = 0; + ipv6->ip6_vfc = 0x60; + ipv6->ip6_hlim = 255; - /* XXX Double-check this one */ - ipv6->ip6_src= idata->srcaddr_f?(*srcaddr):*sel_src_addr_ra(idata, &((scan->target[scan->ctarget])->cur.in6_addr)); - ipv6->ip6_dst= (scan->target[scan->ctarget])->cur.in6_addr; + /* XXX Double-check this one */ + ipv6->ip6_src = + idata->srcaddr_f ? (*srcaddr) : *sel_src_addr_ra(idata, &((scan->target[scan->ctarget])->cur.in6_addr)); + ipv6->ip6_dst = (scan->target[scan->ctarget])->cur.in6_addr; #ifdef DEBUG -print_ipv6_address("Direccion actual:", &((scan->target[scan->ctarget])->cur.in6_addr)); + print_ipv6_address("Direccion actual:", &((scan->target[scan->ctarget])->cur.in6_addr)); #endif - prev_nh = (unsigned char *) &(ipv6->ip6_nxt); + prev_nh = (unsigned char *)&(ipv6->ip6_nxt); - ptr = (unsigned char *) v6buffer + MIN_IPV6_HLEN; + ptr = (unsigned char *)v6buffer + MIN_IPV6_HLEN; - switch(type){ - case PROBE_ICMP6_ECHO: - *prev_nh = IPPROTO_ICMPV6; + switch (type) { + case PROBE_ICMP6_ECHO: + *prev_nh = IPPROTO_ICMPV6; - if( (ptr+sizeof(struct icmp6_hdr)+ICMPV6_ECHO_PAYLOAD_SIZE) > (v6buffer+idata->mtu)){ - if(idata->verbose_f>1) - puts("Packet too large while creating ICMPv6 Echo Request Probe packet"); + if ((ptr + sizeof(struct icmp6_hdr) + ICMPV6_ECHO_PAYLOAD_SIZE) > (v6buffer + idata->mtu)) { + if (idata->verbose_f > 1) + puts("Packet too large while creating ICMPv6 Echo Request Probe packet"); - return(-1); - } + return (-1); + } - icmp6 = (struct icmp6_hdr *) ptr; - icmp6->icmp6_type = ICMP6_ECHO_REQUEST; - icmp6->icmp6_code = 0; - icmp6->icmp6_data16[0]= htons(getpid()); /* Identifier */ - icmp6->icmp6_data16[1]= htons(0); /* Sequence Number */ + icmp6 = (struct icmp6_hdr *)ptr; + icmp6->icmp6_type = ICMP6_ECHO_REQUEST; + icmp6->icmp6_code = 0; + icmp6->icmp6_data16[0] = htons(getpid()); /* Identifier */ + icmp6->icmp6_data16[1] = htons(0); /* Sequence Number */ - ptr = ptr+ sizeof(struct icmp6_hdr); + ptr = ptr + sizeof(struct icmp6_hdr); - for(i=0; i<(ICMPV6_ECHO_PAYLOAD_SIZE>>2); i++){ - *(uint32_t *)ptr = random(); - ptr += sizeof(uint32_t); - } - - ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); - icmp6->icmp6_cksum = 0; - icmp6->icmp6_cksum = in_chksum(v6buffer, icmp6, ptr-((unsigned char *)icmp6), IPPROTO_ICMPV6); - break; - - case PROBE_UNREC_OPT: - *prev_nh = IPPROTO_DSTOPTS; - - if( (ptr+sizeof(struct icmp6_hdr) + 8 + ICMPV6_ECHO_PAYLOAD_SIZE) > (v6buffer+idata->mtu)){ - if(idata->verbose_f>1) - puts("Packet too large while creating Unrec. Opt. Probe Packet"); - - return(-1); - } - - destopth = (struct ip6_dest *) ptr; - destopth->ip6d_len= 0; - destopth->ip6d_nxt= IPPROTO_ICMPV6; - - ptr= ptr + 2; - opt= (struct ip6_option *) ptr; - opt->ip6o_type= 0x80; - opt->ip6o_len= 4; - - ptr= ptr + 2; - uint32 = (uint32_t *) ptr; - *uint32 = random(); - - ptr= ptr +4; - icmp6 = (struct icmp6_hdr *) ptr; - icmp6->icmp6_type = ICMP6_ECHO_REQUEST; - icmp6->icmp6_code = 0; - icmp6->icmp6_data16[0]= htons(getpid()); /* Identifier */ - icmp6->icmp6_data16[1]= htons(0); /* Sequence Number */ - - ptr = ptr+ sizeof(struct icmp6_hdr); - - for(i=0; i<(ICMPV6_ECHO_PAYLOAD_SIZE>>2); i++){ - *(uint32_t *)ptr = random(); - ptr += sizeof(uint32_t); - } - - ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); - icmp6->icmp6_cksum = 0; - icmp6->icmp6_cksum = in_chksum(v6buffer, icmp6, ptr-((unsigned char *)icmp6), IPPROTO_ICMPV6); - break; - - case PROBE_TCP: - *prev_nh = IPPROTO_TCP; - - if( (ptr+sizeof(struct tcp_hdr)) > (v6buffer + idata->max_packet_size)){ - if(idata->verbose_f) - puts("Packet Too Large while inserting TCP header"); - - return(0); - } - - tcp = (struct tcp_hdr *) ptr; - memset(tcp, 0, sizeof(struct tcp_hdr)); - - if(srcport_f) - tcp->th_sport= htons(srcport); - else - tcp->th_sport= htons(1024+ random() % 64512); - - if(dstport_f) - tcp->th_dport= htons(dstport); - else - tcp->th_dport= htons(1+ random() % 1024); - - if(tcpflags_f) - tcp->th_flags= tcpflags; - else - tcp->th_flags= TH_ACK; - - if(tcpflags & TH_ACK) - tcp->th_ack= htonl(random()); - else - tcp->th_ack= htonl(0); - - tcp->th_win= htons( 4096 * (random() % 9 + 1)); - - /* Current version of tcp6 does not support sending TCP options */ - tcp->th_off= sizeof(struct tcp_hdr) >> 2; - ptr+= tcp->th_off << 2; - - if( (ptr + rhbytes) > v6buffer+idata->max_packet_size){ - puts("Packet Too Large while inserting TCP segment"); - exit(EXIT_FAILURE); - } - - while(rhbytes>=4){ - *(uint32_t *)ptr = random(); - ptr += sizeof(uint32_t); - rhbytes -= sizeof(uint32_t); - } - - while(rhbytes>0){ - *(uint8_t *) ptr= (uint8_t) random(); - ptr++; - rhbytes--; - } - - ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); - tcp->th_sum = 0; - tcp->th_sum = in_chksum(v6buffer, tcp, ptr-((unsigned char *)tcp), IPPROTO_TCP); - break; - } + for (i = 0; i < (ICMPV6_ECHO_PAYLOAD_SIZE >> 2); i++) { + *(uint32_t *)ptr = random(); + ptr += sizeof(uint32_t); + } + + ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); + icmp6->icmp6_cksum = 0; + icmp6->icmp6_cksum = in_chksum(v6buffer, icmp6, ptr - ((unsigned char *)icmp6), IPPROTO_ICMPV6); + break; + + case PROBE_UNREC_OPT: + *prev_nh = IPPROTO_DSTOPTS; + + if ((ptr + sizeof(struct icmp6_hdr) + 8 + ICMPV6_ECHO_PAYLOAD_SIZE) > (v6buffer + idata->mtu)) { + if (idata->verbose_f > 1) + puts("Packet too large while creating Unrec. Opt. Probe Packet"); + + return (-1); + } + + destopth = (struct ip6_dest *)ptr; + destopth->ip6d_len = 0; + destopth->ip6d_nxt = IPPROTO_ICMPV6; + + ptr = ptr + 2; + opt = (struct ip6_option *)ptr; + opt->ip6o_type = 0x80; + opt->ip6o_len = 4; + + ptr = ptr + 2; + uint32 = (uint32_t *)ptr; + *uint32 = random(); + + ptr = ptr + 4; + icmp6 = (struct icmp6_hdr *)ptr; + icmp6->icmp6_type = ICMP6_ECHO_REQUEST; + icmp6->icmp6_code = 0; + icmp6->icmp6_data16[0] = htons(getpid()); /* Identifier */ + icmp6->icmp6_data16[1] = htons(0); /* Sequence Number */ + + ptr = ptr + sizeof(struct icmp6_hdr); + + for (i = 0; i < (ICMPV6_ECHO_PAYLOAD_SIZE >> 2); i++) { + *(uint32_t *)ptr = random(); + ptr += sizeof(uint32_t); + } + + ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); + icmp6->icmp6_cksum = 0; + icmp6->icmp6_cksum = in_chksum(v6buffer, icmp6, ptr - ((unsigned char *)icmp6), IPPROTO_ICMPV6); + break; + + case PROBE_TCP: + *prev_nh = IPPROTO_TCP; + + if ((ptr + sizeof(struct tcp_hdr)) > (v6buffer + idata->max_packet_size)) { + if (idata->verbose_f) + puts("Packet Too Large while inserting TCP header"); + + return (0); + } + + tcp = (struct tcp_hdr *)ptr; + memset(tcp, 0, sizeof(struct tcp_hdr)); + + if (srcport_f) + tcp->th_sport = htons(srcport); + else + tcp->th_sport = htons(1024 + random() % 64512); + + if (dstport_f) + tcp->th_dport = htons(dstport); + else + tcp->th_dport = htons(1 + random() % 1024); + + if (tcpflags_f) + tcp->th_flags = tcpflags; + else + tcp->th_flags = TH_ACK; + + if (tcpflags & TH_ACK) + tcp->th_ack = htonl(random()); + else + tcp->th_ack = htonl(0); + + tcp->th_win = htons(4096 * (random() % 9 + 1)); + + /* Current version of tcp6 does not support sending TCP options */ + tcp->th_off = sizeof(struct tcp_hdr) >> 2; + ptr += tcp->th_off << 2; + + if ((ptr + rhbytes) > v6buffer + idata->max_packet_size) { + puts("Packet Too Large while inserting TCP segment"); + exit(EXIT_FAILURE); + } + + while (rhbytes >= 4) { + *(uint32_t *)ptr = random(); + ptr += sizeof(uint32_t); + rhbytes -= sizeof(uint32_t); + } + + while (rhbytes > 0) { + *(uint8_t *)ptr = (uint8_t)random(); + ptr++; + rhbytes--; + } + + ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); + tcp->th_sum = 0; + tcp->th_sum = in_chksum(v6buffer, tcp, ptr - ((unsigned char *)tcp), IPPROTO_TCP); + break; + } #ifdef DEBUG -puts("In send_probe_remote(), prior to send"); + puts("In send_probe_remote(), prior to send"); #endif - if((nw=pcap_inject(idata->pfd, buffer, ptr - buffer)) == -1){ - if(idata->verbose_f) - printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); + if ((nw = pcap_inject(idata->pfd, buffer, ptr - buffer)) == -1) { + if (idata->verbose_f) + printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); - return(0); - } + return (0); + } #ifdef DEBUG -puts("In send_probe_remote(), after to send"); + puts("In send_probe_remote(), after to send"); #endif - if(nw != (ptr-buffer)){ - if(idata->verbose_f) - printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, \ - (LUI) (ptr-buffer)); - return(0); - } + if (nw != (ptr - buffer)) { + if (idata->verbose_f) + printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, (LUI)(ptr - buffer)); + return (0); + } - return(1); + return (1); } - - /* * Function: send_pscan_probe() * * Sends a probe packet to a target port */ -int send_pscan_probe(struct iface_data *idata, struct scan_list *scan, struct port_list *port_list, struct in6_addr *srcaddr, unsigned char type){ - unsigned char *ptr; - struct ether_header *ether; - struct dlt_null *dlt_null; +int send_pscan_probe(struct iface_data *idata, struct scan_list *scan, struct port_list *port_list, + struct in6_addr *srcaddr, unsigned char type) { + unsigned char *ptr; + struct ether_header *ether; + struct dlt_null *dlt_null; #if defined(__linux__) - struct sll_linux *sll_linux; + struct sll_linux *sll_linux; #endif - unsigned char *v6buffer; - struct ip6_hdr *ipv6; - struct tcp_hdr *tcp; - struct udp_hdr *udp; - unsigned int rhleft; - - ether = (struct ether_header *) buffer; - dlt_null= (struct dlt_null *) buffer; + unsigned char *v6buffer; + struct ip6_hdr *ipv6; + struct tcp_hdr *tcp; + struct udp_hdr *udp; + unsigned int rhleft; + + ether = (struct ether_header *)buffer; + dlt_null = (struct dlt_null *)buffer; #if defined(__linux__) - sll_linux= (struct sll_linux *) buffer; + sll_linux = (struct sll_linux *)buffer; #endif - v6buffer = buffer + idata->linkhsize; - ipv6 = (struct ip6_hdr *) v6buffer; - - if(idata->type == DLT_EN10MB){ - ether->ether_type = htons(ETHERTYPE_IPV6); - - if(!(idata->flags & IFACE_LOOPBACK)){ - ether->src = idata->ether; - - if(!onlink_f){ - ether->dst = idata->nhhaddr; - }else{ - if(ipv6_to_ether(idata->pfd, idata, &((scan->target[scan->ctarget])->cur.in6_addr), &(idata->hdstaddr)) != 1){ - return(1); - } - } - } - } - else if(idata->type == DLT_NULL){ - dlt_null->family= PF_INET6; - } -#if defined (__OpenBSD__) - else if(idata->type == DLT_LOOP){ - dlt_null->family= htonl(PF_INET6); - } + v6buffer = buffer + idata->linkhsize; + ipv6 = (struct ip6_hdr *)v6buffer; + + if (idata->type == DLT_EN10MB) { + ether->ether_type = htons(ETHERTYPE_IPV6); + + if (!(idata->flags & IFACE_LOOPBACK)) { + ether->src = idata->ether; + + if (!onlink_f) { + ether->dst = idata->nhhaddr; + } + else { + if (ipv6_to_ether(idata->pfd, idata, &((scan->target[scan->ctarget])->cur.in6_addr), + &(idata->hdstaddr)) != 1) { + return (1); + } + } + } + } + else if (idata->type == DLT_NULL) { + dlt_null->family = PF_INET6; + } +#if defined(__OpenBSD__) + else if (idata->type == DLT_LOOP) { + dlt_null->family = htonl(PF_INET6); + } #elif defined(__linux__) - else if(idata->type == DLT_LINUX_SLL){ - sll_linux->sll_pkttype= htons(0x0004); - sll_linux->sll_hatype= htons(0xffff); - sll_linux->sll_halen= htons(0x0000); - sll_linux->sll_protocol= htons(ETHERTYPE_IPV6); - } + else if (idata->type == DLT_LINUX_SLL) { + sll_linux->sll_pkttype = htons(0x0004); + sll_linux->sll_hatype = htons(0xffff); + sll_linux->sll_halen = htons(0x0000); + sll_linux->sll_protocol = htons(ETHERTYPE_IPV6); + } #endif - ipv6->ip6_flow=0; - ipv6->ip6_vfc= 0x60; - ipv6->ip6_hlim= 255; - - ipv6->ip6_src= idata->srcaddr; - /* XXX Double-check this one */ - /* ipv6->ip6_src= idata->srcaddr_f?(*srcaddr):*sel_src_addr_ra(idata, &((scan->target[scan->ctarget])->cur.in6_addr)); */ - - ipv6->ip6_dst= (scan->target[scan->ctarget])->cur.in6_addr; - prev_nh = (unsigned char *) &(ipv6->ip6_nxt); - - ptr = (unsigned char *) v6buffer + MIN_IPV6_HLEN; - - switch(type){ - case IPPROTO_TCP: - *prev_nh = IPPROTO_TCP; + ipv6->ip6_flow = 0; + ipv6->ip6_vfc = 0x60; + ipv6->ip6_hlim = 255; + + ipv6->ip6_src = idata->srcaddr; + /* XXX Double-check this one */ + /* ipv6->ip6_src= idata->srcaddr_f?(*srcaddr):*sel_src_addr_ra(idata, + * &((scan->target[scan->ctarget])->cur.in6_addr)); */ + + ipv6->ip6_dst = (scan->target[scan->ctarget])->cur.in6_addr; + prev_nh = (unsigned char *)&(ipv6->ip6_nxt); + + ptr = (unsigned char *)v6buffer + MIN_IPV6_HLEN; + + switch (type) { + case IPPROTO_TCP: + *prev_nh = IPPROTO_TCP; + + if ((ptr + sizeof(struct tcp_hdr)) > (v6buffer + idata->max_packet_size)) { + if (idata->verbose_f) + puts("Packet Too Large while inserting TCP header"); + + return (0); + } + + tcp = (struct tcp_hdr *)ptr; + memset(tcp, 0, sizeof(struct tcp_hdr)); + + if (srcport_f) + tcp->th_sport = htons(srcport); + else + tcp->th_sport = htons(1024 + random() % 64512); + + tcp->th_dport = htons((port_list->port[port_list->cport])->cur); + + if (tcpflags_f) + tcp->th_flags = tcpflags; + else + tcp->th_flags = TH_ACK; + + if (tcpflags & TH_ACK) + tcp->th_ack = htonl(random()); + else + tcp->th_ack = htonl(0); + + tcp->th_win = htons(4096 * (random() % 9 + 1)); + + /* Current version of tcp6 does not support sending TCP options */ + tcp->th_off = sizeof(struct tcp_hdr) >> 2; + ptr += tcp->th_off << 2; + + if ((ptr + rhbytes) > v6buffer + idata->max_packet_size) { + puts("Packet Too Large while inserting TCP segment"); + exit(EXIT_FAILURE); + } + + while (rhbytes >= 4) { + *(uint32_t *)ptr = random(); + ptr += sizeof(uint32_t); + rhbytes -= sizeof(uint32_t); + } + + while (rhbytes > 0) { + *(uint8_t *)ptr = (uint8_t)random(); + ptr++; + rhbytes--; + } + + ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); + tcp->th_sum = 0; + tcp->th_sum = in_chksum(v6buffer, tcp, ptr - ((unsigned char *)tcp), IPPROTO_TCP); + break; + + case IPPROTO_UDP: + *prev_nh = IPPROTO_UDP; + + if ((ptr + sizeof(struct udp_hdr)) > (v6buffer + idata->max_packet_size)) { + puts("Packet too large while inserting ICMPv6 header (should be using Frag. option?)"); + exit(EXIT_FAILURE); + } + + udp = (struct udp_hdr *)ptr; + memset(udp, 0, sizeof(struct udp_hdr)); + ptr += sizeof(struct udp_hdr); + + /* + For UDP, we encode the current probe number and the current Hop Limit as fr TCP. + Namely, we encode the probe number and the current Hop Limit in the TCP Source Port. + The probe number is encoded in the upper eight bits, while the current Hop Limit is + encoded in the lower eight bits. A constant "offset" is employed for encoding the probe + number, such that the resulting Source Port falls into what is typically known as the + dynamic ports range (say, ports larger than 50000). + */ - if( (ptr+sizeof(struct tcp_hdr)) > (v6buffer + idata->max_packet_size)){ - if(idata->verbose_f) - puts("Packet Too Large while inserting TCP header"); - - return(0); - } - - tcp = (struct tcp_hdr *) ptr; - memset(tcp, 0, sizeof(struct tcp_hdr)); - - if(srcport_f) - tcp->th_sport= htons(srcport); - else - tcp->th_sport= htons(1024+ random() % 64512); - - tcp->th_dport= htons((port_list->port[port_list->cport])->cur); - - if(tcpflags_f) - tcp->th_flags= tcpflags; - else - tcp->th_flags= TH_ACK; - - if(tcpflags & TH_ACK) - tcp->th_ack= htonl(random()); - else - tcp->th_ack= htonl(0); - - tcp->th_win= htons( 4096 * (random() % 9 + 1)); - - /* Current version of tcp6 does not support sending TCP options */ - tcp->th_off= sizeof(struct tcp_hdr) >> 2; - ptr+= tcp->th_off << 2; - - if( (ptr + rhbytes) > v6buffer+idata->max_packet_size){ - puts("Packet Too Large while inserting TCP segment"); - exit(EXIT_FAILURE); - } - - while(rhbytes>=4){ - *(uint32_t *)ptr = random(); - ptr += sizeof(uint32_t); - rhbytes -= sizeof(uint32_t); - } - - while(rhbytes>0){ - *(uint8_t *) ptr= (uint8_t) random(); - ptr++; - rhbytes--; - } - - ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); - tcp->th_sum = 0; - tcp->th_sum = in_chksum(v6buffer, tcp, ptr-((unsigned char *)tcp), IPPROTO_TCP); - break; - - case IPPROTO_UDP: - *prev_nh = IPPROTO_UDP; - - if( (ptr+sizeof(struct udp_hdr)) > (v6buffer+ idata->max_packet_size)){ - puts("Packet too large while inserting ICMPv6 header (should be using Frag. option?)"); - exit(EXIT_FAILURE); - } - - udp= (struct udp_hdr *) ptr; - memset(udp, 0, sizeof(struct udp_hdr)); - ptr+= sizeof(struct udp_hdr); - - /* - For UDP, we encode the current probe number and the current Hop Limit as fr TCP. - Namely, we encode the probe number and the current Hop Limit in the TCP Source Port. - The probe number is encoded in the upper eight bits, while the current Hop Limit is - encoded in the lower eight bits. A constant "offset" is employed for encoding the probe - number, such that the resulting Source Port falls into what is typically known as the - dynamic ports range (say, ports larger than 50000). - */ - - if(srcport_f) - udp->uh_sport= htons(srcport); - else - udp->uh_sport= htons(1024+ random() % 64512); - - udp->uh_dport= htons((port_list->port[port_list->cport])->cur); - - /* XXX Send some minimum packet size -- should be changed */ - rhbytes= 40; - - if(rhbytes){ - rhleft=rhbytes; - - if( (ptr + rhleft) > (v6buffer+ idata->max_packet_size)){ - puts("Packet Too Large while inserting TCP segment"); - exit(EXIT_FAILURE); - } - - while(rhleft>=4){ - *(uint32_t *)ptr = random(); - ptr += sizeof(uint32_t); - rhleft -= sizeof(uint32_t); - } - - while(rhleft>0){ - *(uint8_t *) ptr= (uint8_t) random(); - ptr++; - rhleft--; - } - } - - ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); - udp->uh_ulen= htons(ptr - (unsigned char *) udp); - udp->uh_sum=0; - udp->uh_sum = in_chksum(v6buffer, udp, ptr-((unsigned char *)udp), IPPROTO_UDP); - break; - } - - if((nw=pcap_inject(idata->pfd, buffer, ptr - buffer)) == -1){ - if(idata->verbose_f) - printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); - - return(0); - } - - if(nw != (ptr-buffer)){ - if(idata->verbose_f) - printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, \ - (LUI) (ptr-buffer)); - return(0); - } - - return(1); + if (srcport_f) + udp->uh_sport = htons(srcport); + else + udp->uh_sport = htons(1024 + random() % 64512); + + udp->uh_dport = htons((port_list->port[port_list->cport])->cur); + + /* XXX Send some minimum packet size -- should be changed */ + rhbytes = 40; + + if (rhbytes) { + rhleft = rhbytes; + + if ((ptr + rhleft) > (v6buffer + idata->max_packet_size)) { + puts("Packet Too Large while inserting TCP segment"); + exit(EXIT_FAILURE); + } + + while (rhleft >= 4) { + *(uint32_t *)ptr = random(); + ptr += sizeof(uint32_t); + rhleft -= sizeof(uint32_t); + } + + while (rhleft > 0) { + *(uint8_t *)ptr = (uint8_t)random(); + ptr++; + rhleft--; + } + } + + ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); + udp->uh_ulen = htons(ptr - (unsigned char *)udp); + udp->uh_sum = 0; + udp->uh_sum = in_chksum(v6buffer, udp, ptr - ((unsigned char *)udp), IPPROTO_UDP); + break; + } + + if ((nw = pcap_inject(idata->pfd, buffer, ptr - buffer)) == -1) { + if (idata->verbose_f) + printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); + + return (0); + } + + if (nw != (ptr - buffer)) { + if (idata->verbose_f) + printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, (LUI)(ptr - buffer)); + return (0); + } + + return (1); } - - - /* * Function: multi_scan_local() * * Performs an IPv6 address scan on a local link */ -int multi_scan_local(pcap_t *pfd, struct iface_data *idata, struct in6_addr *srcaddr, unsigned char type, \ - const char *ptargetaddr, struct host_list *hlist){ - - struct bpf_program pcap_filter; - struct pcap_pkthdr *pkthdr; - const u_char *pktdata; - struct ip6_hdr *pkt_ipv6; - struct icmp6_hdr *pkt_icmp6; - struct nd_neighbor_solicit *pkt_ns; - unsigned char *pkt_end; - unsigned char *ptr; - - unsigned char buffer[65556]; - unsigned int icmp6_max_packet_size; - struct ether_header *ether; - unsigned char *v6buffer; - struct ip6_hdr *ipv6; - volatile unsigned int tries=0; - struct in6_addr targetaddr; - struct sigaction new_sig, old_sig; - struct ip6_dest *destopth; - struct ip6_option *opt; - uint32_t *uint32; - unsigned char error_f=FALSE, llocalsrc_f=FALSE; - int result; - - icmp6_max_packet_size = idata->mtu; - ether = (struct ether_header *) buffer; - v6buffer = buffer + sizeof(struct ether_header); - ipv6 = (struct ip6_hdr *) v6buffer; - - if ( inet_pton(AF_INET6, ptargetaddr, &targetaddr) <= 0){ - if(idata->verbose_f>1) - puts("inet_pton(): Source Address not valid"); - - return(-1); - } - - if(IN6_IS_ADDR_LINKLOCAL(srcaddr)) - llocalsrc_f=TRUE; - - if(pfd == NULL) - return(-1); - - switch(type){ - case PROBE_ICMP6_ECHO: - if(pcap_compile(pfd, &pcap_filter, PCAP_ICMPV6_ERNS_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1){ - if(idata->verbose_f) - printf("pcap_compile(): %s", pcap_geterr(pfd)); - - return(-1); - } - break; - - case PROBE_UNREC_OPT: - if(pcap_compile(pfd, &pcap_filter, PCAP_ICMPV6_ERRORNS_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1){ - if(idata->verbose_f) - printf("pcap_compile(): %s", pcap_geterr(pfd)); - - return(-1); - } - break; - - default: - return(-1); - break; - } - - if(pcap_setfilter(pfd, &pcap_filter) == -1){ - if(idata->verbose_f) - printf("pcap_setfilter(): %s", pcap_geterr(pfd)); - - return(-1); - } - - pcap_freecode(&pcap_filter); - - ipv6->ip6_flow=0; - ipv6->ip6_vfc= 0x60; - ipv6->ip6_hlim= 255; - - ipv6->ip6_src= *srcaddr; - ipv6->ip6_dst= targetaddr; - - ether->src = idata->ether; - ether->dst = ether_multicast(&(ipv6->ip6_dst)); - ether->ether_type = htons(ETHERTYPE_IPV6); - - prev_nh = (unsigned char *) &(ipv6->ip6_nxt); - - ptr = (unsigned char *) v6buffer + MIN_IPV6_HLEN; - - switch(type){ - case PROBE_ICMP6_ECHO: - *prev_nh = IPPROTO_ICMPV6; - - if( (ptr+sizeof(struct icmp6_hdr)+ICMPV6_ECHO_PAYLOAD_SIZE) > (v6buffer+icmp6_max_packet_size)){ - if(idata->verbose_f>1) - puts("Packet too large while creating ICMPv6 Echo Request Probe packet"); - - return(-1); - } - - icmp6 = (struct icmp6_hdr *) ptr; - icmp6->icmp6_type = ICMP6_ECHO_REQUEST; - icmp6->icmp6_code = 0; - icmp6->icmp6_cksum = random(); - icmp6->icmp6_data16[0]= htons(getpid()); /* Identifier */ - icmp6->icmp6_data16[1]= htons(random()); /* Sequence Number */ - - ptr = ptr+ sizeof(struct icmp6_hdr); - - for(i=0; i<(ICMPV6_ECHO_PAYLOAD_SIZE>>2); i++){ - *(uint32_t *)ptr = random(); - ptr += sizeof(uint32_t); - } - break; - - case PROBE_UNREC_OPT: - *prev_nh = IPPROTO_DSTOPTS; - - if( (ptr+sizeof(struct icmp6_hdr) + 8 + ICMPV6_ECHO_PAYLOAD_SIZE) > (v6buffer+icmp6_max_packet_size)){ - if(idata->verbose_f>1) - puts("Packet too large while creating Unrec. Opt. Probe Packet"); +int multi_scan_local(pcap_t *pfd, struct iface_data *idata, struct in6_addr *srcaddr, unsigned char type, + const char *ptargetaddr, struct host_list *hlist) { + + struct bpf_program pcap_filter; + struct pcap_pkthdr *pkthdr; + const u_char *pktdata; + struct ip6_hdr *pkt_ipv6; + struct icmp6_hdr *pkt_icmp6; + struct nd_neighbor_solicit *pkt_ns; + unsigned char *pkt_end; + unsigned char *ptr; + + unsigned char buffer[65556]; + unsigned int icmp6_max_packet_size; + struct ether_header *ether; + unsigned char *v6buffer; + struct ip6_hdr *ipv6; + volatile unsigned int tries = 0; + struct in6_addr targetaddr; + struct sigaction new_sig, old_sig; + struct ip6_dest *destopth; + struct ip6_option *opt; + uint32_t *uint32; + unsigned char error_f = FALSE, llocalsrc_f = FALSE; + int result; + + icmp6_max_packet_size = idata->mtu; + ether = (struct ether_header *)buffer; + v6buffer = buffer + sizeof(struct ether_header); + ipv6 = (struct ip6_hdr *)v6buffer; + + if (inet_pton(AF_INET6, ptargetaddr, &targetaddr) <= 0) { + if (idata->verbose_f > 1) + puts("inet_pton(): Source Address not valid"); + + return (-1); + } + + if (IN6_IS_ADDR_LINKLOCAL(srcaddr)) + llocalsrc_f = TRUE; + + if (pfd == NULL) + return (-1); + + switch (type) { + case PROBE_ICMP6_ECHO: + if (pcap_compile(pfd, &pcap_filter, PCAP_ICMPV6_ERNS_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1) { + if (idata->verbose_f) + printf("pcap_compile(): %s", pcap_geterr(pfd)); + + return (-1); + } + break; + + case PROBE_UNREC_OPT: + if (pcap_compile(pfd, &pcap_filter, PCAP_ICMPV6_ERRORNS_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1) { + if (idata->verbose_f) + printf("pcap_compile(): %s", pcap_geterr(pfd)); + + return (-1); + } + break; + + default: + return (-1); + break; + } + + if (pcap_setfilter(pfd, &pcap_filter) == -1) { + if (idata->verbose_f) + printf("pcap_setfilter(): %s", pcap_geterr(pfd)); + + return (-1); + } + + pcap_freecode(&pcap_filter); + + ipv6->ip6_flow = 0; + ipv6->ip6_vfc = 0x60; + ipv6->ip6_hlim = 255; + + ipv6->ip6_src = *srcaddr; + ipv6->ip6_dst = targetaddr; + + ether->src = idata->ether; + ether->dst = ether_multicast(&(ipv6->ip6_dst)); + ether->ether_type = htons(ETHERTYPE_IPV6); + + prev_nh = (unsigned char *)&(ipv6->ip6_nxt); + + ptr = (unsigned char *)v6buffer + MIN_IPV6_HLEN; + + switch (type) { + case PROBE_ICMP6_ECHO: + *prev_nh = IPPROTO_ICMPV6; + + if ((ptr + sizeof(struct icmp6_hdr) + ICMPV6_ECHO_PAYLOAD_SIZE) > (v6buffer + icmp6_max_packet_size)) { + if (idata->verbose_f > 1) + puts("Packet too large while creating ICMPv6 Echo Request Probe packet"); + + return (-1); + } + + icmp6 = (struct icmp6_hdr *)ptr; + icmp6->icmp6_type = ICMP6_ECHO_REQUEST; + icmp6->icmp6_code = 0; + icmp6->icmp6_cksum = random(); + icmp6->icmp6_data16[0] = htons(getpid()); /* Identifier */ + icmp6->icmp6_data16[1] = htons(random()); /* Sequence Number */ + + ptr = ptr + sizeof(struct icmp6_hdr); + + for (i = 0; i < (ICMPV6_ECHO_PAYLOAD_SIZE >> 2); i++) { + *(uint32_t *)ptr = random(); + ptr += sizeof(uint32_t); + } + break; + + case PROBE_UNREC_OPT: + *prev_nh = IPPROTO_DSTOPTS; - return(-1); - } - - destopth = (struct ip6_dest *) ptr; - destopth->ip6d_len= 0; - destopth->ip6d_nxt= IPPROTO_ICMPV6; - - ptr= ptr + 2; - opt= (struct ip6_option *) ptr; - opt->ip6o_type= 0x80; - opt->ip6o_len= 4; - - ptr= ptr + 2; - uint32 = (uint32_t *) ptr; - *uint32 = random(); - - ptr= ptr +4; - icmp6 = (struct icmp6_hdr *) ptr; - icmp6->icmp6_type = ICMP6_ECHO_REQUEST; - icmp6->icmp6_code = 0; - icmp6->icmp6_cksum = random(); - icmp6->icmp6_data16[0]= htons(getpid()); /* Identifier */ - icmp6->icmp6_data16[1]= htons(random()); /* Sequence Number */ - - ptr = ptr+ sizeof(struct icmp6_hdr); - - for(i=0; i<(ICMPV6_ECHO_PAYLOAD_SIZE>>2); i++){ - *(uint32_t *)ptr = random(); - ptr += sizeof(uint32_t); - } - break; - } - - ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); - icmp6->icmp6_cksum = 0; - icmp6->icmp6_cksum = in_chksum(v6buffer, icmp6, ptr-((unsigned char *)icmp6), IPPROTO_ICMPV6); - - /* We set the signal handler, and the anchor for siglongjump() */ - canjump=0; - memset(&new_sig, 0, sizeof(struct sigaction)); - sigemptyset(&new_sig.sa_mask); - new_sig.sa_handler= &local_sig_alarm; - - if( sigaction(SIGALRM, &new_sig, &old_sig) == -1){ - if(idata->verbose_f>1) - puts("Error setting up 'Alarm' signal"); - - return(-1); - } - - if(sigsetjmp(env, 1) != 0) - tries++; - - canjump=1; - - while(tries <= idata->local_retrans && !error_f){ - if((nw=pcap_inject(pfd, buffer, ptr - buffer)) == -1){ - if(idata->verbose_f>1) - printf("pcap_inject(): %s\n", pcap_geterr(pfd)); - - error_f=TRUE; - break; - } - - if(nw != (ptr-buffer)){ - if(idata->verbose_f>1) - printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, \ - (LUI) (ptr-buffer)); - - error_f=TRUE; - break; - } - - alarm(idata->local_timeout); - - while( (hlist->nhosts < hlist->maxhosts) && !error_f){ - - do{ - if((result=pcap_next_ex(pfd, &pkthdr, &pktdata)) == -1){ - if(idata->verbose_f>1) - printf("pcap_next_ex(): %s", pcap_geterr(pfd)); - - error_f=TRUE; - break; - } - }while(result == 0 || pktdata == NULL); - - if(error_f) - break; - - pkt_ether = (struct ether_header *) pktdata; - pkt_ipv6 = (struct ip6_hdr *)((char *) pkt_ether + ETHER_HDR_LEN); - pkt_icmp6 = (struct icmp6_hdr *) ((char *) pkt_ipv6 + sizeof(struct ip6_hdr)); - pkt_ns= (struct nd_neighbor_solicit *) pkt_icmp6; - pkt_end = (unsigned char *) pktdata + pkthdr->caplen; - - if( (pkt_end - pktdata) < (ETHER_HDR_LEN + MIN_IPV6_HLEN)) - continue; - - if(pkt_ipv6->ip6_nxt == IPPROTO_ICMPV6){ - if(pkt_icmp6->icmp6_type == ND_NEIGHBOR_SOLICIT){ - if( (pkt_end - (unsigned char *) pkt_ns) < sizeof(struct nd_neighbor_solicit)) - continue; - - if(is_eq_in6_addr(&(pkt_ns->nd_ns_target), srcaddr) || \ - is_eq_in6_addr(&(pkt_ns->nd_ns_target), &(idata->ip6_local))){ - if(send_neighbor_advert(idata, pfd, pktdata) == -1){ - error_f=TRUE; - break; - } - } - } - else if( (pkt_icmp6->icmp6_type == ICMP6_ECHO_REPLY) || (pkt_icmp6->icmp6_type == ICMP6_PARAM_PROB)){ - if( (pkt_end - (unsigned char *) pkt_icmp6) < sizeof(struct icmp6_hdr)) - continue; - - /* - If the Source Address was a link-local address, we only want link-local addresses. - OTOH, if the Source Address was a global address, we only want global addresses. - */ - if(llocalsrc_f){ - if(!IN6_IS_ADDR_LINKLOCAL(&(pkt_ipv6->ip6_src))) - continue; - } - else{ - if(IN6_IS_ADDR_LINKLOCAL(&(pkt_ipv6->ip6_src))) - continue; - } - - if(valid_icmp6_response(idata, type, pkthdr, pktdata, buffer)){ - if(is_ip6_in_list(&(pkt_ipv6->ip6_src), hlist)) - continue; - - if( (hlist->host[hlist->nhosts]= malloc(sizeof(struct host_entry))) == NULL){ - if(idata->verbose_f>1) - puts("Error when allocating memory for host data"); - - error_f=TRUE; - break; - } - - memset(hlist->host[hlist->nhosts], 0, sizeof(struct host_entry)); - - (hlist->host[hlist->nhosts])->ip6= pkt_ipv6->ip6_src; - (hlist->host[hlist->nhosts])->ether= pkt_ether->src; - (hlist->host[hlist->nhosts])->flag = VALID_MAPPING; - (hlist->nhosts)++; - } - } - } - - } /* Processing packets */ - - } /* Resending Neighbor Solicitations */ - - - if( sigaction(SIGALRM, &old_sig, NULL) == -1){ - if(idata->verbose_f>1) - puts("Error setting up 'Alarm' signal"); - - error_f=TRUE; - } - - if(error_f) - return(-1); - else - return 0; -} + if ((ptr + sizeof(struct icmp6_hdr) + 8 + ICMPV6_ECHO_PAYLOAD_SIZE) > (v6buffer + icmp6_max_packet_size)) { + if (idata->verbose_f > 1) + puts("Packet too large while creating Unrec. Opt. Probe Packet"); + return (-1); + } + destopth = (struct ip6_dest *)ptr; + destopth->ip6d_len = 0; + destopth->ip6d_nxt = IPPROTO_ICMPV6; + + ptr = ptr + 2; + opt = (struct ip6_option *)ptr; + opt->ip6o_type = 0x80; + opt->ip6o_len = 4; + + ptr = ptr + 2; + uint32 = (uint32_t *)ptr; + *uint32 = random(); + + ptr = ptr + 4; + icmp6 = (struct icmp6_hdr *)ptr; + icmp6->icmp6_type = ICMP6_ECHO_REQUEST; + icmp6->icmp6_code = 0; + icmp6->icmp6_cksum = random(); + icmp6->icmp6_data16[0] = htons(getpid()); /* Identifier */ + icmp6->icmp6_data16[1] = htons(random()); /* Sequence Number */ + + ptr = ptr + sizeof(struct icmp6_hdr); + + for (i = 0; i < (ICMPV6_ECHO_PAYLOAD_SIZE >> 2); i++) { + *(uint32_t *)ptr = random(); + ptr += sizeof(uint32_t); + } + break; + } + + ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); + icmp6->icmp6_cksum = 0; + icmp6->icmp6_cksum = in_chksum(v6buffer, icmp6, ptr - ((unsigned char *)icmp6), IPPROTO_ICMPV6); + + /* We set the signal handler, and the anchor for siglongjump() */ + canjump = 0; + memset(&new_sig, 0, sizeof(struct sigaction)); + sigemptyset(&new_sig.sa_mask); + new_sig.sa_handler = &local_sig_alarm; + + if (sigaction(SIGALRM, &new_sig, &old_sig) == -1) { + if (idata->verbose_f > 1) + puts("Error setting up 'Alarm' signal"); + + return (-1); + } + + if (sigsetjmp(env, 1) != 0) + tries++; + + canjump = 1; + + while (tries <= idata->local_retrans && !error_f) { + if ((nw = pcap_inject(pfd, buffer, ptr - buffer)) == -1) { + if (idata->verbose_f > 1) + printf("pcap_inject(): %s\n", pcap_geterr(pfd)); + + error_f = TRUE; + break; + } + + if (nw != (ptr - buffer)) { + if (idata->verbose_f > 1) + printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, (LUI)(ptr - buffer)); + + error_f = TRUE; + break; + } + + alarm(idata->local_timeout); + + while ((hlist->nhosts < hlist->maxhosts) && !error_f) { + + do { + if ((result = pcap_next_ex(pfd, &pkthdr, &pktdata)) == -1) { + if (idata->verbose_f > 1) + printf("pcap_next_ex(): %s", pcap_geterr(pfd)); + + error_f = TRUE; + break; + } + } while (result == 0 || pktdata == NULL); + + if (error_f) + break; + + pkt_ether = (struct ether_header *)pktdata; + pkt_ipv6 = (struct ip6_hdr *)((char *)pkt_ether + ETHER_HDR_LEN); + pkt_icmp6 = (struct icmp6_hdr *)((char *)pkt_ipv6 + sizeof(struct ip6_hdr)); + pkt_ns = (struct nd_neighbor_solicit *)pkt_icmp6; + pkt_end = (unsigned char *)pktdata + pkthdr->caplen; + + if ((pkt_end - pktdata) < (ETHER_HDR_LEN + MIN_IPV6_HLEN)) + continue; + + if (pkt_ipv6->ip6_nxt == IPPROTO_ICMPV6) { + if (pkt_icmp6->icmp6_type == ND_NEIGHBOR_SOLICIT) { + if ((pkt_end - (unsigned char *)pkt_ns) < sizeof(struct nd_neighbor_solicit)) + continue; + + if (is_eq_in6_addr(&(pkt_ns->nd_ns_target), srcaddr) || + is_eq_in6_addr(&(pkt_ns->nd_ns_target), &(idata->ip6_local))) { + if (send_neighbor_advert(idata, pfd, pktdata) == -1) { + error_f = TRUE; + break; + } + } + } + else if ((pkt_icmp6->icmp6_type == ICMP6_ECHO_REPLY) || (pkt_icmp6->icmp6_type == ICMP6_PARAM_PROB)) { + if ((pkt_end - (unsigned char *)pkt_icmp6) < sizeof(struct icmp6_hdr)) + continue; + + /* + If the Source Address was a link-local address, we only want link-local addresses. + OTOH, if the Source Address was a global address, we only want global addresses. + */ + if (llocalsrc_f) { + if (!IN6_IS_ADDR_LINKLOCAL(&(pkt_ipv6->ip6_src))) + continue; + } + else { + if (IN6_IS_ADDR_LINKLOCAL(&(pkt_ipv6->ip6_src))) + continue; + } + + if (valid_icmp6_response(idata, type, pkthdr, pktdata, buffer)) { + if (is_ip6_in_list(&(pkt_ipv6->ip6_src), hlist)) + continue; + + if ((hlist->host[hlist->nhosts] = malloc(sizeof(struct host_entry))) == NULL) { + if (idata->verbose_f > 1) + puts("Error when allocating memory for host data"); + + error_f = TRUE; + break; + } + + memset(hlist->host[hlist->nhosts], 0, sizeof(struct host_entry)); + + (hlist->host[hlist->nhosts])->ip6 = pkt_ipv6->ip6_src; + (hlist->host[hlist->nhosts])->ether = pkt_ether->src; + (hlist->host[hlist->nhosts])->flag = VALID_MAPPING; + (hlist->nhosts)++; + } + } + } + + } /* Processing packets */ + + } /* Resending Neighbor Solicitations */ + + if (sigaction(SIGALRM, &old_sig, NULL) == -1) { + if (idata->verbose_f > 1) + puts("Error setting up 'Alarm' signal"); + + error_f = TRUE; + } + + if (error_f) + return (-1); + else + return 0; +} /* * Function: find_local_globals() @@ -5100,384 +5049,376 @@ int multi_scan_local(pcap_t *pfd, struct iface_data *idata, struct in6_addr *src * Finds Global Unicast Addresses present on the local link */ -int find_local_globals(pcap_t *pfd, struct iface_data *idata, unsigned char type, const char *ptargetaddr, \ - struct host_list *hlist){ - unsigned int i; - for(i=0; i < idata->ip6_global.nprefix; i++){ - if(multi_scan_local(pfd, idata, &((idata->ip6_global.prefix[i])->ip6), type, ALL_NODES_MULTICAST_ADDR,\ - hlist) == -1){ - return(-1); - } - } - - return 0; +int find_local_globals(pcap_t *pfd, struct iface_data *idata, unsigned char type, const char *ptargetaddr, + struct host_list *hlist) { + unsigned int i; + for (i = 0; i < idata->ip6_global.nprefix; i++) { + if (multi_scan_local(pfd, idata, &((idata->ip6_global.prefix[i])->ip6), type, ALL_NODES_MULTICAST_ADDR, + hlist) == -1) { + return (-1); + } + } + + return 0; } - /* * Function: host_scan_local() * * Scans a single IPv6 address */ -int host_scan_local(pcap_t *pfd, struct iface_data *idata, struct in6_addr *srcaddr, unsigned char type, struct host_entry *host){ - struct bpf_program pcap_filter; - struct pcap_pkthdr *pkthdr; - const u_char *pktdata; - struct ip6_hdr *pkt_ipv6; - struct icmp6_hdr *pkt_icmp6; - struct nd_neighbor_solicit *pkt_ns; - unsigned char *pkt_end; - volatile unsigned char *ptr; - - unsigned char buffer[65556]; - unsigned int icmp6_max_packet_size; - struct ether_header *ether; - unsigned char *v6buffer; - struct ip6_hdr *ipv6; - volatile unsigned int tries=0; - struct in6_addr targetaddr; - struct sigaction new_sig, old_sig; - struct ip6_dest *destopth; - struct ip6_option *opt; - uint32_t *uint32; - unsigned char foundaddr_f=FALSE, error_f=FALSE; - int result; - - icmp6_max_packet_size = idata->mtu; - ether = (struct ether_header *) buffer; - v6buffer = buffer + sizeof(struct ether_header); - ipv6 = (struct ip6_hdr *) v6buffer; - - targetaddr= host->ip6; - - if( pcap_datalink(pfd) != DLT_EN10MB){ - if(idata->verbose_f>1) - printf("Error: Interface %s is not an Ethernet interface", idata->iface); - - return(-1); - } - - switch(type){ - case PROBE_ICMP6_ECHO: - if(pcap_compile(pfd, &pcap_filter, PCAP_ICMPV6_ERNS_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1){ - if(idata->verbose_f>1) - printf("pcap_compile(): %s", pcap_geterr(pfd)); - - return(-1); - } - - break; - - case PROBE_UNREC_OPT: - if(pcap_compile(pfd, &pcap_filter, PCAP_ICMPV6_ERRORNS_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1){ - if(idata->verbose_f>1) - printf("pcap_compile(): %s", pcap_geterr(pfd)); - - return(-1); - } - - break; - - default: - return(-1); - break; - } - - if(pcap_setfilter(pfd, &pcap_filter) == -1){ - if(idata->verbose_f>1) - printf("pcap_setfilter(): %s", pcap_geterr(pfd)); - - return(-1); - } - - pcap_freecode(&pcap_filter); - - ipv6->ip6_flow=0; - ipv6->ip6_vfc= 0x60; - ipv6->ip6_hlim= 255; - ipv6->ip6_dst= targetaddr; - ipv6->ip6_src= *srcaddr; - - ether->src = idata->ether; - ether->dst = host->ether; - ether->ether_type = htons(ETHERTYPE_IPV6); - - prev_nh = (unsigned char *) &(ipv6->ip6_nxt); - - ptr = (unsigned char *) v6buffer + MIN_IPV6_HLEN; - - switch(type){ - case PROBE_ICMP6_ECHO: - *prev_nh = IPPROTO_ICMPV6; - - if( (ptr+sizeof(struct icmp6_hdr)+ICMPV6_ECHO_PAYLOAD_SIZE) > (v6buffer+icmp6_max_packet_size)){ - if(idata->verbose_f>1) - puts("Packet too large while creating ICMPv6 Echo Request Probe packet"); - - return(-1); - } - - icmp6 = (struct icmp6_hdr *) ptr; - icmp6->icmp6_type = ICMP6_ECHO_REQUEST; - icmp6->icmp6_code = 0; - icmp6->icmp6_cksum = random(); - icmp6->icmp6_data16[0]= htons(getpid()); /* Identifier */ - icmp6->icmp6_data16[1]= htons(random()); /* Sequence Number */ - - ptr = ptr+ sizeof(struct icmp6_hdr); - - for(i=0; i<(ICMPV6_ECHO_PAYLOAD_SIZE>>2); i++){ - *(uint32_t *)ptr = random(); - ptr += sizeof(uint32_t); - } - break; +int host_scan_local(pcap_t *pfd, struct iface_data *idata, struct in6_addr *srcaddr, unsigned char type, + struct host_entry *host) { + struct bpf_program pcap_filter; + struct pcap_pkthdr *pkthdr; + const u_char *pktdata; + struct ip6_hdr *pkt_ipv6; + struct icmp6_hdr *pkt_icmp6; + struct nd_neighbor_solicit *pkt_ns; + unsigned char *pkt_end; + volatile unsigned char *ptr; + + unsigned char buffer[65556]; + unsigned int icmp6_max_packet_size; + struct ether_header *ether; + unsigned char *v6buffer; + struct ip6_hdr *ipv6; + volatile unsigned int tries = 0; + struct in6_addr targetaddr; + struct sigaction new_sig, old_sig; + struct ip6_dest *destopth; + struct ip6_option *opt; + uint32_t *uint32; + unsigned char foundaddr_f = FALSE, error_f = FALSE; + int result; + + icmp6_max_packet_size = idata->mtu; + ether = (struct ether_header *)buffer; + v6buffer = buffer + sizeof(struct ether_header); + ipv6 = (struct ip6_hdr *)v6buffer; + + targetaddr = host->ip6; + + if (pcap_datalink(pfd) != DLT_EN10MB) { + if (idata->verbose_f > 1) + printf("Error: Interface %s is not an Ethernet interface", idata->iface); + + return (-1); + } + + switch (type) { + case PROBE_ICMP6_ECHO: + if (pcap_compile(pfd, &pcap_filter, PCAP_ICMPV6_ERNS_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1) { + if (idata->verbose_f > 1) + printf("pcap_compile(): %s", pcap_geterr(pfd)); + + return (-1); + } + + break; + + case PROBE_UNREC_OPT: + if (pcap_compile(pfd, &pcap_filter, PCAP_ICMPV6_ERRORNS_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1) { + if (idata->verbose_f > 1) + printf("pcap_compile(): %s", pcap_geterr(pfd)); + + return (-1); + } + + break; + + default: + return (-1); + break; + } + + if (pcap_setfilter(pfd, &pcap_filter) == -1) { + if (idata->verbose_f > 1) + printf("pcap_setfilter(): %s", pcap_geterr(pfd)); + + return (-1); + } + + pcap_freecode(&pcap_filter); + + ipv6->ip6_flow = 0; + ipv6->ip6_vfc = 0x60; + ipv6->ip6_hlim = 255; + ipv6->ip6_dst = targetaddr; + ipv6->ip6_src = *srcaddr; + + ether->src = idata->ether; + ether->dst = host->ether; + ether->ether_type = htons(ETHERTYPE_IPV6); + + prev_nh = (unsigned char *)&(ipv6->ip6_nxt); + + ptr = (unsigned char *)v6buffer + MIN_IPV6_HLEN; + + switch (type) { + case PROBE_ICMP6_ECHO: + *prev_nh = IPPROTO_ICMPV6; + + if ((ptr + sizeof(struct icmp6_hdr) + ICMPV6_ECHO_PAYLOAD_SIZE) > (v6buffer + icmp6_max_packet_size)) { + if (idata->verbose_f > 1) + puts("Packet too large while creating ICMPv6 Echo Request Probe packet"); + + return (-1); + } + + icmp6 = (struct icmp6_hdr *)ptr; + icmp6->icmp6_type = ICMP6_ECHO_REQUEST; + icmp6->icmp6_code = 0; + icmp6->icmp6_cksum = random(); + icmp6->icmp6_data16[0] = htons(getpid()); /* Identifier */ + icmp6->icmp6_data16[1] = htons(random()); /* Sequence Number */ + + ptr = ptr + sizeof(struct icmp6_hdr); + + for (i = 0; i < (ICMPV6_ECHO_PAYLOAD_SIZE >> 2); i++) { + *(uint32_t *)ptr = random(); + ptr += sizeof(uint32_t); + } + break; - case PROBE_UNREC_OPT: - *prev_nh = IPPROTO_DSTOPTS; + case PROBE_UNREC_OPT: + *prev_nh = IPPROTO_DSTOPTS; + if ((ptr + sizeof(struct icmp6_hdr) + 8 + ICMPV6_ECHO_PAYLOAD_SIZE) > (v6buffer + icmp6_max_packet_size)) { + if (idata->verbose_f > 1) + puts("Packet too large while creating Unrec. Opt. Probe Packet"); - if( (ptr+sizeof(struct icmp6_hdr) + 8 + ICMPV6_ECHO_PAYLOAD_SIZE) > (v6buffer+icmp6_max_packet_size)){ - if(idata->verbose_f>1) - puts("Packet too large while creating Unrec. Opt. Probe Packet"); + return (-1); + } - return(-1); - } + destopth = (struct ip6_dest *)ptr; + destopth->ip6d_len = 0; + destopth->ip6d_nxt = IPPROTO_ICMPV6; - destopth = (struct ip6_dest *) ptr; - destopth->ip6d_len= 0; - destopth->ip6d_nxt= IPPROTO_ICMPV6; + ptr = ptr + 2; + opt = (struct ip6_option *)ptr; + opt->ip6o_type = 0x80; + opt->ip6o_len = 4; - ptr= ptr + 2; - opt= (struct ip6_option *) ptr; - opt->ip6o_type= 0x80; - opt->ip6o_len= 4; + ptr = ptr + 2; + uint32 = (uint32_t *)ptr; + *uint32 = random(); - ptr= ptr + 2; - uint32 = (uint32_t *) ptr; - *uint32 = random(); + ptr = ptr + 4; + icmp6 = (struct icmp6_hdr *)ptr; + icmp6->icmp6_type = ICMP6_ECHO_REQUEST; + icmp6->icmp6_code = 0; + icmp6->icmp6_cksum = random(); + icmp6->icmp6_data16[0] = htons(getpid()); /* Identifier */ + icmp6->icmp6_data16[1] = htons(random()); /* Sequence Number */ - ptr= ptr +4; - icmp6 = (struct icmp6_hdr *) ptr; - icmp6->icmp6_type = ICMP6_ECHO_REQUEST; - icmp6->icmp6_code = 0; - icmp6->icmp6_cksum = random(); - icmp6->icmp6_data16[0]= htons(getpid()); /* Identifier */ - icmp6->icmp6_data16[1]= htons(random()); /* Sequence Number */ + ptr = ptr + sizeof(struct icmp6_hdr); - ptr = ptr+ sizeof(struct icmp6_hdr); + for (i = 0; i < (ICMPV6_ECHO_PAYLOAD_SIZE >> 2); i++) { + *(uint32_t *)ptr = random(); + ptr += sizeof(uint32_t); + } + break; + } - for(i=0; i<(ICMPV6_ECHO_PAYLOAD_SIZE>>2); i++){ - *(uint32_t *)ptr = random(); - ptr += sizeof(uint32_t); - } - break; - } + ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); + icmp6->icmp6_cksum = 0; + icmp6->icmp6_cksum = in_chksum(v6buffer, icmp6, ptr - ((unsigned char *)icmp6), IPPROTO_ICMPV6); - ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); - icmp6->icmp6_cksum = 0; - icmp6->icmp6_cksum = in_chksum(v6buffer, icmp6, ptr-((unsigned char *)icmp6), IPPROTO_ICMPV6); + /* We set the signal handler, and the anchor for siglongjump() */ + canjump = 0; + memset(&new_sig, 0, sizeof(struct sigaction)); + sigemptyset(&new_sig.sa_mask); + new_sig.sa_handler = &local_sig_alarm; - /* We set the signal handler, and the anchor for siglongjump() */ - canjump=0; - memset(&new_sig, 0, sizeof(struct sigaction)); - sigemptyset(&new_sig.sa_mask); - new_sig.sa_handler= &local_sig_alarm; + if (sigaction(SIGALRM, &new_sig, &old_sig) == -1) { + if (idata->verbose_f > 1) + puts("Error setting up 'Alarm' signal"); - if( sigaction(SIGALRM, &new_sig, &old_sig) == -1){ - if(idata->verbose_f>1) - puts("Error setting up 'Alarm' signal"); + return (-1); + } - return(-1); - } + if (sigsetjmp(env, 1) != 0) + tries++; - if(sigsetjmp(env, 1) != 0) - tries++; + canjump = 1; - canjump=1; + while (tries <= idata->local_retrans && !foundaddr_f && !error_f) { + if ((nw = pcap_inject(pfd, buffer, ptr - buffer)) == -1) { + if (idata->verbose_f > 1) + printf("pcap_inject(): %s\n", pcap_geterr(pfd)); - while(tries<= idata->local_retrans && !foundaddr_f && !error_f){ - if((nw=pcap_inject(pfd, buffer, ptr - buffer)) == -1){ - if(idata->verbose_f>1) - printf("pcap_inject(): %s\n", pcap_geterr(pfd)); + error_f = TRUE; + break; + } - error_f=TRUE; - break; - } + if (nw != (ptr - buffer)) { + if (idata->verbose_f > 1) + printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, (LUI)(ptr - buffer)); + + error_f = TRUE; + break; + } + + alarm(idata->local_timeout); - if(nw != (ptr-buffer)){ - if(idata->verbose_f>1) - printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, \ - (LUI) (ptr-buffer)); + foundaddr_f = FALSE; + + while (!foundaddr_f && !error_f) { - error_f=TRUE; - break; - } + do { + if ((result = pcap_next_ex(pfd, &pkthdr, &pktdata)) == -1) { + if (idata->verbose_f > 1) + printf("pcap_next_ex(): %s", pcap_geterr(pfd)); - alarm(idata->local_timeout); - - foundaddr_f=FALSE; + error_f = TRUE; + break; + } + } while (result == 0 || pktdata == NULL); + + if (error_f) + break; - while(!foundaddr_f && !error_f){ - - do{ - if( (result=pcap_next_ex(pfd, &pkthdr, &pktdata)) == -1){ - if(idata->verbose_f>1) - printf("pcap_next_ex(): %s", pcap_geterr(pfd)); + pkt_ether = (struct ether_header *)pktdata; + pkt_ipv6 = (struct ip6_hdr *)((char *)pkt_ether + ETHER_HDR_LEN); + pkt_end = (unsigned char *)pktdata + pkthdr->caplen; - error_f=TRUE; - break; - } - }while(result == 0 || pktdata == NULL); + if ((pkt_end - pktdata) < (ETHER_HDR_LEN + MIN_IPV6_HLEN)) + continue; - if(error_f) - break; + if (pkt_ipv6->ip6_nxt == IPPROTO_ICMPV6) { + pkt_icmp6 = (struct icmp6_hdr *)((char *)pkt_ipv6 + sizeof(struct ip6_hdr)); + + if (pkt_icmp6->icmp6_type == ND_NEIGHBOR_SOLICIT) { + pkt_ns = (struct nd_neighbor_solicit *)pkt_icmp6; + + if ((pkt_end - (unsigned char *)pkt_ns) < sizeof(struct nd_neighbor_solicit)) + continue; - pkt_ether = (struct ether_header *) pktdata; - pkt_ipv6 = (struct ip6_hdr *)((char *) pkt_ether + ETHER_HDR_LEN); - pkt_end = (unsigned char *) pktdata + pkthdr->caplen; + if (is_eq_in6_addr(&(pkt_ns->nd_ns_target), &(idata->ip6_local)) || + is_eq_in6_addr(&(pkt_ns->nd_ns_target), srcaddr)) { + if (send_neighbor_advert(idata, pfd, pktdata) == -1) { + error_f = TRUE; + break; + } + } + } + else if ((pkt_icmp6->icmp6_type == ICMP6_ECHO_REPLY) || (pkt_icmp6->icmp6_type == ICMP6_PARAM_PROB)) { + + if ((pkt_end - (unsigned char *)pkt_icmp6) < sizeof(struct icmp6_hdr)) + continue; - if( (pkt_end - pktdata) < (ETHER_HDR_LEN + MIN_IPV6_HLEN)) - continue; - - if(pkt_ipv6->ip6_nxt == IPPROTO_ICMPV6){ - pkt_icmp6 = (struct icmp6_hdr *) ((char *) pkt_ipv6 + sizeof(struct ip6_hdr)); - - if(pkt_icmp6->icmp6_type == ND_NEIGHBOR_SOLICIT){ - pkt_ns= (struct nd_neighbor_solicit *) pkt_icmp6; - - if( (pkt_end - (unsigned char *) pkt_ns) < sizeof(struct nd_neighbor_solicit)) - continue; - - if(is_eq_in6_addr(&(pkt_ns->nd_ns_target), &(idata->ip6_local)) || \ - is_eq_in6_addr(&(pkt_ns->nd_ns_target), srcaddr)){ - if(send_neighbor_advert(idata, pfd, pktdata) == -1){ - error_f=TRUE; - break; - } - } - } - else if( (pkt_icmp6->icmp6_type == ICMP6_ECHO_REPLY) || (pkt_icmp6->icmp6_type == ICMP6_PARAM_PROB)){ - - if( (pkt_end - (unsigned char *) pkt_icmp6) < sizeof(struct icmp6_hdr)) - continue; + if (valid_icmp6_response(idata, type, pkthdr, pktdata, buffer)) { + host->ether = pkt_ether->src; + host->flag = VALID_MAPPING; + foundaddr_f = TRUE; + break; + } + } + } - if(valid_icmp6_response(idata, type, pkthdr, pktdata, buffer)){ - host->ether= pkt_ether->src; - host->flag = VALID_MAPPING; - foundaddr_f=TRUE; - break; - } - } - } + } /* Processing packets */ - } /* Processing packets */ + } /* Resending Probe packet */ - } /* Resending Probe packet */ + if (sigaction(SIGALRM, &old_sig, NULL) == -1) { + if (idata->verbose_f > 1) + puts("Error setting up 'Alarm' signal"); - if( sigaction(SIGALRM, &old_sig, NULL) == -1){ - if(idata->verbose_f>1) - puts("Error setting up 'Alarm' signal"); - - error_f=TRUE; - } - - if(error_f) - return(-1); - else - return 0; + error_f = TRUE; + } + if (error_f) + return (-1); + else + return 0; } - - /* * Function: print_host_entries() * * Prints the IPv6 addresses (and optionally the Ethernet addresses) in a list */ -int print_host_entries(struct host_list *hlist, unsigned char flag){ - unsigned int i; +int print_host_entries(struct host_list *hlist, unsigned char flag) { + unsigned int i; - for(i=0; i < (hlist->nhosts); i++){ - if(inet_ntop(AF_INET6, &((hlist->host[i])->ip6), pv6addr, sizeof(pv6addr)) == NULL){ - if(verbose_f>1) - puts("inet_ntop(): Error converting IPv6 address to presentation format"); + for (i = 0; i < (hlist->nhosts); i++) { + if (inet_ntop(AF_INET6, &((hlist->host[i])->ip6), pv6addr, sizeof(pv6addr)) == NULL) { + if (verbose_f > 1) + puts("inet_ntop(): Error converting IPv6 address to presentation format"); - return(-1); - } + return (-1); + } - if(flag == PRINT_ETHER_ADDR){ - if(ether_ntop( &((hlist->host[i])->ether), plinkaddr, sizeof(plinkaddr)) == 0){ - if(verbose_f>1) - puts("ether_ntop(): Error converting address"); + if (flag == PRINT_ETHER_ADDR) { + if (ether_ntop(&((hlist->host[i])->ether), plinkaddr, sizeof(plinkaddr)) == 0) { + if (verbose_f > 1) + puts("ether_ntop(): Error converting address"); - return(-1); - } + return (-1); + } - printf("%s @ %s\n", pv6addr, plinkaddr); - } - else - printf("%s\n", pv6addr); - } + printf("%s @ %s\n", pv6addr, plinkaddr); + } + else + printf("%s\n", pv6addr); + } - return 0; + return 0; } - /* * Function: print_unique_host_entries() * - * Prints only one IPv6 address (and optionally the Ethernet addresses) per Ethernet + * Prints only one IPv6 address (and optionally the Ethernet addresses) per Ethernet * address in a list. */ -int print_unique_host_entries(struct host_list *hlist, unsigned char flag){ - unsigned int i, j, k; - - for(i=0; i < (hlist->nhosts); i++){ +int print_unique_host_entries(struct host_list *hlist, unsigned char flag) { + unsigned int i, j, k; - if(i){ - for(j=0; j < i; j++){ - for(k=0; k < ETH_ALEN; k++){ - if((hlist->host[i])->ether.a[k] != (hlist->host[j])->ether.a[k]) - break; - } + for (i = 0; i < (hlist->nhosts); i++) { - if(k == ETH_ALEN) - break; - } + if (i) { + for (j = 0; j < i; j++) { + for (k = 0; k < ETH_ALEN; k++) { + if ((hlist->host[i])->ether.a[k] != (hlist->host[j])->ether.a[k]) + break; + } - if(j < i) - continue; - } - - if(inet_ntop(AF_INET6, &((hlist->host[i])->ip6), pv6addr, sizeof(pv6addr)) == NULL){ - if(verbose_f>1) - puts("inet_ntop(): Error converting IPv6 address to presentation format"); + if (k == ETH_ALEN) + break; + } - return(-1); - } + if (j < i) + continue; + } - if(flag == PRINT_ETHER_ADDR){ - if(ether_ntop( &((hlist->host[i])->ether), plinkaddr, sizeof(plinkaddr)) == 0){ - if(verbose_f>1) - puts("ether_ntop(): Error converting address"); + if (inet_ntop(AF_INET6, &((hlist->host[i])->ip6), pv6addr, sizeof(pv6addr)) == NULL) { + if (verbose_f > 1) + puts("inet_ntop(): Error converting IPv6 address to presentation format"); - return(-1); - } + return (-1); + } - printf("%s @ %s\n", pv6addr, plinkaddr); - } - else - printf("%s\n", pv6addr); - } + if (flag == PRINT_ETHER_ADDR) { + if (ether_ntop(&((hlist->host[i])->ether), plinkaddr, sizeof(plinkaddr)) == 0) { + if (verbose_f > 1) + puts("ether_ntop(): Error converting address"); - return 0; -} + return (-1); + } + printf("%s @ %s\n", pv6addr, plinkaddr); + } + else + printf("%s\n", pv6addr); + } + return 0; +} /* * Function: free_host_entries() @@ -5485,214 +5426,206 @@ int print_unique_host_entries(struct host_list *hlist, unsigned char flag){ * Releases memory allocated for holding IPv6 addresses and Ethernet addresses */ -void free_host_entries(struct host_list *hlist){ - unsigned int i; +void free_host_entries(struct host_list *hlist) { + unsigned int i; - for(i=0; i< hlist->nhosts; i++) - free(hlist->host[i]); + for (i = 0; i < hlist->nhosts; i++) + free(hlist->host[i]); - hlist->nhosts=0; /* Set the number of entries to 0, to reflect the released memory */ - return; + hlist->nhosts = 0; /* Set the number of entries to 0, to reflect the released memory */ + return; } - /* * Function: create_candidate_globals() * * Generates list of cadidate global addresses based on the local Global prefixes and Interface IDs */ -int create_candidate_globals(struct iface_data *idata, struct host_list *local, struct host_list *global, \ - struct host_list *candidate){ - unsigned int i, j, k; - struct in6_addr caddr; +int create_candidate_globals(struct iface_data *idata, struct host_list *local, struct host_list *global, + struct host_list *candidate) { + unsigned int i, j, k; + struct in6_addr caddr; - for(i=0; (i < local->nhosts) && (candidate->nhosts < candidate->maxhosts); i++){ + for (i = 0; (i < local->nhosts) && (candidate->nhosts < candidate->maxhosts); i++) { - /* Avoid global Address present in "local" list -- shouldn't happen, though */ - if(IN6_IS_ADDR_LINKLOCAL(&((local->host[i])->ip6)) ){ - /* We create one candidate address with the Interface-ID of the link-local address, - for each of the autoconf prefixes - */ - for(j=0; (j < idata->prefix_ac.nprefix) && (candidate->nhosts < candidate->maxhosts); j++){ - for(k=0; k<2; k++) - caddr.s6_addr32[k] = (idata->prefix_ac.prefix[j])->ip6.s6_addr32[k]; + /* Avoid global Address present in "local" list -- shouldn't happen, though */ + if (IN6_IS_ADDR_LINKLOCAL(&((local->host[i])->ip6))) { + /* We create one candidate address with the Interface-ID of the link-local address, + for each of the autoconf prefixes + */ + for (j = 0; (j < idata->prefix_ac.nprefix) && (candidate->nhosts < candidate->maxhosts); j++) { + for (k = 0; k < 2; k++) + caddr.s6_addr32[k] = (idata->prefix_ac.prefix[j])->ip6.s6_addr32[k]; - for(k=2; k<4; k++) - caddr.s6_addr32[k] = local->host[i]->ip6.s6_addr32[k]; + for (k = 2; k < 4; k++) + caddr.s6_addr32[k] = local->host[i]->ip6.s6_addr32[k]; - /* We discard the candidate address if it is already present in the "global" list */ - if(is_ip6_in_list(&caddr, global)) - continue; + /* We discard the candidate address if it is already present in the "global" list */ + if (is_ip6_in_list(&caddr, global)) + continue; - if( (candidate->host[candidate->nhosts]=malloc(sizeof(struct host_entry))) == NULL){ - if(verbose_f>1) - puts("Error allocating memory while creating local -> global list"); + if ((candidate->host[candidate->nhosts] = malloc(sizeof(struct host_entry))) == NULL) { + if (verbose_f > 1) + puts("Error allocating memory while creating local -> global list"); - return(-1); - } + return (-1); + } - memset(candidate->host[candidate->nhosts], 0, sizeof(struct host_entry)); + memset(candidate->host[candidate->nhosts], 0, sizeof(struct host_entry)); - (candidate->host[candidate->nhosts])->ip6 = caddr; - (candidate->host[candidate->nhosts])->ether = (local->host[i])->ether; - (candidate->nhosts)++; - } + (candidate->host[candidate->nhosts])->ip6 = caddr; + (candidate->host[candidate->nhosts])->ether = (local->host[i])->ether; + (candidate->nhosts)++; + } + } + } - } - } - - return 0; + return 0; } - - /* * Function: validate_host_entries() * * Tests entries in a list, updates entries with invalid mappings, and removes non-existent addresses */ -int validate_host_entries(pcap_t *pfd, struct iface_data *idata, struct host_list *candidate, struct host_list *global){ - unsigned int i; - struct in6_addr *srcaddrptr; - - for(i=0; i< candidate->nhosts; i++){ - if((candidate->host[i])->flag == INVALID_MAPPING){ - srcaddrptr = sel_src_addr_ra(idata, &((candidate->host[i])->ip6)); - - if(probe_unrec_f){ - if(host_scan_local(pfd, idata, srcaddrptr, PROBE_UNREC_OPT, candidate->host[i]) == -1) - return(-1); - } - - if( ((candidate->host[i])->flag == INVALID_MAPPING) && probe_echo_f){ - if(host_scan_local(pfd, idata, srcaddrptr, PROBE_ICMP6_ECHO, candidate->host[i]) == -1) - return(-1); - } - } - - if((candidate->host[i])->flag == VALID_MAPPING){ - global->host[global->nhosts] = candidate->host[i]; - (global->nhosts)++; - } - else{ - free(candidate->host[i]); - } - } - - return 0; +int validate_host_entries(pcap_t *pfd, struct iface_data *idata, struct host_list *candidate, + struct host_list *global) { + unsigned int i; + struct in6_addr *srcaddrptr; + + for (i = 0; i < candidate->nhosts; i++) { + if ((candidate->host[i])->flag == INVALID_MAPPING) { + srcaddrptr = sel_src_addr_ra(idata, &((candidate->host[i])->ip6)); + + if (probe_unrec_f) { + if (host_scan_local(pfd, idata, srcaddrptr, PROBE_UNREC_OPT, candidate->host[i]) == -1) + return (-1); + } + + if (((candidate->host[i])->flag == INVALID_MAPPING) && probe_echo_f) { + if (host_scan_local(pfd, idata, srcaddrptr, PROBE_ICMP6_ECHO, candidate->host[i]) == -1) + return (-1); + } + } + + if ((candidate->host[i])->flag == VALID_MAPPING) { + global->host[global->nhosts] = candidate->host[i]; + (global->nhosts)++; + } + else { + free(candidate->host[i]); + } + } + + return 0; } - - /* * Function: valid_icmp6_response() * * Checks whether the response to an ICMPv6 probe is valid */ -int valid_icmp6_response(struct iface_data *idata, unsigned char type, struct pcap_pkthdr *pkthdr,\ - const u_char *pktdata, unsigned char *pktsent){ - - struct ether_header *pkt_ether; - struct ip6_hdr *pkt_ipv6, *ipv6; - struct icmp6_hdr *pkt_icmp6, *pkt_icmp6_icmp6, *icmp6; - unsigned char *pkt_end; - - ipv6 = (struct ip6_hdr *) (pktsent + sizeof(struct ether_header)); - - if(type == PROBE_UNREC_OPT) - icmp6 = (struct icmp6_hdr *) ( (char *) ipv6 + sizeof(struct ip6_hdr) + MIN_DST_OPT_HDR_SIZE); - else - icmp6 = (struct icmp6_hdr *) ( (char *) ipv6 + sizeof(struct ip6_hdr)); - - pkt_ether = (struct ether_header *) pktdata; - pkt_ipv6 = (struct ip6_hdr *)((char *) pkt_ether + ETHER_HDR_LEN); - pkt_icmp6 = (struct icmp6_hdr *) ((char *) pkt_ipv6 + MIN_IPV6_HLEN); - pkt_end = (unsigned char *) pktdata + pkthdr->caplen; - - switch(type){ - case PROBE_ICMP6_ECHO: - pkt_icmp6 = (struct icmp6_hdr *) ((char *) pkt_ipv6 + MIN_IPV6_HLEN); - - /* The packet length is the minimum of what we capured, and what is specified in the - IPv6 Total Lenght field - */ - if( pkt_end > ((unsigned char *)pkt_icmp6 + pkt_ipv6->ip6_plen) ) - pkt_end = (unsigned char *)pkt_icmp6 + pkt_ipv6->ip6_plen; - - /* - Discard the packet if it is not of the minimum size to contain an ICMPv6 - header and the payload we included in the ICMPv6 Echo Request - */ - if( (pkt_end - (unsigned char *) pkt_icmp6) < (sizeof(struct icmp6_hdr) + \ - ICMPV6_ECHO_PAYLOAD_SIZE) ) - return 0; - - break; - - case PROBE_UNREC_OPT: - pkt_icmp6 = (struct icmp6_hdr *) ((char *) pkt_ipv6 + MIN_IPV6_HLEN); - - /* The packet length is the minimum of what we capured, and what is specified in the - IPv6 Total Lenght field - */ - if( pkt_end > ((unsigned char *)pkt_icmp6 + pkt_ipv6->ip6_plen) ) - pkt_end = (unsigned char *)pkt_icmp6 + pkt_ipv6->ip6_plen; - - /* - Discard the packet if it is not of the minimum size to contain an ICMPv6 - header and the embedded payload - */ - if( (pkt_end - (unsigned char *) pkt_icmp6) < (sizeof(struct icmp6_hdr) + \ - + sizeof(struct ip6_hdr) + MIN_DST_OPT_HDR_SIZE + sizeof(struct icmp6_hdr) + \ - ICMPV6_ECHO_PAYLOAD_SIZE) ) - return 0; - - break; - - } - - /* - Check that that the Destination Address of the incoming packet is the same as the one - we used for the Source Address of the Probe packet. - */ - if(!is_eq_in6_addr(&(pkt_ipv6->ip6_dst), &(ipv6->ip6_src))) - return 0; - - /* Check that the ICMPv6 checksum is correct */ - if(in_chksum(pkt_ipv6, pkt_icmp6, pkt_end-((unsigned char *)pkt_icmp6), IPPROTO_ICMPV6) != 0) - return 0; - - switch(type){ - case PROBE_ICMP6_ECHO: - if(pkt_icmp6->icmp6_data16[0] != icmp6->icmp6_data16[0]){ - return 0; - } - else if(pkt_icmp6->icmp6_data16[1] != icmp6->icmp6_data16[1]){ - return 0; - } - - break; - - case PROBE_UNREC_OPT: - pkt_icmp6_icmp6= (struct icmp6_hdr *) ((unsigned char *) pkt_icmp6 + sizeof(struct icmp6_hdr) +\ - sizeof(struct ip6_hdr) + MIN_DST_OPT_HDR_SIZE); - - if(pkt_icmp6_icmp6->icmp6_data16[0] != icmp6->icmp6_data16[0]){ - return 0; - } - else if(pkt_icmp6_icmp6->icmp6_data16[1] != icmp6->icmp6_data16[1]){ - return 0; - } - - break; - } - - return 1; -} +int valid_icmp6_response(struct iface_data *idata, unsigned char type, struct pcap_pkthdr *pkthdr, + const u_char *pktdata, unsigned char *pktsent) { + + struct ether_header *pkt_ether; + struct ip6_hdr *pkt_ipv6, *ipv6; + struct icmp6_hdr *pkt_icmp6, *pkt_icmp6_icmp6, *icmp6; + unsigned char *pkt_end; + + ipv6 = (struct ip6_hdr *)(pktsent + sizeof(struct ether_header)); + + if (type == PROBE_UNREC_OPT) + icmp6 = (struct icmp6_hdr *)((char *)ipv6 + sizeof(struct ip6_hdr) + MIN_DST_OPT_HDR_SIZE); + else + icmp6 = (struct icmp6_hdr *)((char *)ipv6 + sizeof(struct ip6_hdr)); + pkt_ether = (struct ether_header *)pktdata; + pkt_ipv6 = (struct ip6_hdr *)((char *)pkt_ether + ETHER_HDR_LEN); + pkt_icmp6 = (struct icmp6_hdr *)((char *)pkt_ipv6 + MIN_IPV6_HLEN); + pkt_end = (unsigned char *)pktdata + pkthdr->caplen; + + switch (type) { + case PROBE_ICMP6_ECHO: + pkt_icmp6 = (struct icmp6_hdr *)((char *)pkt_ipv6 + MIN_IPV6_HLEN); + + /* The packet length is the minimum of what we capured, and what is specified in the + IPv6 Total Lenght field + */ + if (pkt_end > ((unsigned char *)pkt_icmp6 + pkt_ipv6->ip6_plen)) + pkt_end = (unsigned char *)pkt_icmp6 + pkt_ipv6->ip6_plen; + + /* + Discard the packet if it is not of the minimum size to contain an ICMPv6 + header and the payload we included in the ICMPv6 Echo Request + */ + if ((pkt_end - (unsigned char *)pkt_icmp6) < (sizeof(struct icmp6_hdr) + ICMPV6_ECHO_PAYLOAD_SIZE)) + return 0; + + break; + + case PROBE_UNREC_OPT: + pkt_icmp6 = (struct icmp6_hdr *)((char *)pkt_ipv6 + MIN_IPV6_HLEN); + + /* The packet length is the minimum of what we capured, and what is specified in the + IPv6 Total Lenght field + */ + if (pkt_end > ((unsigned char *)pkt_icmp6 + pkt_ipv6->ip6_plen)) + pkt_end = (unsigned char *)pkt_icmp6 + pkt_ipv6->ip6_plen; + + /* + Discard the packet if it is not of the minimum size to contain an ICMPv6 + header and the embedded payload + */ + if ((pkt_end - (unsigned char *)pkt_icmp6) < + (sizeof(struct icmp6_hdr) + +sizeof(struct ip6_hdr) + MIN_DST_OPT_HDR_SIZE + sizeof(struct icmp6_hdr) + + ICMPV6_ECHO_PAYLOAD_SIZE)) + return 0; + + break; + } + + /* + Check that that the Destination Address of the incoming packet is the same as the one + we used for the Source Address of the Probe packet. + */ + if (!is_eq_in6_addr(&(pkt_ipv6->ip6_dst), &(ipv6->ip6_src))) + return 0; + + /* Check that the ICMPv6 checksum is correct */ + if (in_chksum(pkt_ipv6, pkt_icmp6, pkt_end - ((unsigned char *)pkt_icmp6), IPPROTO_ICMPV6) != 0) + return 0; + + switch (type) { + case PROBE_ICMP6_ECHO: + if (pkt_icmp6->icmp6_data16[0] != icmp6->icmp6_data16[0]) { + return 0; + } + else if (pkt_icmp6->icmp6_data16[1] != icmp6->icmp6_data16[1]) { + return 0; + } + + break; + + case PROBE_UNREC_OPT: + pkt_icmp6_icmp6 = (struct icmp6_hdr *)((unsigned char *)pkt_icmp6 + sizeof(struct icmp6_hdr) + + sizeof(struct ip6_hdr) + MIN_DST_OPT_HDR_SIZE); + + if (pkt_icmp6_icmp6->icmp6_data16[0] != icmp6->icmp6_data16[0]) { + return 0; + } + else if (pkt_icmp6_icmp6->icmp6_data16[1] != icmp6->icmp6_data16[1]) { + return 0; + } + + break; + } + + return 1; +} /* * Function: valid_icmp6_response_remote() @@ -5700,107 +5633,101 @@ int valid_icmp6_response(struct iface_data *idata, unsigned char type, struct pc * Checks whether the response to an ICMPv6 probe is valid */ -int valid_icmp6_response_remote(struct iface_data *idata, struct scan_list *scan, unsigned char type, struct pcap_pkthdr *pkthdr,\ - const u_char *pktdata, unsigned char *pktsent){ - - struct ether_header *pkt_ether; - struct ip6_hdr *pkt_ipv6, *ipv6; - struct icmp6_hdr *pkt_icmp6, *pkt_icmp6_icmp6, *icmp6; - unsigned char *pkt_end; - - ipv6 = (struct ip6_hdr *) (pktsent + idata->linkhsize); - - if(type == PROBE_UNREC_OPT) - icmp6 = (struct icmp6_hdr *) ( (char *) ipv6 + sizeof(struct ip6_hdr) + MIN_DST_OPT_HDR_SIZE); - else - icmp6 = (struct icmp6_hdr *) ( (char *) ipv6 + sizeof(struct ip6_hdr)); - - pkt_ether = (struct ether_header *) pktdata; - pkt_ipv6 = (struct ip6_hdr *)((char *) pkt_ether + idata->linkhsize); - pkt_icmp6 = (struct icmp6_hdr *) ((char *) pkt_ipv6 + sizeof(struct ip6_hdr)); - pkt_end = (unsigned char *) pktdata + pkthdr->caplen; - - switch(type){ - case PROBE_ICMP6_ECHO: - /* The packet length is the minimum of what we capured, and what is specified in the - IPv6 Total Lenght field - */ - if( pkt_end > ((unsigned char *)pkt_icmp6 + pkt_ipv6->ip6_plen) ) - pkt_end = (unsigned char *)pkt_icmp6 + pkt_ipv6->ip6_plen; - - /* - Discard the packet if it is not of the minimum size to contain an ICMPv6 - header and the payload we included in the ICMPv6 Echo Request - */ - if( (pkt_end - (unsigned char *) pkt_icmp6) < (sizeof(struct icmp6_hdr) + \ - ICMPV6_ECHO_PAYLOAD_SIZE) ) - return 0; - - break; - - case PROBE_UNREC_OPT: - /* The packet length is the minimum of what we capured, and what is specified in the - IPv6 Total Lenght field - */ - if( pkt_end > ((unsigned char *)pkt_icmp6 + pkt_ipv6->ip6_plen) ) - pkt_end = (unsigned char *)pkt_icmp6 + pkt_ipv6->ip6_plen; - - /* - Discard the packet if it is not of the minimum size to contain an ICMPv6 - header and the empedded payload - */ - if( (pkt_end - (unsigned char *) pkt_icmp6) < (sizeof(struct icmp6_hdr) + \ - + sizeof(struct ip6_hdr) + MIN_DST_OPT_HDR_SIZE + sizeof(struct icmp6_hdr) + \ - ICMPV6_ECHO_PAYLOAD_SIZE) ) - return 0; - - break; - - } - - /* - Check that that the Destination Address of the incoming packet is the same as the one - we used for the Source Address of the Probe packet. - */ - if(!is_eq_in6_addr(&(pkt_ipv6->ip6_dst), &(ipv6->ip6_src))) - return 0; - - /* Check that the ICMPv6 checksum is correct */ - if(in_chksum(pkt_ipv6, pkt_icmp6, pkt_end-((unsigned char *)pkt_icmp6), IPPROTO_ICMPV6) != 0) - return 0; - - switch(type){ - case PROBE_ICMP6_ECHO: - if(pkt_icmp6->icmp6_data16[0] != icmp6->icmp6_data16[0]){ - return 0; - } - else if(pkt_icmp6->icmp6_data16[1] != icmp6->icmp6_data16[1]){ - return 0; - } - - break; - - case PROBE_UNREC_OPT: - pkt_icmp6_icmp6= (struct icmp6_hdr *) ((unsigned char *) pkt_icmp6 + sizeof(struct icmp6_hdr) +\ - sizeof(struct ip6_hdr) + MIN_DST_OPT_HDR_SIZE); - - if(pkt_icmp6_icmp6->icmp6_data16[0] != icmp6->icmp6_data16[0]){ - return 0; - } - - - else if(pkt_icmp6_icmp6->icmp6_data16[1] != icmp6->icmp6_data16[1]){ - return 0; - } - - break; - } - - return 1; -} +int valid_icmp6_response_remote(struct iface_data *idata, struct scan_list *scan, unsigned char type, + struct pcap_pkthdr *pkthdr, const u_char *pktdata, unsigned char *pktsent) { + + struct ether_header *pkt_ether; + struct ip6_hdr *pkt_ipv6, *ipv6; + struct icmp6_hdr *pkt_icmp6, *pkt_icmp6_icmp6, *icmp6; + unsigned char *pkt_end; + + ipv6 = (struct ip6_hdr *)(pktsent + idata->linkhsize); + + if (type == PROBE_UNREC_OPT) + icmp6 = (struct icmp6_hdr *)((char *)ipv6 + sizeof(struct ip6_hdr) + MIN_DST_OPT_HDR_SIZE); + else + icmp6 = (struct icmp6_hdr *)((char *)ipv6 + sizeof(struct ip6_hdr)); + + pkt_ether = (struct ether_header *)pktdata; + pkt_ipv6 = (struct ip6_hdr *)((char *)pkt_ether + idata->linkhsize); + pkt_icmp6 = (struct icmp6_hdr *)((char *)pkt_ipv6 + sizeof(struct ip6_hdr)); + pkt_end = (unsigned char *)pktdata + pkthdr->caplen; + + switch (type) { + case PROBE_ICMP6_ECHO: + /* The packet length is the minimum of what we capured, and what is specified in the + IPv6 Total Lenght field + */ + if (pkt_end > ((unsigned char *)pkt_icmp6 + pkt_ipv6->ip6_plen)) + pkt_end = (unsigned char *)pkt_icmp6 + pkt_ipv6->ip6_plen; + + /* + Discard the packet if it is not of the minimum size to contain an ICMPv6 + header and the payload we included in the ICMPv6 Echo Request + */ + if ((pkt_end - (unsigned char *)pkt_icmp6) < (sizeof(struct icmp6_hdr) + ICMPV6_ECHO_PAYLOAD_SIZE)) + return 0; + break; + case PROBE_UNREC_OPT: + /* The packet length is the minimum of what we capured, and what is specified in the + IPv6 Total Lenght field + */ + if (pkt_end > ((unsigned char *)pkt_icmp6 + pkt_ipv6->ip6_plen)) + pkt_end = (unsigned char *)pkt_icmp6 + pkt_ipv6->ip6_plen; + /* + Discard the packet if it is not of the minimum size to contain an ICMPv6 + header and the empedded payload + */ + if ((pkt_end - (unsigned char *)pkt_icmp6) < + (sizeof(struct icmp6_hdr) + +sizeof(struct ip6_hdr) + MIN_DST_OPT_HDR_SIZE + sizeof(struct icmp6_hdr) + + ICMPV6_ECHO_PAYLOAD_SIZE)) + return 0; + + break; + } + + /* + Check that that the Destination Address of the incoming packet is the same as the one + we used for the Source Address of the Probe packet. + */ + if (!is_eq_in6_addr(&(pkt_ipv6->ip6_dst), &(ipv6->ip6_src))) + return 0; + + /* Check that the ICMPv6 checksum is correct */ + if (in_chksum(pkt_ipv6, pkt_icmp6, pkt_end - ((unsigned char *)pkt_icmp6), IPPROTO_ICMPV6) != 0) + return 0; + + switch (type) { + case PROBE_ICMP6_ECHO: + if (pkt_icmp6->icmp6_data16[0] != icmp6->icmp6_data16[0]) { + return 0; + } + else if (pkt_icmp6->icmp6_data16[1] != icmp6->icmp6_data16[1]) { + return 0; + } + + break; + + case PROBE_UNREC_OPT: + pkt_icmp6_icmp6 = (struct icmp6_hdr *)((unsigned char *)pkt_icmp6 + sizeof(struct icmp6_hdr) + + sizeof(struct ip6_hdr) + MIN_DST_OPT_HDR_SIZE); + + if (pkt_icmp6_icmp6->icmp6_data16[0] != icmp6->icmp6_data16[0]) { + return 0; + } + + else if (pkt_icmp6_icmp6->icmp6_data16[1] != icmp6->icmp6_data16[1]) { + return 0; + } + + break; + } + + return 1; +} /* * Function: process_config_file() @@ -5808,286 +5735,275 @@ int valid_icmp6_response_remote(struct iface_data *idata, struct scan_list *scan * Processes the SI6 Networks' toolkit configuration file */ -int process_config_file(const char *path){ - FILE *fp; - char *key, *value; - char line[MAX_LINE_SIZE]; - int r; - unsigned int ln=1; - - if( (fp=fopen(path, "r")) == NULL){ - return(0); - } - - while(fgets(line, sizeof(line), fp) != NULL){ - r=keyval(line, Strnlen(line, MAX_LINE_SIZE), &key, &value); - - if(r == 1){ - if(strncmp(key, "OUI-Database", MAX_VAR_NAME_LEN) == 0){ - strncpy(fname, value, MAX_FILENAME_SIZE-1); - fname[MAX_FILENAME_SIZE-1]=0; - fname_f=TRUE; - } - else if(strncmp(key, "Ports-Database", MAX_VAR_NAME_LEN) == 0){ - strncpy(portsfname, value, MAX_FILENAME_SIZE-1); - portsfname[MAX_FILENAME_SIZE-1]=0; - portsfname_f=TRUE; - } - else if(strncmp(key, "Top-Ports-Database", MAX_VAR_NAME_LEN) == 0){ - strncpy(topportsfname, value, MAX_FILENAME_SIZE-1); - topportsfname[MAX_FILENAME_SIZE-1]=0; - topportsfname_f=TRUE; - } - } - else if(r == -1){ - if(verbose_f){ - printf("Error in configuration file %s", configfile); - } - - fclose(fp); - return(0); - } - - ln++; - } - - fclose(fp); - - if(!fname_f) - strncpy(fname, "/usr/local/share/ipv6toolkit/oui.txt", MAX_FILENAME_SIZE-1); - - if(!portsfname_f) - strncpy(portsfname, "/usr/local/share/ipv6toolkit/service-names-port-numbers.csv", MAX_FILENAME_SIZE-1); - - if(!topportsfname_f) - strncpy(topportsfname, "/usr/local/share/ipv6toolkit/top-port-numbers.csv", MAX_FILENAME_SIZE-1); - - return(1); +int process_config_file(const char *path) { + FILE *fp; + char *key, *value; + char line[MAX_LINE_SIZE]; + int r; + unsigned int ln = 1; + + if ((fp = fopen(path, "r")) == NULL) { + return (0); + } + + while (fgets(line, sizeof(line), fp) != NULL) { + r = keyval(line, Strnlen(line, MAX_LINE_SIZE), &key, &value); + + if (r == 1) { + if (strncmp(key, "OUI-Database", MAX_VAR_NAME_LEN) == 0) { + strncpy(fname, value, MAX_FILENAME_SIZE - 1); + fname[MAX_FILENAME_SIZE - 1] = 0; + fname_f = TRUE; + } + else if (strncmp(key, "Ports-Database", MAX_VAR_NAME_LEN) == 0) { + strncpy(portsfname, value, MAX_FILENAME_SIZE - 1); + portsfname[MAX_FILENAME_SIZE - 1] = 0; + portsfname_f = TRUE; + } + else if (strncmp(key, "Top-Ports-Database", MAX_VAR_NAME_LEN) == 0) { + strncpy(topportsfname, value, MAX_FILENAME_SIZE - 1); + topportsfname[MAX_FILENAME_SIZE - 1] = 0; + topportsfname_f = TRUE; + } + } + else if (r == -1) { + if (verbose_f) { + printf("Error in configuration file %s", configfile); + } + + fclose(fp); + return (0); + } + + ln++; + } + + fclose(fp); + + if (!fname_f) + strncpy(fname, "/usr/local/share/ipv6toolkit/oui.txt", MAX_FILENAME_SIZE - 1); + + if (!portsfname_f) + strncpy(portsfname, "/usr/local/share/ipv6toolkit/service-names-port-numbers.csv", MAX_FILENAME_SIZE - 1); + + if (!topportsfname_f) + strncpy(topportsfname, "/usr/local/share/ipv6toolkit/top-port-numbers.csv", MAX_FILENAME_SIZE - 1); + + return (1); } - - /* * Function: is_ip6_in_scan_list() * * Check whether an IPv6 address belongs to one of our scan ranges */ -int is_ip6_in_scan_list(struct scan_list *scan, struct in6_addr *ip6){ - unsigned int i, j; - union my6_addr myip6; +int is_ip6_in_scan_list(struct scan_list *scan, struct in6_addr *ip6) { + unsigned int i, j; + union my6_addr myip6; - myip6.in6_addr= *ip6; + myip6.in6_addr = *ip6; - for(i=0; i< scan->ntarget; i++){ - for(j=0; j<8; j++){ - if( (ntohs(myip6.s6addr16[j]) < ntohs((scan->target[i])->start.s6addr16[j])) || \ - (ntohs(myip6.s6addr16[j]) > ntohs((scan->target[i])->end.s6addr16[j]))){ - break; - } - } + for (i = 0; i < scan->ntarget; i++) { + for (j = 0; j < 8; j++) { + if ((ntohs(myip6.s6addr16[j]) < ntohs((scan->target[i])->start.s6addr16[j])) || + (ntohs(myip6.s6addr16[j]) > ntohs((scan->target[i])->end.s6addr16[j]))) { + break; + } + } - if(j == 8) - return(TRUE); - } + if (j == 8) + return (TRUE); + } - return(FALSE); + return (FALSE); } - - - /* * Handler for the ALARM signal. * * Used for setting a timeout on libpcap reads */ -void local_sig_alarm(int num){ - if(canjump == 0) - return; +void local_sig_alarm(int num) { + if (canjump == 0) + return; - siglongjmp(env, 1); + siglongjmp(env, 1); } - - /* * Function: load_port_table() * * Create table with mappings of port number -> service name */ -int load_port_table(struct port_table_entry *pentry, char *prot, unsigned int maxport){ - FILE *fp; - char line[MAX_PORTS_LINE_SIZE], proto[MAX_PORTS_LINE_SIZE], name[MAX_PORTS_LINE_SIZE]; - char *charptr, *lasts; - unsigned int lines=0, ports=0; - unsigned int port; - char unassigned[]="Unassigned"; - - /* We initialize all entries to "Unassigned" */ - for(i=0; i= maxport) - continue; + port = atoi(charptr); - if((charptr = strtok_r(NULL, ",", &lasts)) == NULL){ - continue; - } + if (port >= maxport) + continue; - strncpy(proto, charptr, sizeof(proto)); - proto[sizeof(proto)-1]=0; + if ((charptr = strtok_r(NULL, ",", &lasts)) == NULL) { + continue; + } - if(strncmp(prot, proto, sizeof(proto)) == 0){ - strncpy(pentry[port].name, name, sizeof(pentry[port].name)); - pentry[port].name[sizeof(pentry[port].name)-1]=0; - } - } + strncpy(proto, charptr, sizeof(proto)); + proto[sizeof(proto) - 1] = 0; + if (strncmp(prot, proto, sizeof(proto)) == 0) { + strncpy(pentry[port].name, name, sizeof(pentry[port].name)); + pentry[port].name[sizeof(pentry[port].name) - 1] = 0; + } + } - if(ferror(fp)){ - perror("scan6:"); + if (ferror(fp)) { + perror("scan6:"); - return(FALSE); - } + return (FALSE); + } - fclose(fp); - return(TRUE); + fclose(fp); + return (TRUE); } - - /* * Function: load_top_ports_entries() * * Load target ports from top ports file */ -int load_top_ports_entries(struct port_list *tcp_port_list, struct port_list *udp_port_list, uint8_t protocol, unsigned int maxport){ - FILE *fp; - char line[MAX_PORTS_LINE_SIZE]; - char *charptr, *lasts; - unsigned int lines=0, ports=0; - uint16_t port; - uint8_t cprotocol; - struct port_list *port_list; - - if( (fp=fopen(topportsfname, "r")) == NULL){ - perror("scan6:"); - return(0); - } - - while( ports < maxport && fgets(line, MAX_PORTS_LINE_SIZE, fp) != NULL){ - lines=Strnlen(line, MAX_PORTS_LINE_SIZE); - charptr= (char *)line; - - /* Skip any whitespaces */ - while(charptr < ( (char *)line + lines) && *charptr == ' ') - charptr++; - - if((charptr = strtok_r(charptr, ",", &lasts)) == NULL){ - continue; - } - - port= atoi(charptr); - - if((charptr = strtok_r(NULL, ",", &lasts)) == NULL){ - continue; - } - - if(strncmp(charptr, "tcp", 3) == 0 || strncmp(charptr, "TCP", 3) == 0){ - cprotocol= IPPROTO_TCP; - port_list= tcp_port_list; - } - else if(strncmp(charptr, "udp", 3) == 0 || strncmp(charptr, "UDP", 3) == 0){ - cprotocol= IPPROTO_UDP; - port_list= udp_port_list; - } - else - continue; - - /* If this entry corresponds to the protocol we have selected, incorporate the entry */ - if(protocol == cprotocol || protocol==IPPROTO_ALL){ - if(port_list->nport < port_list->maxport){ - if( (port_list->port[port_list->nport] = malloc(sizeof(struct port_entry))) == NULL){ - if(idata.verbose_f) - puts("scan6: Not enough memory"); - - exit(EXIT_FAILURE); - } - - port_list->port[port_list->nport]->start= port; - port_list->port[port_list->nport]->end= port; - (port_list->port[port_list->nport])->cur= (port_list->port[port_list->nport])->start; - port_list->nport++; - ports++; - } - else{ - /* - If the number of "prots" has already been exceeded, it doesn't make sense to continue further, - since there wouldn't be space for any specific target types - */ - if(idata.verbose_f) - puts("Too many port ranges!"); - - exit(EXIT_FAILURE); - } - } - } - - if(ferror(fp)){ - perror("scan6:"); - - return(0); - } - - fclose(fp); - return(TRUE); +int load_top_ports_entries(struct port_list *tcp_port_list, struct port_list *udp_port_list, uint8_t protocol, + unsigned int maxport) { + FILE *fp; + char line[MAX_PORTS_LINE_SIZE]; + char *charptr, *lasts; + unsigned int lines = 0, ports = 0; + uint16_t port; + uint8_t cprotocol; + struct port_list *port_list; + + if ((fp = fopen(topportsfname, "r")) == NULL) { + perror("scan6:"); + return (0); + } + + while (ports < maxport && fgets(line, MAX_PORTS_LINE_SIZE, fp) != NULL) { + lines = Strnlen(line, MAX_PORTS_LINE_SIZE); + charptr = (char *)line; + + /* Skip any whitespaces */ + while (charptr < ((char *)line + lines) && *charptr == ' ') + charptr++; + + if ((charptr = strtok_r(charptr, ",", &lasts)) == NULL) { + continue; + } + + port = atoi(charptr); + + if ((charptr = strtok_r(NULL, ",", &lasts)) == NULL) { + continue; + } + + if (strncmp(charptr, "tcp", 3) == 0 || strncmp(charptr, "TCP", 3) == 0) { + cprotocol = IPPROTO_TCP; + port_list = tcp_port_list; + } + else if (strncmp(charptr, "udp", 3) == 0 || strncmp(charptr, "UDP", 3) == 0) { + cprotocol = IPPROTO_UDP; + port_list = udp_port_list; + } + else + continue; + + /* If this entry corresponds to the protocol we have selected, incorporate the entry */ + if (protocol == cprotocol || protocol == IPPROTO_ALL) { + if (port_list->nport < port_list->maxport) { + if ((port_list->port[port_list->nport] = malloc(sizeof(struct port_entry))) == NULL) { + if (idata.verbose_f) + puts("scan6: Not enough memory"); + + exit(EXIT_FAILURE); + } + + port_list->port[port_list->nport]->start = port; + port_list->port[port_list->nport]->end = port; + (port_list->port[port_list->nport])->cur = (port_list->port[port_list->nport])->start; + port_list->nport++; + ports++; + } + else { + /* + If the number of "prots" has already been exceeded, it doesn't make sense to continue further, + since there wouldn't be space for any specific target types + */ + if (idata.verbose_f) + puts("Too many port ranges!"); + + exit(EXIT_FAILURE); + } + } + } + + if (ferror(fp)) { + perror("scan6:"); + + return (0); + } + + fclose(fp); + return (TRUE); } - - /* * Function: print_port_table() * * Print the port table (for debugging puroses) */ -void print_port_table(struct port_table_entry *pentry, unsigned int maxport){ - unsigned int i; +void print_port_table(struct port_table_entry *pentry, unsigned int maxport) { + unsigned int i; - for(i=0; i < maxport; i++){ - printf("%5d (%s)\n", i, pentry[i].name); - } + for (i = 0; i < maxport; i++) { + printf("%5d (%s)\n", i, pentry[i].name); + } } /* @@ -6096,195 +6012,186 @@ void print_port_table(struct port_table_entry *pentry, unsigned int maxport){ * Initialize the contents of the attack packet (Ethernet header, IPv6 Header, and ICMPv6 header) * that are expected to remain constant for the specified attack. */ -void init_packet_data(struct iface_data *idata){ - struct dlt_null *dlt_null; - ethernet= (struct ether_header *) buffer; - dlt_null= (struct dlt_null *) buffer; - v6buffer = buffer + idata->linkhsize; - ipv6 = (struct ip6_hdr *) v6buffer; - - if(idata->type == DLT_EN10MB){ - ethernet->ether_type = htons(ETHERTYPE_IPV6); - - if(!(idata->flags & IFACE_LOOPBACK)){ - ethernet->src = idata->hsrcaddr; - ethernet->dst = idata->hdstaddr; - } - } - else if(idata->type == DLT_NULL){ - dlt_null->family= PF_INET6; - } -#if defined (__OpenBSD__) - else if(idata->type == DLT_LOOP){ - dlt_null->family= htonl(PF_INET6); - } +void init_packet_data(struct iface_data *idata) { + struct dlt_null *dlt_null; + ethernet = (struct ether_header *)buffer; + dlt_null = (struct dlt_null *)buffer; + v6buffer = buffer + idata->linkhsize; + ipv6 = (struct ip6_hdr *)v6buffer; + + if (idata->type == DLT_EN10MB) { + ethernet->ether_type = htons(ETHERTYPE_IPV6); + + if (!(idata->flags & IFACE_LOOPBACK)) { + ethernet->src = idata->hsrcaddr; + ethernet->dst = idata->hdstaddr; + } + } + else if (idata->type == DLT_NULL) { + dlt_null->family = PF_INET6; + } +#if defined(__OpenBSD__) + else if (idata->type == DLT_LOOP) { + dlt_null->family = htonl(PF_INET6); + } #endif - ipv6->ip6_flow=0; - ipv6->ip6_vfc= 0x60; - ipv6->ip6_hlim= hoplimit; - ipv6->ip6_src= idata->srcaddr; - ipv6->ip6_dst= idata->dstaddr; - - prev_nh = (unsigned char *) &(ipv6->ip6_nxt); - - ptr = (unsigned char *) v6buffer + MIN_IPV6_HLEN; - - if(hbhopthdr_f){ - hbhopthdrs=0; - - while(hbhopthdrs < nhbhopthdr){ - if((ptr+ hbhopthdrlen[hbhopthdrs]) > (v6buffer+ idata->mtu)){ - puts("Packet too large while processing HBH Opt. Header"); - exit(EXIT_FAILURE); - } - - *prev_nh = IPPROTO_HOPOPTS; - prev_nh = ptr; - memcpy(ptr, hbhopthdr[hbhopthdrs], hbhopthdrlen[hbhopthdrs]); - ptr = ptr + hbhopthdrlen[hbhopthdrs]; - hbhopthdrs++; - } - } - - if(dstoptuhdr_f){ - dstoptuhdrs=0; - - while(dstoptuhdrs < ndstoptuhdr){ - if((ptr+ dstoptuhdrlen[dstoptuhdrs]) > (v6buffer+ idata->mtu)){ - puts("Packet too large while processing Dest. Opt. Header (Unfrag. Part)"); - exit(EXIT_FAILURE); - } - - *prev_nh = IPPROTO_DSTOPTS; - prev_nh = ptr; - memcpy(ptr, dstoptuhdr[dstoptuhdrs], dstoptuhdrlen[dstoptuhdrs]); - ptr = ptr + dstoptuhdrlen[dstoptuhdrs]; - dstoptuhdrs++; - } - } - - /* Everything that follows is the Fragmentable Part of the packet */ - fragpart = ptr; - - if(idata->fragh_f){ - /* Check that we are able to send the Unfragmentable Part, together with a - Fragment Header and a chunk data over our link layer - */ - if( (fragpart+sizeof(fraghdr)+nfrags) > (v6buffer+idata->mtu)){ - puts("Unfragmentable part too large for current MTU"); - exit(EXIT_FAILURE); - } - - /* We prepare a separete Fragment Header, but we do not include it in the packet to be sent. - This Fragment Header will be used (an assembled with the rest of the packet by the - send_packet() function. - */ - memset(&fraghdr, 0, FRAG_HDR_SIZE); - *prev_nh = IPPROTO_FRAGMENT; - prev_nh = (unsigned char *) &fraghdr; - } - - if(dstopthdr_f){ - dstopthdrs=0; - - while(dstopthdrs < ndstopthdr){ - if((ptr+ dstopthdrlen[dstopthdrs]) > (v6buffer+ idata->max_packet_size)){ - puts("Packet too large while processing Dest. Opt. Header (should be using the Frag. option?)"); - exit(EXIT_FAILURE); - } - - *prev_nh = IPPROTO_DSTOPTS; - prev_nh = ptr; - memcpy(ptr, dstopthdr[dstopthdrs], dstopthdrlen[dstopthdrs]); - ptr = ptr + dstopthdrlen[dstopthdrs]; - dstopthdrs++; - } - } - - - *prev_nh = IPPROTO_TCP; - - startofprefixes=ptr; + ipv6->ip6_flow = 0; + ipv6->ip6_vfc = 0x60; + ipv6->ip6_hlim = hoplimit; + ipv6->ip6_src = idata->srcaddr; + ipv6->ip6_dst = idata->dstaddr; + + prev_nh = (unsigned char *)&(ipv6->ip6_nxt); + + ptr = (unsigned char *)v6buffer + MIN_IPV6_HLEN; + + if (hbhopthdr_f) { + hbhopthdrs = 0; + + while (hbhopthdrs < nhbhopthdr) { + if ((ptr + hbhopthdrlen[hbhopthdrs]) > (v6buffer + idata->mtu)) { + puts("Packet too large while processing HBH Opt. Header"); + exit(EXIT_FAILURE); + } + + *prev_nh = IPPROTO_HOPOPTS; + prev_nh = ptr; + memcpy(ptr, hbhopthdr[hbhopthdrs], hbhopthdrlen[hbhopthdrs]); + ptr = ptr + hbhopthdrlen[hbhopthdrs]; + hbhopthdrs++; + } + } + + if (dstoptuhdr_f) { + dstoptuhdrs = 0; + + while (dstoptuhdrs < ndstoptuhdr) { + if ((ptr + dstoptuhdrlen[dstoptuhdrs]) > (v6buffer + idata->mtu)) { + puts("Packet too large while processing Dest. Opt. Header (Unfrag. Part)"); + exit(EXIT_FAILURE); + } + + *prev_nh = IPPROTO_DSTOPTS; + prev_nh = ptr; + memcpy(ptr, dstoptuhdr[dstoptuhdrs], dstoptuhdrlen[dstoptuhdrs]); + ptr = ptr + dstoptuhdrlen[dstoptuhdrs]; + dstoptuhdrs++; + } + } + + /* Everything that follows is the Fragmentable Part of the packet */ + fragpart = ptr; + + if (idata->fragh_f) { + /* Check that we are able to send the Unfragmentable Part, together with a + Fragment Header and a chunk data over our link layer + */ + if ((fragpart + sizeof(fraghdr) + nfrags) > (v6buffer + idata->mtu)) { + puts("Unfragmentable part too large for current MTU"); + exit(EXIT_FAILURE); + } + + /* We prepare a separete Fragment Header, but we do not include it in the packet to be sent. + This Fragment Header will be used (an assembled with the rest of the packet by the + send_packet() function. + */ + memset(&fraghdr, 0, FRAG_HDR_SIZE); + *prev_nh = IPPROTO_FRAGMENT; + prev_nh = (unsigned char *)&fraghdr; + } + + if (dstopthdr_f) { + dstopthdrs = 0; + + while (dstopthdrs < ndstopthdr) { + if ((ptr + dstopthdrlen[dstopthdrs]) > (v6buffer + idata->max_packet_size)) { + puts("Packet too large while processing Dest. Opt. Header (should be using the Frag. option?)"); + exit(EXIT_FAILURE); + } + + *prev_nh = IPPROTO_DSTOPTS; + prev_nh = ptr; + memcpy(ptr, dstopthdr[dstopthdrs], dstopthdrlen[dstopthdrs]); + ptr = ptr + dstopthdrlen[dstopthdrs]; + dstopthdrs++; + } + } + + *prev_nh = IPPROTO_TCP; + + startofprefixes = ptr; } - /* * Function: print_port_entries() * * Print port entries */ -void print_port_entries(struct port_list *port_list){ - int i; - - for(i=0; i< port_list->nport; i++){ - if((port_list->port[i])->start == (port_list->port[i])->end){ - printf("%u;", (port_list->port[i])->start); - } - else{ - printf("%u-%u;", (port_list->port[i])->start, (port_list->port[i])->end); - } - } +void print_port_entries(struct port_list *port_list) { + int i; + + for (i = 0; i < port_list->nport; i++) { + if ((port_list->port[i])->start == (port_list->port[i])->end) { + printf("%u;", (port_list->port[i])->start); + } + else { + printf("%u-%u;", (port_list->port[i])->start, (port_list->port[i])->end); + } + } } - - - - /* * Function: add_to_scan_list() * * Check whether an IPv6 address belongs to one of our scan ranges */ -int add_to_scan_list(struct scan_list *scan_list, struct scan_entry *new_entry){ +int add_to_scan_list(struct scan_list *scan_list, struct scan_entry *new_entry) { - if(scan_list->ntarget >= scan_list->maxtarget){ - return(FALSE); - } + if (scan_list->ntarget >= scan_list->maxtarget) { + return (FALSE); + } + /* Do not add this entry if it is a duplicate */ + if (is_scan_entry_duplicate(scan_list, new_entry)) { + return (TRUE); + } - /* Do not add this entry if it is a duplicate */ - if(is_scan_entry_duplicate(scan_list, new_entry)){ - return(TRUE); - } + if ((scan_list->target[scan_list->ntarget] = malloc(sizeof(struct scan_entry))) == NULL) { + if (verbose_f > 1) + puts("scan6: Not enough memory"); - if( (scan_list->target[scan_list->ntarget] = malloc(sizeof(struct scan_entry))) == NULL){ - if(verbose_f > 1) - puts("scan6: Not enough memory"); + return (FALSE); + } - return(FALSE); - } - - *(scan_list->target[scan_list->ntarget]) = *new_entry; - (scan_list->ntarget)++; - return(TRUE); + *(scan_list->target[scan_list->ntarget]) = *new_entry; + (scan_list->ntarget)++; + return (TRUE); } - - /* * Function: is_scan_entry_duplicate() * * Compares two IPv6 addresses */ -int is_scan_entry_duplicate(struct scan_list *scan_list, struct scan_entry *scan_entry){ - unsigned int i, j; +int is_scan_entry_duplicate(struct scan_list *scan_list, struct scan_entry *scan_entry) { + unsigned int i, j; - for(i=0; i < scan_list->ntarget; i++){ - for(j=0; j<8; j++){ - if( ntohs(scan_entry->start.in6_addr.s6_addr16[j]) < ntohs((scan_list->target[i])->start.in6_addr.s6_addr16[j]) || - ntohs(scan_entry->end.in6_addr.s6_addr16[j]) > ntohs((scan_list->target[i])->end.in6_addr.s6_addr16[j])){ - break; - } - } + for (i = 0; i < scan_list->ntarget; i++) { + for (j = 0; j < 8; j++) { + if (ntohs(scan_entry->start.in6_addr.s6_addr16[j]) < + ntohs((scan_list->target[i])->start.in6_addr.s6_addr16[j]) || + ntohs(scan_entry->end.in6_addr.s6_addr16[j]) > + ntohs((scan_list->target[i])->end.in6_addr.s6_addr16[j])) { + break; + } + } - if(j >= 8) - return(TRUE); - } + if (j >= 8) + return (TRUE); + } - return(FALSE); + return (FALSE); } - - diff --git a/tools/scan6.h b/tools/scan6.h index aca13e9..e00672d 100644 --- a/tools/scan6.h +++ b/tools/scan6.h @@ -3,156 +3,142 @@ * */ -#define BUFFER_SIZE 65556 +#define BUFFER_SIZE 65556 /* Constants used with the multi_scan_local() function */ -#define PROBE_ICMP6_ECHO 1 -#define PROBE_UNREC_OPT 2 -#define PROBE_TCP 3 -#define LOCAL_SRC 1 -#define GLOBAL_SRC 2 +#define PROBE_ICMP6_ECHO 1 +#define PROBE_UNREC_OPT 2 +#define PROBE_TCP 3 +#define LOCAL_SRC 1 +#define GLOBAL_SRC 2 -#define ICMPV6_ECHO_PAYLOAD_SIZE 56 -#define MAX_IPV6_ENTRIES 65000 +#define ICMPV6_ECHO_PAYLOAD_SIZE 56 +#define MAX_IPV6_ENTRIES 65000 /* Constant for the host-scanning functions */ -#define PRINT_ETHER_ADDR 1 -#define NOT_PRINT_ETHER_ADDR 0 - -#define VALID_MAPPING 1 -#define INVALID_MAPPING 0 +#define PRINT_ETHER_ADDR 1 +#define NOT_PRINT_ETHER_ADDR 0 +#define VALID_MAPPING 1 +#define INVALID_MAPPING 0 /* Remote scans */ -#define LOW_BYTE_1ST_WORD_UPPER 0x1500 -#define LOW_BYTE_2ND_WORD_UPPER 0x0100 -#define EMBEDDED_PORT_2ND_WORD 5 -#define MAX_IEEE_OUIS_LINE_SIZE 160 -#define OUI_HEX_STRING_SIZE 5 -#define MAX_IEEE_OUIS 1000 -#define MAX_SCAN_ENTRIES 65535 -#define MAX_PORT_ENTRIES 65536 -#define MAX_PREF_ENTRIES MAX_SCAN_ENTRIES -#define SELECT_TIMEOUT 4 -#define PSCAN_TIMEOUT 1 -#define MAX_RANGE_STR_LEN 79 -#define MIN_INC_RANGE 1000 +#define LOW_BYTE_1ST_WORD_UPPER 0x1500 +#define LOW_BYTE_2ND_WORD_UPPER 0x0100 +#define EMBEDDED_PORT_2ND_WORD 5 +#define MAX_IEEE_OUIS_LINE_SIZE 160 +#define OUI_HEX_STRING_SIZE 5 +#define MAX_IEEE_OUIS 1000 +#define MAX_SCAN_ENTRIES 65535 +#define MAX_PORT_ENTRIES 65536 +#define MAX_PREF_ENTRIES MAX_SCAN_ENTRIES +#define SELECT_TIMEOUT 4 +#define PSCAN_TIMEOUT 1 +#define MAX_RANGE_STR_LEN 79 +#define MIN_INC_RANGE 1000 /* #define MAX_DESTNATIONS 65535 */ -#define MAX_IID_ENTRIES 65535 +#define MAX_IID_ENTRIES 65535 -#define ND_RETRIES 0 +#define ND_RETRIES 0 /* Constants for config file processing */ -#define MAX_LINE_SIZE 250 -#define MAX_VAR_NAME_LEN 100 -#define MAX_FILENAME_SIZE 250 - - -union my6_addr{ - uint8_t s6addr[16]; - uint16_t s6addr16[8]; - uint32_t s6addr32[4]; - struct in6_addr in6_addr; +#define MAX_LINE_SIZE 250 +#define MAX_VAR_NAME_LEN 100 +#define MAX_FILENAME_SIZE 250 + +union my6_addr { + uint8_t s6addr[16]; + uint16_t s6addr16[8]; + uint32_t s6addr32[4]; + struct in6_addr in6_addr; }; - /* Stores one remote target to scan */ -struct scan_entry{ - union my6_addr start; - union my6_addr end; - union my6_addr cur; +struct scan_entry { + union my6_addr start; + union my6_addr end; + union my6_addr cur; }; - /* Store the list of remote targets to scan */ -struct scan_list{ - struct scan_entry **target; - unsigned int ctarget; - unsigned int ntarget; /* Number of existing enties */ - unsigned int maxtarget; /* Max enties */ - unsigned int inc; /* Increment size */ +struct scan_list { + struct scan_entry **target; + unsigned int ctarget; + unsigned int ntarget; /* Number of existing enties */ + unsigned int maxtarget; /* Max enties */ + unsigned int inc; /* Increment size */ }; - -#define MAX_PORTS_LINE_SIZE 80 +#define MAX_PORTS_LINE_SIZE 80 /* Stores one port entry to scan */ -struct port_entry{ - uint16_t start; - uint16_t end; - uint16_t cur; +struct port_entry { + uint16_t start; + uint16_t end; + uint16_t cur; }; /* Store the list of remote targets to scan */ -struct port_list{ - struct port_entry **port; - unsigned int cport; - unsigned int nport; - unsigned int maxport; - unsigned int proto; - struct port_table_entry *port_table; +struct port_list { + struct port_entry **port; + unsigned int cport; + unsigned int nport; + unsigned int maxport; + unsigned int proto; + struct port_table_entry *port_table; }; - /* Store the list of remote targets to scan */ -struct port_table_entry{ - unsigned int loaded; - char name[MAX_PORTS_LINE_SIZE]; +struct port_table_entry { + unsigned int loaded; + char name[MAX_PORTS_LINE_SIZE]; }; - - /* Constants for port scan results */ -#define PORT_FILTERED 1 -#define PORT_OPEN 2 -#define PORT_CLOSED 4 -#define PORT_ACT_FILT 8 - +#define PORT_FILTERED 1 +#define PORT_OPEN 2 +#define PORT_CLOSED 4 +#define PORT_ACT_FILT 8 -#define DEFAULT_MIN_PORT 0 -#define DEFAULT_MAX_PORT 65535 -#define MAX_PORT_RANGE 65536 -#define IPPROTO_ALL 0xf1 /* Fake number to indicate both TCP and UDP */ +#define DEFAULT_MIN_PORT 0 +#define DEFAULT_MAX_PORT 65535 +#define MAX_PORT_RANGE 65536 +#define IPPROTO_ALL 0xf1 /* Fake number to indicate both TCP and UDP */ /* Constants for printing the scanning results */ /* Steps into which results will be printed */ -#define MAX_STEPS 20 - - -struct print_scan_entry{ - struct timeval start; - unsigned int nscan_entry; - struct in6_addr addrstart; - unsigned int nport_entry; - uint16_t portstart; +#define MAX_STEPS 20 + +struct print_scan_entry { + struct timeval start; + unsigned int nscan_entry; + struct in6_addr addrstart; + unsigned int nport_entry; + uint16_t portstart; }; -struct print_scans_list{ - struct print_scan_entry print_scan_entry[MAX_STEPS]; -/* unsigned int max=MAX_STEPS; */ - unsigned int fullq; /* Flag to indicate that the cirdular list is full */ - unsigned int in; /* Next entry to write */ - unsigned int out; /* Next entry to read */ - unsigned int donesending; +struct print_scans_list { + struct print_scan_entry print_scan_entry[MAX_STEPS]; + /* unsigned int max=MAX_STEPS; */ + unsigned int fullq; /* Flag to indicate that the cirdular list is full */ + unsigned int in; /* Next entry to write */ + unsigned int out; /* Next entry to read */ + unsigned int donesending; }; - -struct hashed_host_entry{ - struct in6_addr ip6; - unsigned int tcp_results[MAX_PORT_RANGE]; - struct hashed_host_entry *next; - struct hashed_host_entry *prev; +struct hashed_host_entry { + struct in6_addr ip6; + unsigned int tcp_results[MAX_PORT_RANGE]; + struct hashed_host_entry *next; + struct hashed_host_entry *prev; }; -struct hashed_host_list{ - struct hashed_host_entry **host; /* Double-linked list of host entries */ - unsigned int nhosts; /* Current number of host entries */ - unsigned int maxhosts; /* Maximum number of host entries */ - uint16_t key_l; /* Low-order word of the hash key */ - uint16_t key_h; /* High-order word of the hash key */ +struct hashed_host_list { + struct hashed_host_entry **host; /* Double-linked list of host entries */ + unsigned int nhosts; /* Current number of host entries */ + unsigned int maxhosts; /* Maximum number of host entries */ + uint16_t key_l; /* Low-order word of the hash key */ + uint16_t key_h; /* High-order word of the hash key */ }; - - - diff --git a/tools/tcp6.c b/tools/tcp6.c index fffb06d..a001684 100644 --- a/tools/tcp6.c +++ b/tools/tcp6.c @@ -18,2619 +18,2599 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . - * + * * Build with: make tcp6 - * + * * It requires that the libpcap library be installed on your system. * * Please send any bug reports to Fernando Gont */ -#include -#include #include #include +#include +#include +#include #include +#include #include #include -#include -#include -#include -#include -#include #include -#include #include #include -#include +#include +#include +#include #include +#include +#include #include -#include -#include +#include +#include -#include "tcp6.h" #include "ipv6toolkit.h" #include "libipv6.h" - +#include "tcp6.h" /* Function prototypes */ -void init_packet_data(struct iface_data *); -void send_packet(struct iface_data *, const u_char *, struct pcap_pkthdr *); -void print_attack_info(struct iface_data *); -void usage(void); -void print_help(void); -void frag_and_send(struct iface_data *); -unsigned int queue_data(struct tcp_queue *, unsigned char *, unsigned int); -unsigned int dequeue_data(struct tcp_queue *, unsigned char *, unsigned int); -unsigned int queue_copy(struct tcp_queue *, unsigned char *, unsigned int, unsigned char *, unsigned int); -unsigned int queue_remove(struct tcp_queue *, unsigned char *, unsigned int); -void queue_purge( struct tcp_queue *); -int tcp_init(struct tcp *); -int tcp_open(struct iface_data *, struct tcp *, unsigned int); -int tcp_close(struct iface_data *, struct tcp *); -int tcp_send(struct iface_data *, struct tcp *, unsigned char *, unsigned int); -int tcp_receive(struct iface_data *, struct tcp *, unsigned char *, unsigned int); -int tcp_input(struct iface_data *, struct tcp *, const u_char *, struct pcap_pkthdr *, struct packet *); -int tcp_output(struct iface_data *, struct tcp *, struct packet *, struct timeval *); -int is_valid_tcp_segment(struct iface_data *, const u_char *, struct pcap_pkthdr *); +void init_packet_data(struct iface_data *); +void send_packet(struct iface_data *, const u_char *, struct pcap_pkthdr *); +void print_attack_info(struct iface_data *); +void usage(void); +void print_help(void); +void frag_and_send(struct iface_data *); +unsigned int queue_data(struct tcp_queue *, unsigned char *, unsigned int); +unsigned int dequeue_data(struct tcp_queue *, unsigned char *, unsigned int); +unsigned int queue_copy(struct tcp_queue *, unsigned char *, unsigned int, unsigned char *, unsigned int); +unsigned int queue_remove(struct tcp_queue *, unsigned char *, unsigned int); +void queue_purge(struct tcp_queue *); +int tcp_init(struct tcp *); +int tcp_open(struct iface_data *, struct tcp *, unsigned int); +int tcp_close(struct iface_data *, struct tcp *); +int tcp_send(struct iface_data *, struct tcp *, unsigned char *, unsigned int); +int tcp_receive(struct iface_data *, struct tcp *, unsigned char *, unsigned int); +int tcp_input(struct iface_data *, struct tcp *, const u_char *, struct pcap_pkthdr *, struct packet *); +int tcp_output(struct iface_data *, struct tcp *, struct packet *, struct timeval *); +int is_valid_tcp_segment(struct iface_data *, const u_char *, struct pcap_pkthdr *); /* Flags */ -unsigned char floodt_f=0; -unsigned char listen_f=0, accepted_f=0, loop_f=0, sleep_f=0; -unsigned char hoplimit_f=0, rand_link_src_f=0, rand_src_f=0; -unsigned char floods_f=0, floodp_f=0, donesending_f=0, startclose_f=0; -unsigned char data_f=0, senddata_f=0, useaddrkey_f=0, window_f=0, winmodulate_f=0; - -/* Flags used for TCP (specifically) */ -unsigned char srcport_f=0, dstport_f=0, srcportrnd_f=0, dstportrnd_f=0; -unsigned char tcpseq_f=0, tcpack_f=0, tcpurg_f=0, tcpflags_f=0, tcpwin_f=0; -unsigned char rhbytes_f=0, tcpflags_auto_f=0, tcpopen_f=0, tcpclose_f=0; -unsigned char pps_f=0, bps_f=0, probemode_f=0, retrans_f=0, rto_f=0; -unsigned char ackdata_f=1, ackflags_f=1; -unsigned int probemode, tcpopen=0, tcpclose=0, win1_size=0, win2_size=0, window=0, time1_len=0, time2_len=0; - -uint16_t srcport, dstport, pport, tcpurg, tcpwin, tcpwinm; -uint8_t srcportpref, dstportpref; -unsigned int retrans, rto; -uint32_t tcpseq=0, tcpack=0; -uint8_t tcpflags=0, pkt_tcp_flags; -struct tcp_hdr *rhtcp; -unsigned int rhbytes, currentsize, packetsize; - +unsigned char floodt_f = 0; +unsigned char listen_f = 0, accepted_f = 0, loop_f = 0, sleep_f = 0; +unsigned char hoplimit_f = 0, rand_link_src_f = 0, rand_src_f = 0; +unsigned char floods_f = 0, floodp_f = 0, donesending_f = 0, startclose_f = 0; +unsigned char data_f = 0, senddata_f = 0, useaddrkey_f = 0, window_f = 0, winmodulate_f = 0; + +/* Flags used for TCP (specifically) */ +unsigned char srcport_f = 0, dstport_f = 0, srcportrnd_f = 0, dstportrnd_f = 0; +unsigned char tcpseq_f = 0, tcpack_f = 0, tcpurg_f = 0, tcpflags_f = 0, tcpwin_f = 0; +unsigned char rhbytes_f = 0, tcpflags_auto_f = 0, tcpopen_f = 0, tcpclose_f = 0; +unsigned char pps_f = 0, bps_f = 0, probemode_f = 0, retrans_f = 0, rto_f = 0; +unsigned char ackdata_f = 1, ackflags_f = 1; +unsigned int probemode, tcpopen = 0, tcpclose = 0, win1_size = 0, win2_size = 0, window = 0, time1_len = 0, + time2_len = 0; + +uint16_t srcport, dstport, pport, tcpurg, tcpwin, tcpwinm; +uint8_t srcportpref, dstportpref; +unsigned int retrans, rto; +uint32_t tcpseq = 0, tcpack = 0; +uint8_t tcpflags = 0, pkt_tcp_flags; +struct tcp_hdr *rhtcp; +unsigned int rhbytes, currentsize, packetsize; /* Used for router discovery */ -struct iface_data idata; +struct iface_data idata; /* Data structures for packets read from the wire */ -struct pcap_pkthdr *pkthdr; -const u_char *pktdata; -unsigned char *pkt_end; -struct ether_header *pkt_ether; -struct nd_neighbor_solicit *pkt_ns; -struct ip6_hdr *pkt_ipv6; -struct tcp_hdr *pkt_tcp; -struct in6_addr *pkt_ipv6addr; -unsigned int pktbytes; - - -bpf_u_int32 my_netmask; -bpf_u_int32 my_ip; -struct bpf_program pcap_filter; -char dev[64], errbuf[PCAP_ERRBUF_SIZE]; -unsigned char buffer[65556], buffrh[MIN_IPV6_HLEN + MIN_TCP_HLEN]; -unsigned char *v6buffer, *ptr, *startofprefixes; -char *pref; -char data[DATA_BUFFER_LEN]; -unsigned int datalen; -char iface[IFACE_LENGTH]; -char line[LINE_BUFFER_SIZE]; - -struct ip6_hdr *ipv6; -struct tcp_hdr *tcp; - -struct ether_header *ethernet; -struct nd_opt_tlla *tllaopt; - -struct in6_addr targetaddr, randprefix; -struct ether_addr linkaddr[MAX_TLLA_OPTION]; -unsigned int nlinkaddr=0, linkaddrs; - -char *lasts, *rpref; -char *charptr; - -int nw; -unsigned long ul_res, ul_val, rate; -unsigned int i, j, startrand; -unsigned int skip; -unsigned int sources, nsources, ports, nports, nsleep; -unsigned char randpreflen; - -uint16_t mask; -uint8_t hoplimit; -uint16_t addr_key; - -char plinkaddr[ETHER_ADDR_PLEN]; -char psrcaddr[INET6_ADDRSTRLEN], pdstaddr[INET6_ADDRSTRLEN], pv6addr[INET6_ADDRSTRLEN]; - +struct pcap_pkthdr *pkthdr; +const u_char *pktdata; +unsigned char *pkt_end; +struct ether_header *pkt_ether; +struct nd_neighbor_solicit *pkt_ns; +struct ip6_hdr *pkt_ipv6; +struct tcp_hdr *pkt_tcp; +struct in6_addr *pkt_ipv6addr; +unsigned int pktbytes; + +bpf_u_int32 my_netmask; +bpf_u_int32 my_ip; +struct bpf_program pcap_filter; +char dev[64], errbuf[PCAP_ERRBUF_SIZE]; +unsigned char buffer[65556], buffrh[MIN_IPV6_HLEN + MIN_TCP_HLEN]; +unsigned char *v6buffer, *ptr, *startofprefixes; +char *pref; +char data[DATA_BUFFER_LEN]; +unsigned int datalen; +char iface[IFACE_LENGTH]; +char line[LINE_BUFFER_SIZE]; + +struct ip6_hdr *ipv6; +struct tcp_hdr *tcp; + +struct ether_header *ethernet; +struct nd_opt_tlla *tllaopt; + +struct in6_addr targetaddr, randprefix; +struct ether_addr linkaddr[MAX_TLLA_OPTION]; +unsigned int nlinkaddr = 0, linkaddrs; + +char *lasts, *rpref; +char *charptr; + +int nw; +unsigned long ul_res, ul_val, rate; +unsigned int i, j, startrand; +unsigned int skip; +unsigned int sources, nsources, ports, nports, nsleep; +unsigned char randpreflen; + +uint16_t mask; +uint8_t hoplimit; +uint16_t addr_key; + +char plinkaddr[ETHER_ADDR_PLEN]; +char psrcaddr[INET6_ADDRSTRLEN], pdstaddr[INET6_ADDRSTRLEN], pv6addr[INET6_ADDRSTRLEN]; /* Support for Extension Headers */ -unsigned int dstopthdrs, dstoptuhdrs, hbhopthdrs; -char hbhopthdr_f=0, dstoptuhdr_f=0, dstopthdr_f=0; -unsigned char *dstopthdr[MAX_DST_OPT_HDR], *dstoptuhdr[MAX_DST_OPT_U_HDR]; -unsigned char *hbhopthdr[MAX_HBH_OPT_HDR]; -unsigned int dstopthdrlen[MAX_DST_OPT_HDR], dstoptuhdrlen[MAX_DST_OPT_U_HDR]; -unsigned int hbhopthdrlen[MAX_HBH_OPT_HDR], m, pad; - -struct ip6_frag fraghdr, *fh; -struct ip6_hdr *fipv6; - -unsigned char fragbuffer[ETHER_HDR_LEN+MIN_IPV6_HLEN+MAX_IPV6_PAYLOAD]; -unsigned char *fragpart, *fptr, *fptrend, *ptrend, *ptrhdr, *ptrhdrend; -unsigned int hdrlen, ndstopthdr=0, nhbhopthdr=0, ndstoptuhdr=0; -unsigned int nfrags, fragsize; -unsigned char *prev_nh, *startoffragment; - -struct filters filters; - -int main(int argc, char **argv){ - extern char *optarg; - char *endptr; /* Used by strtoul() */ - fd_set sset, rset; -/* fd_set wset, eset; */ - int r, sel; - struct timeval timeout, stimeout, curtime, lastprobe, wmtimeout; - /*struct tcp tcb; */ - /* unsigned char end_f=0, error_f; */ - unsigned char end_f=0; - unsigned long pktinterval=0; /*Add datasent=0*/ - unsigned int retr=0; - struct target_ipv6 targetipv6; - - static struct option longopts[] = { - {"interface", required_argument, 0, 'i'}, - {"src-addr", required_argument, 0, 's'}, - {"dst-addr", required_argument, 0, 'd'}, - {"hop-limit", required_argument, 0, 'A'}, - {"open-mode", required_argument, 0, 'c'}, - {"close-mode", required_argument, 0, 'C'}, - {"data", required_argument, 0, 'Z'}, - {"dst-opt-hdr", required_argument, 0, 'u'}, - {"dst-opt-u-hdr", required_argument, 0, 'U'}, - {"hbh-opt-hdr", required_argument, 0, 'H'}, - {"frag-hdr", required_argument, 0, 'y'}, - {"link-src-addr", required_argument, 0, 'S'}, - {"link-dst-addr", required_argument, 0, 'D'}, - {"payload-size", required_argument, 0, 'P'}, - {"src-port", required_argument, 0, 'o'}, - {"dst-port", required_argument, 0, 'a'}, - {"tcp-flags", required_argument, 0, 'X'}, - {"tcp-seq", required_argument, 0, 'q'}, - {"tcp-ack", required_argument, 0, 'Q'}, - {"tcp-urg", required_argument, 0, 'V'}, - {"tcp-win", required_argument, 0, 'w'}, - {"window-mode", required_argument, 0, 'W'}, - {"win-modulation", required_argument, 0, 'M'}, - {"not-ack-data", no_argument, 0, 'N'}, - {"not-ack-flags", no_argument, 0, 'n'}, - {"block-src-addr", required_argument, 0, 'j'}, - {"block-dst-addr", required_argument, 0, 'k'}, - {"block-link-src-addr", required_argument, 0, 'J'}, - {"block-link-dst-addr", required_argument, 0, 'K'}, - {"accept-src-addr", required_argument, 0, 'b'}, - {"accept-dst-addr", required_argument, 0, 'g'}, - {"accept-link-src-addr", required_argument, 0, 'B'}, - {"accept-link-dst-addr", required_argument, 0, 'G'}, - {"flood-sources", required_argument, 0, 'F'}, - {"flood-ports", required_argument, 0, 'T'}, - {"loop", no_argument, 0, 'l'}, - {"rate-limit", required_argument, 0, 'r'}, - {"sleep", required_argument, 0, 'z'}, - {"listen", no_argument, 0, 'L'}, - {"probe-mode", required_argument, 0, 'p'}, - {"retrans", required_argument, 0, 'x'}, - {"verbose", no_argument, 0, 'v'}, - {"help", no_argument, 0, 'h'}, - {0, 0, 0, 0 } - }; - - const char shortopts[]= "i:s:d:A:c:C:Z:u:U:H:y:S:D:P:o:a:X:q:Q:V:w:W:M:Nnj:k:J:K:b:g:B:G:F:T:lr:z:Lp:x:vh"; - - char option; - - if(argc<=1){ - usage(); - exit(EXIT_FAILURE); - } - - hoplimit=255; - - lastprobe.tv_sec= 0; - lastprobe.tv_usec= 0; - - /* Initialize filters structure */ - if(init_filters(&filters) == -1){ - puts("Error initializing internal data structure"); - exit(EXIT_FAILURE); - } - - if(init_iface_data(&idata) == FAILURE){ - puts("Error initializing internal data structure"); - exit(EXIT_FAILURE); - } - - while((r=getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { - option= r; - - switch(option){ - case 'i': /* Interface */ - strncpy(idata.iface, optarg, IFACE_LENGTH); - idata.iface[IFACE_LENGTH-1]=0; - idata.ifindex= if_nametoindex(idata.iface); - idata.iface_f=TRUE; - break; - - case 's': /* IPv6 Source Address */ - if(idata.srcaddr_f){ - puts("Error: Multiple '-s' options have been specified"); - exit(EXIT_FAILURE); - } - - if((charptr = strtok_r(optarg, "/", &lasts)) == NULL){ - puts("Error in Source Address"); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, charptr, &(idata.srcaddr)) <= 0){ - puts("inet_pton(): Source Address not valid"); - exit(EXIT_FAILURE); - } - - idata.srcaddr_f = 1; - - if((charptr = strtok_r(NULL, " ", &lasts)) != NULL){ - idata.srcpreflen = atoi(charptr); - - if(idata.srcpreflen>128){ - puts("Prefix length error in IPv6 Source Address"); - exit(EXIT_FAILURE); - } - - if(idata.srcpreflen == 64) - useaddrkey_f= 1; - - sanitize_ipv6_prefix(&(idata.srcaddr), idata.srcpreflen); - idata.srcprefix_f=1; - } - - break; - - case 'd': /* IPv6 Destination Address */ - strncpy( targetipv6.name, optarg, NI_MAXHOST); - targetipv6.name[NI_MAXHOST-1]= 0; - targetipv6.flags= AI_CANONNAME; - - if( (r=get_ipv6_target(&targetipv6)) != 0){ - - if(r < 0){ - printf("Unknown Destination: %s\n", gai_strerror(targetipv6.res)); - } - else{ - puts("Unknown Destination: No IPv6 address found for specified destination"); - } - - exit(EXIT_FAILURE); - } - - idata.dstaddr= targetipv6.ip6; - idata.dstaddr_f = 1; - break; - - case 'A': /* Hop Limit */ - hoplimit= atoi(optarg); - hoplimit_f=1; - break; - - case 'c': - if(strncmp(optarg, "simultaneous", MAX_CMDLINE_OPT_LEN) == 0){ - tcpopen= OPEN_SIMULTANEOUS; - } - else if(strncmp(optarg, "passive", MAX_CMDLINE_OPT_LEN) == 0){ - tcpopen= OPEN_PASSIVE; - } - else if(strncmp(optarg, "abort", MAX_CMDLINE_OPT_LEN) == 0){ - tcpopen= OPEN_ABORT; - } - else if(strncmp(optarg, "active", MAX_CMDLINE_OPT_LEN) == 0){ - tcpopen= OPEN_ACTIVE; - } - else{ - puts("Error: Unknown open mode in '-c' option"); - exit(EXIT_FAILURE); - } - - tcpopen_f=1; - break; - - case 'C': - if(strncmp(optarg, "simultaneous", MAX_CMDLINE_OPT_LEN) == 0){ - tcpclose= CLOSE_SIMULTANEOUS; - } - else if(strncmp(optarg, "passive", MAX_CMDLINE_OPT_LEN) == 0){ - tcpclose= CLOSE_PASSIVE; - } - else if(strncmp(optarg, "abort", MAX_CMDLINE_OPT_LEN) == 0){ - tcpclose= CLOSE_ABORT; - } - else if(strncmp(optarg, "active", MAX_CMDLINE_OPT_LEN) == 0){ - tcpclose= CLOSE_ACTIVE; - } - else if( strncmp(optarg, "fin-wait-1", MAX_CMDLINE_OPT_LEN) == 0 || \ - strncmp(optarg, "FIN-WAIT-1", MAX_CMDLINE_OPT_LEN) == 0){ - tcpclose= CLOSE_FIN_WAIT_1; - } - else if( strncmp(optarg, "fin-wait-2", MAX_CMDLINE_OPT_LEN) == 0 || \ - strncmp(optarg, "FIN-WAIT-2", MAX_CMDLINE_OPT_LEN) == 0){ - tcpclose= CLOSE_FIN_WAIT_2; - } - else if( strncmp(optarg, "last-ack", MAX_CMDLINE_OPT_LEN) == 0 || \ - strncmp(optarg, "LAST-ACK", MAX_CMDLINE_OPT_LEN) == 0){ - tcpclose= CLOSE_LAST_ACK; - } - else{ - puts("Error: Unknown close option ('-C')"); - exit(EXIT_FAILURE); - } - - tcpclose_f=1; - break; - - case 'Z': /* Data */ - datalen= Strnlen(optarg, MAX_CMDLINE_OPT_LEN); - - if(datalen >= DATA_BUFFER_LEN) - datalen= DATA_BUFFER_LEN-1; - - strncpy(data, optarg, DATA_BUFFER_LEN-1); - data_f=1; - break; - - case 'u': /* Destinations Options Header */ - if(ndstopthdr >= MAX_DST_OPT_HDR){ - puts("Too many Destination Options Headers"); - exit(EXIT_FAILURE); - } - - hdrlen= atoi(optarg); - - if(hdrlen < 8){ - puts("Bad length in Destination Options Header"); - exit(EXIT_FAILURE); - } - - hdrlen = ((hdrlen+7)/8) * 8; - dstopthdrlen[ndstopthdr]= hdrlen; - - if( (dstopthdr[ndstopthdr]= malloc(hdrlen)) == NULL){ - puts("Not enough memory for Destination Options Header"); - exit(EXIT_FAILURE); - } - - ptrhdr= dstopthdr[ndstopthdr] + 2; - ptrhdrend= dstopthdr[ndstopthdr] + hdrlen; - - while( ptrhdr < ptrhdrend){ - - if( (ptrhdrend-ptrhdr)>257) - pad= 257; - else - pad= ptrhdrend-ptrhdr; - - if(!insert_pad_opt(ptrhdr, ptrhdrend, pad)){ - puts("Destination Options Header Too Big"); - exit(EXIT_FAILURE); - } - - ptrhdr= ptrhdr + pad; - } - - *(dstopthdr[ndstopthdr]+1)= (hdrlen/8)-1; - ndstopthdr++; - dstopthdr_f=1; - break; - - case 'U': /* Destination Options Header (Unfragmentable Part) */ - if(ndstoptuhdr >= MAX_DST_OPT_U_HDR){ - puts("Too many Destination Options Headers (Unfragmentable Part)"); - exit(EXIT_FAILURE); - } - - hdrlen= atoi(optarg); - - if(hdrlen < 8){ - puts("Bad length in Destination Options Header (Unfragmentable Part)"); - exit(EXIT_FAILURE); - } - - hdrlen = ((hdrlen+7)/8) * 8; - dstoptuhdrlen[ndstoptuhdr]= hdrlen; - - if( (dstoptuhdr[ndstoptuhdr]= malloc(hdrlen)) == NULL){ - puts("Not enough memory for Destination Options Header (Unfragmentable Part)"); - exit(EXIT_FAILURE); - } - - ptrhdr= dstoptuhdr[ndstoptuhdr]+2; - ptrhdrend= dstoptuhdr[ndstoptuhdr] + hdrlen; - - while( ptrhdr < ptrhdrend){ - - if( (ptrhdrend-ptrhdr)>257) - pad= 257; - else - pad= ptrhdrend-ptrhdr; - - if(!insert_pad_opt(ptrhdr, ptrhdrend, pad)){ - puts("Destination Options Header (Unfragmentable Part) Too Big"); - exit(EXIT_FAILURE); - } - - ptrhdr = ptrhdr + pad; - } - - *(dstoptuhdr[ndstoptuhdr]+1)= (hdrlen/8) - 1; - ndstoptuhdr++; - dstoptuhdr_f=1; - break; - - case 'H': /* Hop-by-Hop Options Header */ - if(nhbhopthdr >= MAX_HBH_OPT_HDR){ - puts("Too many Hop-by-Hop Options Headers"); - exit(EXIT_FAILURE); - } - - hdrlen= atoi(optarg); - - if(hdrlen < 8){ - puts("Bad length in Hop-by-Hop Options Header"); - exit(EXIT_FAILURE); - } - - hdrlen = ((hdrlen+7)/8) * 8; - hbhopthdrlen[nhbhopthdr]= hdrlen; - - if( (hbhopthdr[nhbhopthdr]= malloc(hdrlen)) == NULL){ - puts("Not enough memory for Hop-by-Hop Options Header"); - exit(EXIT_FAILURE); - } - - ptrhdr= hbhopthdr[nhbhopthdr] + 2; - ptrhdrend= hbhopthdr[nhbhopthdr] + hdrlen; - - - while( ptrhdr < ptrhdrend){ - - if( (ptrhdrend-ptrhdr)>257) - pad= 257; - else - pad= ptrhdrend-ptrhdr; - - if(!insert_pad_opt(ptrhdr, ptrhdrend, pad)){ - puts("Hop-by-Hop Options Header Too Big"); - exit(EXIT_FAILURE); - } - - ptrhdr = ptrhdr + pad; - } - - *(hbhopthdr[nhbhopthdr]+1)= (hdrlen/8) - 1; - nhbhopthdr++; - hbhopthdr_f=1; - break; - - case 'y': /* Fragment header */ - nfrags= atoi(optarg); - if(nfrags < 8){ - puts("Error in Fragmentation option: Fragment Size must be at least 8 bytes"); - exit(EXIT_FAILURE); - } - - idata.fragh_f= 1; - break; - - case 'S': /* Source Ethernet address */ - if(ether_pton(optarg, &(idata.hsrcaddr), sizeof(idata.hsrcaddr)) == 0){ - puts("Error in Source link-layer address."); - exit(EXIT_FAILURE); - } - - idata.hsrcaddr_f = 1; - break; - - case 'D': /* Destination Ethernet Address */ - if(ether_pton(optarg, &(idata.hdstaddr), sizeof(idata.hdstaddr)) == 0){ - puts("Error in Source link-layer address."); - exit(EXIT_FAILURE); - } - - idata.hdstaddr_f = 1; - break; - - case 'P': /* Payload Size*/ - rhbytes= atoi(optarg); - rhbytes_f= 1; - break; - - case 'o': /* TCP Source Port */ - if((charptr = strtok_r(optarg, "/", &lasts)) == NULL){ - puts("Error in TCP Source Port"); - exit(EXIT_FAILURE); - } - - srcport= atoi(charptr); - srcport_f= 1; - - if((charptr = strtok_r(NULL, "/", &lasts)) != NULL){ - srcportpref= atoi(charptr); - srcportrnd_f=1; - sanitize_port(&srcport, srcportpref); - } - - if(srcportpref >= 16) - srcportrnd_f= 0; - - break; - - case 'a': /* TCP Destination Port */ - if((charptr = strtok_r(optarg, "/", &lasts)) == NULL){ - puts("Error TCP Destination Port"); - exit(EXIT_FAILURE); - } - - dstport= atoi(optarg); - dstport_f= 1; - - if((charptr = strtok_r(NULL, "/", &lasts)) != NULL){ - dstportpref= atoi(charptr); - dstportrnd_f=1; - sanitize_port(&dstport, dstportpref); - } - - if(dstportpref >= 16) - dstportrnd_f= 0; - - break; - - case 'X': - if(strncmp(optarg, "auto", 4) == 0){ - tcpflags_auto_f=1; - break; - } - - charptr = optarg; - while(*charptr){ - switch(*charptr){ - case 'F': - tcpflags= tcpflags | TH_FIN; - break; - - case 'S': - tcpflags= tcpflags | TH_SYN; - break; - - case 'R': - tcpflags= tcpflags | TH_RST; - break; - - case 'P': - tcpflags= tcpflags | TH_PUSH; - break; - - case 'A': - tcpflags= tcpflags | TH_ACK; - break; - - case 'U': - tcpflags= tcpflags | TH_URG; - break; - - case 'X': /* No TCP flags */ - break; - - default: - printf("Unknown TCP flag '%c'\n", *charptr); - exit(EXIT_FAILURE); - break; - } - - if(*charptr == 'X') - break; - - charptr++; - } - - tcpflags_f=1; - break; - - case 'q': /* TCP Sequence Number */ - if((ul_res = strtoul(optarg, &endptr, 0)) == ULONG_MAX){ - perror("Error in 'TCP Sequence NUmber' parameter"); - exit(EXIT_FAILURE); - } - - if(endptr != optarg){ - tcpseq = ul_res; - tcpseq_f=1; - } - - break; - - case 'Q': /* TCP Acknowledgement Number */ - if((ul_res = strtoul(optarg, &endptr, 0)) == ULONG_MAX){ - perror("Error in 'TCP Sequence NUmber' parameter"); - exit(EXIT_FAILURE); - } - - if(endptr != optarg){ - tcpack = ul_res; - tcpack_f=1; - } - break; - - case 'V': /* TCP Urgent Pointer */ - tcpurg= atoi(optarg); - tcpurg_f= 1; - break; - - case 'w': /* TCP Window */ - tcpwin= atoi(optarg); - tcpwin_f=1; - break; - - case 'W': /* TCP Window */ - if(strncmp(optarg, "close", MAX_CMDLINE_OPT_LEN) == 0 || strncmp(optarg, "closed", MAX_CMDLINE_OPT_LEN) == 0){ - window= WIN_CLOSED; - } - else if(strncmp(optarg, "modulate", MAX_CMDLINE_OPT_LEN) == 0 || strncmp(optarg, "modulation", MAX_CMDLINE_OPT_LEN) == 0){ - window= WIN_MODULATE; - } - else{ - puts("Error: Unknown window option ('-W')"); - exit(EXIT_FAILURE); - } - - window_f=1; - break; - - case 'M': - sscanf(optarg, "%u:%u:%u:%u", &win1_size, &time1_len, &win2_size, &time2_len); - winmodulate_f= 1; - break; - - case 'N': /* Do not ack data */ - ackdata_f= 0; - break; - - case 'n': /* Do not ack flags */ - ackflags_f= 0; - break; - - case 'j': /* IPv6 Source Address (block) filter */ - if(filters.nblocksrc >= MAX_BLOCK_SRC){ - puts("Too many IPv6 Source Address (block) filters."); - exit(EXIT_FAILURE); - } - - if((pref = strtok_r(optarg, "/", &lasts)) == NULL){ - printf("Error in IPv6 Source Address (block) filter number %u.\n", \ - filters.nblocksrc+1); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, pref, &(filters.blocksrc[filters.nblocksrc])) <= 0){ - printf("Error in IPv6 Source Address (block) filter number %u.", \ - filters.nblocksrc+1); - exit(EXIT_FAILURE); - } - - if((charptr = strtok_r(NULL, " ", &lasts)) == NULL){ - filters.blocksrclen[filters.nblocksrc] = 128; - } - else{ - filters.blocksrclen[filters.nblocksrc] = atoi(charptr); - - if(filters.blocksrclen[filters.nblocksrc]>128){ - printf("Length error in IPv6 Source Address (block) filter number %u.\n", \ - filters.nblocksrc+1); - exit(EXIT_FAILURE); - } - } - - sanitize_ipv6_prefix(&(filters.blocksrc[filters.nblocksrc]), filters.blocksrclen[filters.nblocksrc]); - (filters.nblocksrc)++; - break; - - case 'k': /* IPv6 Destination Address (block) filter */ - if(filters.nblockdst >= MAX_BLOCK_DST){ - puts("Too many IPv6 Destination Address (block) filters."); - exit(EXIT_FAILURE); - } - - if((pref = strtok_r(optarg, "/", &lasts)) == NULL){ - printf("Error in IPv6 Destination Address (block) filter number %u.\n", \ - filters.nblockdst+1); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, pref, &(filters.blockdst[filters.nblockdst])) <= 0){ - printf("Error in IPv6 Source Address (block) filter number %u.", \ - filters.nblockdst+1); - exit(EXIT_FAILURE); - } - - if((charptr = strtok_r(NULL, " ", &lasts)) == NULL){ - filters.blockdstlen[filters.nblockdst] = 128; - } - else{ - filters.blockdstlen[filters.nblockdst] = atoi(charptr); - - if(filters.blockdstlen[filters.nblockdst]>128){ - printf("Length error in IPv6 Source Address (block) filter number %u.\n", \ - filters.nblockdst+1); - exit(EXIT_FAILURE); - } - } - - sanitize_ipv6_prefix(&(filters.blockdst[filters.nblockdst]), filters.blockdstlen[filters.nblockdst]); - (filters.nblockdst)++; - break; - - case 'J': /* Link Source Address (block) filter */ - if(filters.nblocklinksrc > MAX_BLOCK_LINK_SRC){ - puts("Too many link-layer Source Address (accept) filters."); - exit(EXIT_FAILURE); - } - - if(ether_pton(optarg, &(filters.blocklinksrc[filters.nblocklinksrc]), sizeof(struct ether_addr)) == 0){ - printf("Error in link-layer Source Address (blick) filter number %u.\n", \ - filters.nblocklinksrc+1); - exit(EXIT_FAILURE); - } - - (filters.nblocklinksrc)++; - break; - - case 'K': /* Link Destination Address (block) filter */ - if(filters.nblocklinkdst > MAX_BLOCK_LINK_DST){ - puts("Too many link-layer Destination Address (block) filters."); - exit(EXIT_FAILURE); - } - - if(ether_pton(optarg, &(filters.blocklinkdst[filters.nblocklinkdst]), sizeof(struct ether_addr)) == 0){ - printf("Error in link-layer Destination Address (blick) filter number %u.\n", \ - filters.nblocklinkdst+1); - exit(EXIT_FAILURE); - } - - filters.nblocklinkdst++; - break; - - case 'b': /* IPv6 Source Address (accept) filter */ - if(filters.nacceptsrc > MAX_ACCEPT_SRC){ - puts("Too many IPv6 Source Address (accept) filters."); - exit(EXIT_FAILURE); - } - - if((pref = strtok_r(optarg, "/", &lasts)) == NULL){ - printf("Error in IPv6 Source Address (accept) filter number %u.\n", \ - filters.nacceptsrc+1); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, pref, &(filters.acceptsrc[filters.nacceptsrc])) <= 0){ - printf("Error in IPv6 Source Address (accept) filter number %u.\n", \ - filters.nacceptsrc+1); - exit(EXIT_FAILURE); - } - - if((charptr = strtok_r(NULL, " ", &lasts)) == NULL){ - filters.acceptsrclen[filters.nacceptsrc] = 128; - } - else{ - filters.acceptsrclen[filters.nacceptsrc] = atoi(charptr); - - if(filters.acceptsrclen[filters.nacceptsrc]>128){ - printf("Length error in IPv6 Source Address (accept) filter number %u.\n", \ - filters.nacceptsrc+1); - exit(EXIT_FAILURE); - } - } - - sanitize_ipv6_prefix(&(filters.acceptsrc[filters.nacceptsrc]), filters.acceptsrclen[filters.nacceptsrc]); - (filters.nacceptsrc)++; - filters.acceptfilters_f=1; - break; - - - case 'g': /* IPv6 Destination Address (accept) filter */ - if(filters.nacceptdst > MAX_ACCEPT_DST){ - puts("Too many IPv6 Destination Address (accept) filters."); - exit(EXIT_FAILURE); - } - - if((pref = strtok_r(optarg, "/", &lasts)) == NULL){ - printf("Error in IPv6 Destination Address (accept) filter number %u.\n", \ - filters.nacceptdst+1); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, pref, &(filters.acceptdst[filters.nacceptdst])) <= 0){ - printf("Error in IPv6 Source Address (accept) filter number %u.\n", \ - filters.nacceptdst+1); - exit(EXIT_FAILURE); - } - - if((charptr = strtok_r(NULL, " ", &lasts)) == NULL){ - filters.acceptdstlen[filters.nacceptdst] = 128; - } - else{ - filters.acceptdstlen[filters.nacceptdst] = atoi(charptr); - - if(filters.acceptdstlen[filters.nacceptdst] > 128){ - printf("Length error in IPv6 Source Address (accept) filter number %u.\n", \ - filters.nacceptdst+1); - exit(EXIT_FAILURE); - } - } - - sanitize_ipv6_prefix(&(filters.acceptdst[filters.nacceptdst]), filters.acceptdstlen[filters.nacceptdst]); - (filters.nacceptdst)++; - filters.acceptfilters_f=1; - break; - - case 'B': /* Link-layer Source Address (accept) filter */ - if(filters.nacceptlinksrc > MAX_ACCEPT_LINK_SRC){ - puts("Too many link-later Source Address (accept) filters."); - exit(EXIT_FAILURE); - } - - if(ether_pton(optarg, &(filters.acceptlinksrc[filters.nacceptlinksrc]), sizeof(struct ether_addr)) == 0){ - printf("Error in link-layer Source Address (accept) filter number %u.\n", \ - filters.nacceptlinksrc+1); - exit(EXIT_FAILURE); - } - - (filters.nacceptlinksrc)++; - filters.acceptfilters_f=1; - break; - - case 'G': /* Link Destination Address (accept) filter */ - if(filters.nacceptlinkdst > MAX_ACCEPT_LINK_DST){ - puts("Too many link-layer Destination Address (accept) filters."); - exit(EXIT_FAILURE); - } - - if(ether_pton(optarg, &(filters.acceptlinkdst[filters.nacceptlinkdst]), sizeof(struct ether_addr)) == 0){ - printf("Error in link-layer Destination Address (accept) filter number %u.\n",\ - filters.nacceptlinkdst+1); - exit(EXIT_FAILURE); - } - - (filters.nacceptlinkdst)++; - filters.acceptfilters_f=1; - break; - - case 'F': /* Flood source addresses */ - nsources= atoi(optarg); - if(nsources == 0){ - puts("Invalid number of source addresses in option -F"); - exit(EXIT_FAILURE); - } - - floods_f= 1; - break; - - case 'T': /* Flood source ports */ - nports= atoi(optarg); - - if(nports == 0){ - puts("Invalid number of source ports in option -T"); - exit(EXIT_FAILURE); - } - - floodp_f= 1; - break; - - case 'l': /* "Loop mode */ - loop_f = 1; - break; - - case 'r': - if( Strnlen(optarg, LINE_BUFFER_SIZE-1) >= (LINE_BUFFER_SIZE-1)){ - puts("tcp6: -r option is too long"); - exit(EXIT_FAILURE); - } - - sscanf(optarg, "%lu%s", &rate, line); - line[LINE_BUFFER_SIZE-1]=0; - - if(strncmp(line, "pps", 3) == 0) - pps_f=1; - else if(strncmp(line, "bps", 3) == 0) - bps_f=1; - else{ - puts("tcp6: Unknown unit of for the rate limit ('-r' option). Unit should be 'bps' or 'pps'"); - exit(EXIT_FAILURE); - } - - break; - - - case 'z': /* Sleep option */ - nsleep=atoi(optarg); - if(nsleep==0){ - puts("Invalid number of seconds in '-z' option"); - exit(EXIT_FAILURE); - } - - sleep_f=1; - break; - - case 'L': /* "Listen mode */ - listen_f = 1; - break; - - case 'p': /* Probe mode */ - if(strncmp(optarg, "dump", MAX_CMDLINE_OPT_LEN) == 0){ - probemode= PROBE_DUMP; - } - else if(strncmp(optarg, "script", MAX_CMDLINE_OPT_LEN) == 0){ - probemode= PROBE_SCRIPT; - } - else{ - puts("Error: Unknown open mode in '-Y' option"); - exit(EXIT_FAILURE); - } - - probemode_f=1; - break; - - case 'x': /* Number of retrnasmissions */ - retrans= atoi(optarg); - retrans_f=1; - break; - - case 'v': /* Be verbose */ - (idata.verbose_f)++; - break; - - case 'h': /* Help */ - print_help(); - exit(EXIT_FAILURE); - break; - - default: - usage(); - exit(EXIT_FAILURE); - break; - - } /* switch */ - } /* while(getopt) */ - - if(geteuid()) { - puts("tcp6 needs root privileges to run."); - exit(EXIT_FAILURE); - } - - srandom(time(NULL)); - - /* - If the flood option ("-F") has been specified, but no prefix has been specified, - assume a /64 prefix. - */ - if(floods_f && !idata.srcprefix_f){ - idata.srcpreflen=64; - } - - if(!(idata.dstaddr_f) && !listen_f){ /* Must specify IPv6 Destination Address if listening mode not used */ - puts("IPv6 Destination Address not specified (and listening mode not selected)"); - exit(EXIT_FAILURE); - } - - if(rhbytes_f && data_f){ - puts("Cannot set '--data' and '--payload-size' at the same time"); - exit(EXIT_FAILURE); - } - - if(!idata.iface_f){ - if(idata.dstaddr_f && IN6_IS_ADDR_LINKLOCAL(&(idata.dstaddr))){ - puts("Must specify a network interface for link-local destinations"); - exit(EXIT_FAILURE); - } - else if(listen_f){ - puts("Must specify a network interface when employing the 'listenging' mode"); - exit(EXIT_FAILURE); - } - } - - if(load_dst_and_pcap(&idata, (idata.dstaddr_f?LOAD_SRC_NXT_HOP:LOAD_PCAP_ONLY)) == FAILURE){ - puts("Error while learning Source Address and Next Hop"); - exit(EXIT_FAILURE); - } - - release_privileges(); - - if(data_f){ - data[datalen]=0; - - if(!string_escapes(data, &datalen, DATA_BUFFER_LEN-1)){ - puts("Error in data string option ('-Z')"); - exit(EXIT_FAILURE); - } - - data[datalen]=0; - } - - if(!floods_f) - nsources=1; - - if(!floodp_f) - nports=1; - - if(!sleep_f) - nsleep=1; - - if(sleep_f && (pps_f || bps_f)){ - puts("Cannot specify a rate-limit (-r) and a sleep time at the same time"); - exit(EXIT_FAILURE); - } - - if(pps_f && bps_f){ - puts("Cannot specify a rate-limit in bps and pps at the same time"); - exit(EXIT_FAILURE); - } - - if(pps_f){ - if(rate < 1) - rate=1; - - pktinterval= 1000000/rate; - } - - if(bps_f){ - packetsize= MIN_IPV6_HLEN + sizeof(struct tcp_hdr) + rhbytes; - - for(i=0; i < ndstopthdr; i++) - packetsize+= dstopthdrlen[i]; - - for(i=0; i < ndstoptuhdr; i++) - packetsize+= dstoptuhdrlen[i]; - - for(i=0; i < nhbhopthdr; i++) - packetsize+= hbhopthdrlen[i]; - - if(idata.fragh_f) - packetsize+= sizeof(struct ip6_frag); - - if(rate == 0 || ((packetsize * 8)/rate) <= 0) - pktinterval= 1000000; - else - pktinterval= ((packetsize * 8)/rate) * 1000000; - } - - /* We Default to 1000 pps */ - if(!pps_f && !bps_f){ - rate= 1000; - pktinterval= 1000000/rate; - } - - if( !idata.fragh_f && dstoptuhdr_f){ - puts("Dst. Options Header (Unfragmentable Part) set, but Fragmentation not specified"); - exit(EXIT_FAILURE); - } - - /* - * If we are going to send packets to a specified target, we must set some default values - */ - if(idata.dstaddr_f){ - if(!tcpflags_auto_f && !tcpflags_f && !tcpopen_f && !tcpclose_f) - tcpflags= tcpflags | TH_ACK; - - if(!tcpack_f && (tcpflags & TH_ACK)) - tcpack= random(); - - if(!tcpseq_f) - tcpseq= random(); - - if(srcport_f){ - if(srcportrnd_f){ - randomize_port(&srcport, srcport, srcportpref); - } - } - else{ - srcport= random(); - } - - if(dstport_f){ - if(dstportrnd_f){ - randomize_port(&dstport, dstport, dstportpref); - } - } - else{ - dstport= random(); - } - - if(!tcpurg_f) - tcpurg= 0; - } - - /* By default, we randomize the TCP Window */ - if(!tcpwin_f) - tcpwin= ((uint16_t) random() + 1500) & (uint16_t)0x7f00; - - if(!rhbytes_f) - rhbytes=0; - - if(idata.verbose_f){ - print_attack_info(&idata); - } - - /* - Set filter for IPv6 packets (find_ipv6_router() set its own filter fore receiving RAs) - */ - - if(pcap_compile(idata.pfd, &pcap_filter, PCAP_TCPIPV6_NS_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1){ - printf("pcap_compile(): %s", pcap_geterr(idata.pfd)); - exit(EXIT_FAILURE); - } - - if(pcap_setfilter(idata.pfd, &pcap_filter) == -1){ - printf("pcap_setfilter(): %s", pcap_geterr(idata.pfd)); - exit(EXIT_FAILURE); - } - - pcap_freecode(&pcap_filter); - - /* Set initial contents of the attack packet */ - init_packet_data(&idata); - addr_key= random(); - - if(sleep_f) - pktinterval= (nsleep * 1000000)/(nsources * nports); - - timeout.tv_sec= pktinterval / 1000000; - timeout.tv_usec= pktinterval % 1000000; - stimeout= timeout; - - if(window_f){ - if(window == WIN_MODULATE && !winmodulate_f){ - win1_size= WIN_MODULATE_CLOSED_SIZE; - time1_len= WIN_MODULATE_CLOSED_LEN; - win2_size= WIN_MODULATE_OPEN_SIZE; - time2_len= WIN_MODULATE_OPEN_LEN; - } - } - - if(window_f && window == WIN_MODULATE){ - if(gettimeofday(&wmtimeout, NULL) == -1){ - if(idata.verbose_f) - perror("tcp6"); - - exit(EXIT_FAILURE); - } - - tcpwinm= win1_size; - } - - - if(probemode_f){ - end_f=0; - - if(dstport_f){ - if(dstportrnd_f){ - randomize_port(&dstport, dstport, dstportpref); - } - } - else{ - dstport= 80; - } - - if(srcport_f){ - if(srcportrnd_f){ - randomize_port(&srcport, srcport, srcportpref); - } - } - else{ - srcport= 50000 + random() % 15000; /* We select ports from the "high ports" range */ - } - - - if(!rto_f) - rto=1; - - if(!retrans_f) - retrans=0; - - retr=0; - retrans++; - - FD_ZERO(&sset); - FD_SET(idata.fd, &sset); - - lastprobe.tv_sec= 0; - lastprobe.tv_usec=0; - - while(!end_f){ - if(gettimeofday(&curtime, NULL) == -1){ - if(idata.verbose_f) - perror("tcp6"); - - exit(EXIT_FAILURE); - } - - if(is_time_elapsed(&curtime, &lastprobe, rto * 1000000) && retr < retrans){ - retr++; - lastprobe= curtime; - send_packet(&idata, NULL, NULL); - } - - if(is_time_elapsed(&curtime, &lastprobe, rto * 1000000) && retr >= retrans){ - end_f=1; - break; - } - - rset= sset; - timeout.tv_usec=0; - timeout.tv_sec= (rto < 1)?rto:1; - - if((sel=select(idata.fd+1, &rset, NULL, NULL, &timeout)) == -1){ - if(errno == EINTR){ - continue; - } - else{ - puts("Error in select()"); - exit(EXIT_FAILURE); - } - } +unsigned int dstopthdrs, dstoptuhdrs, hbhopthdrs; +char hbhopthdr_f = 0, dstoptuhdr_f = 0, dstopthdr_f = 0; +unsigned char *dstopthdr[MAX_DST_OPT_HDR], *dstoptuhdr[MAX_DST_OPT_U_HDR]; +unsigned char *hbhopthdr[MAX_HBH_OPT_HDR]; +unsigned int dstopthdrlen[MAX_DST_OPT_HDR], dstoptuhdrlen[MAX_DST_OPT_U_HDR]; +unsigned int hbhopthdrlen[MAX_HBH_OPT_HDR], m, pad; + +struct ip6_frag fraghdr, *fh; +struct ip6_hdr *fipv6; + +unsigned char fragbuffer[ETHER_HDR_LEN + MIN_IPV6_HLEN + MAX_IPV6_PAYLOAD]; +unsigned char *fragpart, *fptr, *fptrend, *ptrend, *ptrhdr, *ptrhdrend; +unsigned int hdrlen, ndstopthdr = 0, nhbhopthdr = 0, ndstoptuhdr = 0; +unsigned int nfrags, fragsize; +unsigned char *prev_nh, *startoffragment; + +struct filters filters; + +int main(int argc, char **argv) { + extern char *optarg; + char *endptr; /* Used by strtoul() */ + fd_set sset, rset; + /* fd_set wset, eset; */ + int r, sel; + struct timeval timeout, stimeout, curtime, lastprobe, wmtimeout; + /*struct tcp tcb; */ + /* unsigned char end_f=0, error_f; */ + unsigned char end_f = 0; + unsigned long pktinterval = 0; /*Add datasent=0*/ + unsigned int retr = 0; + struct target_ipv6 targetipv6; + + static struct option longopts[] = {{"interface", required_argument, 0, 'i'}, + {"src-addr", required_argument, 0, 's'}, + {"dst-addr", required_argument, 0, 'd'}, + {"hop-limit", required_argument, 0, 'A'}, + {"open-mode", required_argument, 0, 'c'}, + {"close-mode", required_argument, 0, 'C'}, + {"data", required_argument, 0, 'Z'}, + {"dst-opt-hdr", required_argument, 0, 'u'}, + {"dst-opt-u-hdr", required_argument, 0, 'U'}, + {"hbh-opt-hdr", required_argument, 0, 'H'}, + {"frag-hdr", required_argument, 0, 'y'}, + {"link-src-addr", required_argument, 0, 'S'}, + {"link-dst-addr", required_argument, 0, 'D'}, + {"payload-size", required_argument, 0, 'P'}, + {"src-port", required_argument, 0, 'o'}, + {"dst-port", required_argument, 0, 'a'}, + {"tcp-flags", required_argument, 0, 'X'}, + {"tcp-seq", required_argument, 0, 'q'}, + {"tcp-ack", required_argument, 0, 'Q'}, + {"tcp-urg", required_argument, 0, 'V'}, + {"tcp-win", required_argument, 0, 'w'}, + {"window-mode", required_argument, 0, 'W'}, + {"win-modulation", required_argument, 0, 'M'}, + {"not-ack-data", no_argument, 0, 'N'}, + {"not-ack-flags", no_argument, 0, 'n'}, + {"block-src-addr", required_argument, 0, 'j'}, + {"block-dst-addr", required_argument, 0, 'k'}, + {"block-link-src-addr", required_argument, 0, 'J'}, + {"block-link-dst-addr", required_argument, 0, 'K'}, + {"accept-src-addr", required_argument, 0, 'b'}, + {"accept-dst-addr", required_argument, 0, 'g'}, + {"accept-link-src-addr", required_argument, 0, 'B'}, + {"accept-link-dst-addr", required_argument, 0, 'G'}, + {"flood-sources", required_argument, 0, 'F'}, + {"flood-ports", required_argument, 0, 'T'}, + {"loop", no_argument, 0, 'l'}, + {"rate-limit", required_argument, 0, 'r'}, + {"sleep", required_argument, 0, 'z'}, + {"listen", no_argument, 0, 'L'}, + {"probe-mode", required_argument, 0, 'p'}, + {"retrans", required_argument, 0, 'x'}, + {"verbose", no_argument, 0, 'v'}, + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0}}; + + const char shortopts[] = "i:s:d:A:c:C:Z:u:U:H:y:S:D:P:o:a:X:q:Q:V:w:W:M:Nnj:k:J:K:b:g:B:G:F:T:lr:z:Lp:x:vh"; + + char option; + + if (argc <= 1) { + usage(); + exit(EXIT_FAILURE); + } + + hoplimit = 255; + + lastprobe.tv_sec = 0; + lastprobe.tv_usec = 0; + + /* Initialize filters structure */ + if (init_filters(&filters) == -1) { + puts("Error initializing internal data structure"); + exit(EXIT_FAILURE); + } + + if (init_iface_data(&idata) == FAILURE) { + puts("Error initializing internal data structure"); + exit(EXIT_FAILURE); + } + + while ((r = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { + option = r; + + switch (option) { + case 'i': /* Interface */ + strncpy(idata.iface, optarg, IFACE_LENGTH); + idata.iface[IFACE_LENGTH - 1] = 0; + idata.ifindex = if_nametoindex(idata.iface); + idata.iface_f = TRUE; + break; + + case 's': /* IPv6 Source Address */ + if (idata.srcaddr_f) { + puts("Error: Multiple '-s' options have been specified"); + exit(EXIT_FAILURE); + } + + if ((charptr = strtok_r(optarg, "/", &lasts)) == NULL) { + puts("Error in Source Address"); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, charptr, &(idata.srcaddr)) <= 0) { + puts("inet_pton(): Source Address not valid"); + exit(EXIT_FAILURE); + } + + idata.srcaddr_f = 1; + + if ((charptr = strtok_r(NULL, " ", &lasts)) != NULL) { + idata.srcpreflen = atoi(charptr); + + if (idata.srcpreflen > 128) { + puts("Prefix length error in IPv6 Source Address"); + exit(EXIT_FAILURE); + } + + if (idata.srcpreflen == 64) + useaddrkey_f = 1; + + sanitize_ipv6_prefix(&(idata.srcaddr), idata.srcpreflen); + idata.srcprefix_f = 1; + } + + break; + + case 'd': /* IPv6 Destination Address */ + strncpy(targetipv6.name, optarg, NI_MAXHOST); + targetipv6.name[NI_MAXHOST - 1] = 0; + targetipv6.flags = AI_CANONNAME; + + if ((r = get_ipv6_target(&targetipv6)) != 0) { + + if (r < 0) { + printf("Unknown Destination: %s\n", gai_strerror(targetipv6.res)); + } + else { + puts("Unknown Destination: No IPv6 address found for specified destination"); + } + + exit(EXIT_FAILURE); + } + + idata.dstaddr = targetipv6.ip6; + idata.dstaddr_f = 1; + break; + + case 'A': /* Hop Limit */ + hoplimit = atoi(optarg); + hoplimit_f = 1; + break; + + case 'c': + if (strncmp(optarg, "simultaneous", MAX_CMDLINE_OPT_LEN) == 0) { + tcpopen = OPEN_SIMULTANEOUS; + } + else if (strncmp(optarg, "passive", MAX_CMDLINE_OPT_LEN) == 0) { + tcpopen = OPEN_PASSIVE; + } + else if (strncmp(optarg, "abort", MAX_CMDLINE_OPT_LEN) == 0) { + tcpopen = OPEN_ABORT; + } + else if (strncmp(optarg, "active", MAX_CMDLINE_OPT_LEN) == 0) { + tcpopen = OPEN_ACTIVE; + } + else { + puts("Error: Unknown open mode in '-c' option"); + exit(EXIT_FAILURE); + } + + tcpopen_f = 1; + break; + + case 'C': + if (strncmp(optarg, "simultaneous", MAX_CMDLINE_OPT_LEN) == 0) { + tcpclose = CLOSE_SIMULTANEOUS; + } + else if (strncmp(optarg, "passive", MAX_CMDLINE_OPT_LEN) == 0) { + tcpclose = CLOSE_PASSIVE; + } + else if (strncmp(optarg, "abort", MAX_CMDLINE_OPT_LEN) == 0) { + tcpclose = CLOSE_ABORT; + } + else if (strncmp(optarg, "active", MAX_CMDLINE_OPT_LEN) == 0) { + tcpclose = CLOSE_ACTIVE; + } + else if (strncmp(optarg, "fin-wait-1", MAX_CMDLINE_OPT_LEN) == 0 || + strncmp(optarg, "FIN-WAIT-1", MAX_CMDLINE_OPT_LEN) == 0) { + tcpclose = CLOSE_FIN_WAIT_1; + } + else if (strncmp(optarg, "fin-wait-2", MAX_CMDLINE_OPT_LEN) == 0 || + strncmp(optarg, "FIN-WAIT-2", MAX_CMDLINE_OPT_LEN) == 0) { + tcpclose = CLOSE_FIN_WAIT_2; + } + else if (strncmp(optarg, "last-ack", MAX_CMDLINE_OPT_LEN) == 0 || + strncmp(optarg, "LAST-ACK", MAX_CMDLINE_OPT_LEN) == 0) { + tcpclose = CLOSE_LAST_ACK; + } + else { + puts("Error: Unknown close option ('-C')"); + exit(EXIT_FAILURE); + } + + tcpclose_f = 1; + break; + + case 'Z': /* Data */ + datalen = Strnlen(optarg, MAX_CMDLINE_OPT_LEN); + + if (datalen >= DATA_BUFFER_LEN) + datalen = DATA_BUFFER_LEN - 1; + + strncpy(data, optarg, DATA_BUFFER_LEN - 1); + data_f = 1; + break; + + case 'u': /* Destinations Options Header */ + if (ndstopthdr >= MAX_DST_OPT_HDR) { + puts("Too many Destination Options Headers"); + exit(EXIT_FAILURE); + } + + hdrlen = atoi(optarg); + + if (hdrlen < 8) { + puts("Bad length in Destination Options Header"); + exit(EXIT_FAILURE); + } + + hdrlen = ((hdrlen + 7) / 8) * 8; + dstopthdrlen[ndstopthdr] = hdrlen; + + if ((dstopthdr[ndstopthdr] = malloc(hdrlen)) == NULL) { + puts("Not enough memory for Destination Options Header"); + exit(EXIT_FAILURE); + } + + ptrhdr = dstopthdr[ndstopthdr] + 2; + ptrhdrend = dstopthdr[ndstopthdr] + hdrlen; + + while (ptrhdr < ptrhdrend) { + + if ((ptrhdrend - ptrhdr) > 257) + pad = 257; + else + pad = ptrhdrend - ptrhdr; + + if (!insert_pad_opt(ptrhdr, ptrhdrend, pad)) { + puts("Destination Options Header Too Big"); + exit(EXIT_FAILURE); + } + + ptrhdr = ptrhdr + pad; + } + + *(dstopthdr[ndstopthdr] + 1) = (hdrlen / 8) - 1; + ndstopthdr++; + dstopthdr_f = 1; + break; + + case 'U': /* Destination Options Header (Unfragmentable Part) */ + if (ndstoptuhdr >= MAX_DST_OPT_U_HDR) { + puts("Too many Destination Options Headers (Unfragmentable Part)"); + exit(EXIT_FAILURE); + } + + hdrlen = atoi(optarg); + + if (hdrlen < 8) { + puts("Bad length in Destination Options Header (Unfragmentable Part)"); + exit(EXIT_FAILURE); + } + + hdrlen = ((hdrlen + 7) / 8) * 8; + dstoptuhdrlen[ndstoptuhdr] = hdrlen; + + if ((dstoptuhdr[ndstoptuhdr] = malloc(hdrlen)) == NULL) { + puts("Not enough memory for Destination Options Header (Unfragmentable Part)"); + exit(EXIT_FAILURE); + } + + ptrhdr = dstoptuhdr[ndstoptuhdr] + 2; + ptrhdrend = dstoptuhdr[ndstoptuhdr] + hdrlen; + + while (ptrhdr < ptrhdrend) { + + if ((ptrhdrend - ptrhdr) > 257) + pad = 257; + else + pad = ptrhdrend - ptrhdr; + + if (!insert_pad_opt(ptrhdr, ptrhdrend, pad)) { + puts("Destination Options Header (Unfragmentable Part) Too Big"); + exit(EXIT_FAILURE); + } + + ptrhdr = ptrhdr + pad; + } + + *(dstoptuhdr[ndstoptuhdr] + 1) = (hdrlen / 8) - 1; + ndstoptuhdr++; + dstoptuhdr_f = 1; + break; + + case 'H': /* Hop-by-Hop Options Header */ + if (nhbhopthdr >= MAX_HBH_OPT_HDR) { + puts("Too many Hop-by-Hop Options Headers"); + exit(EXIT_FAILURE); + } + + hdrlen = atoi(optarg); + + if (hdrlen < 8) { + puts("Bad length in Hop-by-Hop Options Header"); + exit(EXIT_FAILURE); + } + + hdrlen = ((hdrlen + 7) / 8) * 8; + hbhopthdrlen[nhbhopthdr] = hdrlen; + + if ((hbhopthdr[nhbhopthdr] = malloc(hdrlen)) == NULL) { + puts("Not enough memory for Hop-by-Hop Options Header"); + exit(EXIT_FAILURE); + } + + ptrhdr = hbhopthdr[nhbhopthdr] + 2; + ptrhdrend = hbhopthdr[nhbhopthdr] + hdrlen; + + while (ptrhdr < ptrhdrend) { + + if ((ptrhdrend - ptrhdr) > 257) + pad = 257; + else + pad = ptrhdrend - ptrhdr; + + if (!insert_pad_opt(ptrhdr, ptrhdrend, pad)) { + puts("Hop-by-Hop Options Header Too Big"); + exit(EXIT_FAILURE); + } + + ptrhdr = ptrhdr + pad; + } + + *(hbhopthdr[nhbhopthdr] + 1) = (hdrlen / 8) - 1; + nhbhopthdr++; + hbhopthdr_f = 1; + break; + + case 'y': /* Fragment header */ + nfrags = atoi(optarg); + if (nfrags < 8) { + puts("Error in Fragmentation option: Fragment Size must be at least 8 bytes"); + exit(EXIT_FAILURE); + } + + idata.fragh_f = 1; + break; + + case 'S': /* Source Ethernet address */ + if (ether_pton(optarg, &(idata.hsrcaddr), sizeof(idata.hsrcaddr)) == 0) { + puts("Error in Source link-layer address."); + exit(EXIT_FAILURE); + } + + idata.hsrcaddr_f = 1; + break; + + case 'D': /* Destination Ethernet Address */ + if (ether_pton(optarg, &(idata.hdstaddr), sizeof(idata.hdstaddr)) == 0) { + puts("Error in Source link-layer address."); + exit(EXIT_FAILURE); + } + + idata.hdstaddr_f = 1; + break; + + case 'P': /* Payload Size*/ + rhbytes = atoi(optarg); + rhbytes_f = 1; + break; + + case 'o': /* TCP Source Port */ + if ((charptr = strtok_r(optarg, "/", &lasts)) == NULL) { + puts("Error in TCP Source Port"); + exit(EXIT_FAILURE); + } + + srcport = atoi(charptr); + srcport_f = 1; + + if ((charptr = strtok_r(NULL, "/", &lasts)) != NULL) { + srcportpref = atoi(charptr); + srcportrnd_f = 1; + sanitize_port(&srcport, srcportpref); + } + + if (srcportpref >= 16) + srcportrnd_f = 0; + + break; + + case 'a': /* TCP Destination Port */ + if ((charptr = strtok_r(optarg, "/", &lasts)) == NULL) { + puts("Error TCP Destination Port"); + exit(EXIT_FAILURE); + } + + dstport = atoi(optarg); + dstport_f = 1; + + if ((charptr = strtok_r(NULL, "/", &lasts)) != NULL) { + dstportpref = atoi(charptr); + dstportrnd_f = 1; + sanitize_port(&dstport, dstportpref); + } + + if (dstportpref >= 16) + dstportrnd_f = 0; + + break; + + case 'X': + if (strncmp(optarg, "auto", 4) == 0) { + tcpflags_auto_f = 1; + break; + } + + charptr = optarg; + while (*charptr) { + switch (*charptr) { + case 'F': + tcpflags = tcpflags | TH_FIN; + break; + + case 'S': + tcpflags = tcpflags | TH_SYN; + break; + + case 'R': + tcpflags = tcpflags | TH_RST; + break; + + case 'P': + tcpflags = tcpflags | TH_PUSH; + break; + + case 'A': + tcpflags = tcpflags | TH_ACK; + break; + + case 'U': + tcpflags = tcpflags | TH_URG; + break; + + case 'X': /* No TCP flags */ + break; + + default: + printf("Unknown TCP flag '%c'\n", *charptr); + exit(EXIT_FAILURE); + break; + } + + if (*charptr == 'X') + break; + + charptr++; + } + + tcpflags_f = 1; + break; + + case 'q': /* TCP Sequence Number */ + if ((ul_res = strtoul(optarg, &endptr, 0)) == ULONG_MAX) { + perror("Error in 'TCP Sequence NUmber' parameter"); + exit(EXIT_FAILURE); + } + + if (endptr != optarg) { + tcpseq = ul_res; + tcpseq_f = 1; + } + + break; + + case 'Q': /* TCP Acknowledgement Number */ + if ((ul_res = strtoul(optarg, &endptr, 0)) == ULONG_MAX) { + perror("Error in 'TCP Sequence NUmber' parameter"); + exit(EXIT_FAILURE); + } + + if (endptr != optarg) { + tcpack = ul_res; + tcpack_f = 1; + } + break; + + case 'V': /* TCP Urgent Pointer */ + tcpurg = atoi(optarg); + tcpurg_f = 1; + break; + + case 'w': /* TCP Window */ + tcpwin = atoi(optarg); + tcpwin_f = 1; + break; + + case 'W': /* TCP Window */ + if (strncmp(optarg, "close", MAX_CMDLINE_OPT_LEN) == 0 || + strncmp(optarg, "closed", MAX_CMDLINE_OPT_LEN) == 0) { + window = WIN_CLOSED; + } + else if (strncmp(optarg, "modulate", MAX_CMDLINE_OPT_LEN) == 0 || + strncmp(optarg, "modulation", MAX_CMDLINE_OPT_LEN) == 0) { + window = WIN_MODULATE; + } + else { + puts("Error: Unknown window option ('-W')"); + exit(EXIT_FAILURE); + } + + window_f = 1; + break; + + case 'M': + sscanf(optarg, "%u:%u:%u:%u", &win1_size, &time1_len, &win2_size, &time2_len); + winmodulate_f = 1; + break; + + case 'N': /* Do not ack data */ + ackdata_f = 0; + break; + + case 'n': /* Do not ack flags */ + ackflags_f = 0; + break; + + case 'j': /* IPv6 Source Address (block) filter */ + if (filters.nblocksrc >= MAX_BLOCK_SRC) { + puts("Too many IPv6 Source Address (block) filters."); + exit(EXIT_FAILURE); + } + + if ((pref = strtok_r(optarg, "/", &lasts)) == NULL) { + printf("Error in IPv6 Source Address (block) filter number %u.\n", filters.nblocksrc + 1); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, pref, &(filters.blocksrc[filters.nblocksrc])) <= 0) { + printf("Error in IPv6 Source Address (block) filter number %u.", filters.nblocksrc + 1); + exit(EXIT_FAILURE); + } + + if ((charptr = strtok_r(NULL, " ", &lasts)) == NULL) { + filters.blocksrclen[filters.nblocksrc] = 128; + } + else { + filters.blocksrclen[filters.nblocksrc] = atoi(charptr); + + if (filters.blocksrclen[filters.nblocksrc] > 128) { + printf("Length error in IPv6 Source Address (block) filter number %u.\n", filters.nblocksrc + 1); + exit(EXIT_FAILURE); + } + } + + sanitize_ipv6_prefix(&(filters.blocksrc[filters.nblocksrc]), filters.blocksrclen[filters.nblocksrc]); + (filters.nblocksrc)++; + break; + + case 'k': /* IPv6 Destination Address (block) filter */ + if (filters.nblockdst >= MAX_BLOCK_DST) { + puts("Too many IPv6 Destination Address (block) filters."); + exit(EXIT_FAILURE); + } + + if ((pref = strtok_r(optarg, "/", &lasts)) == NULL) { + printf("Error in IPv6 Destination Address (block) filter number %u.\n", filters.nblockdst + 1); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, pref, &(filters.blockdst[filters.nblockdst])) <= 0) { + printf("Error in IPv6 Source Address (block) filter number %u.", filters.nblockdst + 1); + exit(EXIT_FAILURE); + } + + if ((charptr = strtok_r(NULL, " ", &lasts)) == NULL) { + filters.blockdstlen[filters.nblockdst] = 128; + } + else { + filters.blockdstlen[filters.nblockdst] = atoi(charptr); + + if (filters.blockdstlen[filters.nblockdst] > 128) { + printf("Length error in IPv6 Source Address (block) filter number %u.\n", filters.nblockdst + 1); + exit(EXIT_FAILURE); + } + } + + sanitize_ipv6_prefix(&(filters.blockdst[filters.nblockdst]), filters.blockdstlen[filters.nblockdst]); + (filters.nblockdst)++; + break; + + case 'J': /* Link Source Address (block) filter */ + if (filters.nblocklinksrc > MAX_BLOCK_LINK_SRC) { + puts("Too many link-layer Source Address (accept) filters."); + exit(EXIT_FAILURE); + } + + if (ether_pton(optarg, &(filters.blocklinksrc[filters.nblocklinksrc]), sizeof(struct ether_addr)) == 0) { + printf("Error in link-layer Source Address (blick) filter number %u.\n", filters.nblocklinksrc + 1); + exit(EXIT_FAILURE); + } + + (filters.nblocklinksrc)++; + break; + + case 'K': /* Link Destination Address (block) filter */ + if (filters.nblocklinkdst > MAX_BLOCK_LINK_DST) { + puts("Too many link-layer Destination Address (block) filters."); + exit(EXIT_FAILURE); + } + + if (ether_pton(optarg, &(filters.blocklinkdst[filters.nblocklinkdst]), sizeof(struct ether_addr)) == 0) { + printf("Error in link-layer Destination Address (blick) filter number %u.\n", + filters.nblocklinkdst + 1); + exit(EXIT_FAILURE); + } + + filters.nblocklinkdst++; + break; + + case 'b': /* IPv6 Source Address (accept) filter */ + if (filters.nacceptsrc > MAX_ACCEPT_SRC) { + puts("Too many IPv6 Source Address (accept) filters."); + exit(EXIT_FAILURE); + } + + if ((pref = strtok_r(optarg, "/", &lasts)) == NULL) { + printf("Error in IPv6 Source Address (accept) filter number %u.\n", filters.nacceptsrc + 1); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, pref, &(filters.acceptsrc[filters.nacceptsrc])) <= 0) { + printf("Error in IPv6 Source Address (accept) filter number %u.\n", filters.nacceptsrc + 1); + exit(EXIT_FAILURE); + } + + if ((charptr = strtok_r(NULL, " ", &lasts)) == NULL) { + filters.acceptsrclen[filters.nacceptsrc] = 128; + } + else { + filters.acceptsrclen[filters.nacceptsrc] = atoi(charptr); + + if (filters.acceptsrclen[filters.nacceptsrc] > 128) { + printf("Length error in IPv6 Source Address (accept) filter number %u.\n", filters.nacceptsrc + 1); + exit(EXIT_FAILURE); + } + } + + sanitize_ipv6_prefix(&(filters.acceptsrc[filters.nacceptsrc]), filters.acceptsrclen[filters.nacceptsrc]); + (filters.nacceptsrc)++; + filters.acceptfilters_f = 1; + break; + + case 'g': /* IPv6 Destination Address (accept) filter */ + if (filters.nacceptdst > MAX_ACCEPT_DST) { + puts("Too many IPv6 Destination Address (accept) filters."); + exit(EXIT_FAILURE); + } + + if ((pref = strtok_r(optarg, "/", &lasts)) == NULL) { + printf("Error in IPv6 Destination Address (accept) filter number %u.\n", filters.nacceptdst + 1); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, pref, &(filters.acceptdst[filters.nacceptdst])) <= 0) { + printf("Error in IPv6 Source Address (accept) filter number %u.\n", filters.nacceptdst + 1); + exit(EXIT_FAILURE); + } + + if ((charptr = strtok_r(NULL, " ", &lasts)) == NULL) { + filters.acceptdstlen[filters.nacceptdst] = 128; + } + else { + filters.acceptdstlen[filters.nacceptdst] = atoi(charptr); + + if (filters.acceptdstlen[filters.nacceptdst] > 128) { + printf("Length error in IPv6 Source Address (accept) filter number %u.\n", filters.nacceptdst + 1); + exit(EXIT_FAILURE); + } + } + + sanitize_ipv6_prefix(&(filters.acceptdst[filters.nacceptdst]), filters.acceptdstlen[filters.nacceptdst]); + (filters.nacceptdst)++; + filters.acceptfilters_f = 1; + break; + + case 'B': /* Link-layer Source Address (accept) filter */ + if (filters.nacceptlinksrc > MAX_ACCEPT_LINK_SRC) { + puts("Too many link-later Source Address (accept) filters."); + exit(EXIT_FAILURE); + } + + if (ether_pton(optarg, &(filters.acceptlinksrc[filters.nacceptlinksrc]), sizeof(struct ether_addr)) == 0) { + printf("Error in link-layer Source Address (accept) filter number %u.\n", filters.nacceptlinksrc + 1); + exit(EXIT_FAILURE); + } + + (filters.nacceptlinksrc)++; + filters.acceptfilters_f = 1; + break; + + case 'G': /* Link Destination Address (accept) filter */ + if (filters.nacceptlinkdst > MAX_ACCEPT_LINK_DST) { + puts("Too many link-layer Destination Address (accept) filters."); + exit(EXIT_FAILURE); + } + + if (ether_pton(optarg, &(filters.acceptlinkdst[filters.nacceptlinkdst]), sizeof(struct ether_addr)) == 0) { + printf("Error in link-layer Destination Address (accept) filter number %u.\n", + filters.nacceptlinkdst + 1); + exit(EXIT_FAILURE); + } + + (filters.nacceptlinkdst)++; + filters.acceptfilters_f = 1; + break; + + case 'F': /* Flood source addresses */ + nsources = atoi(optarg); + if (nsources == 0) { + puts("Invalid number of source addresses in option -F"); + exit(EXIT_FAILURE); + } + + floods_f = 1; + break; + + case 'T': /* Flood source ports */ + nports = atoi(optarg); + + if (nports == 0) { + puts("Invalid number of source ports in option -T"); + exit(EXIT_FAILURE); + } + + floodp_f = 1; + break; + + case 'l': /* "Loop mode */ + loop_f = 1; + break; + + case 'r': + if (Strnlen(optarg, LINE_BUFFER_SIZE - 1) >= (LINE_BUFFER_SIZE - 1)) { + puts("tcp6: -r option is too long"); + exit(EXIT_FAILURE); + } + + sscanf(optarg, "%lu%s", &rate, line); + line[LINE_BUFFER_SIZE - 1] = 0; + + if (strncmp(line, "pps", 3) == 0) + pps_f = 1; + else if (strncmp(line, "bps", 3) == 0) + bps_f = 1; + else { + puts("tcp6: Unknown unit of for the rate limit ('-r' option). Unit should be 'bps' or 'pps'"); + exit(EXIT_FAILURE); + } + + break; + + case 'z': /* Sleep option */ + nsleep = atoi(optarg); + if (nsleep == 0) { + puts("Invalid number of seconds in '-z' option"); + exit(EXIT_FAILURE); + } + + sleep_f = 1; + break; + + case 'L': /* "Listen mode */ + listen_f = 1; + break; + + case 'p': /* Probe mode */ + if (strncmp(optarg, "dump", MAX_CMDLINE_OPT_LEN) == 0) { + probemode = PROBE_DUMP; + } + else if (strncmp(optarg, "script", MAX_CMDLINE_OPT_LEN) == 0) { + probemode = PROBE_SCRIPT; + } + else { + puts("Error: Unknown open mode in '-Y' option"); + exit(EXIT_FAILURE); + } + + probemode_f = 1; + break; + + case 'x': /* Number of retrnasmissions */ + retrans = atoi(optarg); + retrans_f = 1; + break; + + case 'v': /* Be verbose */ + (idata.verbose_f)++; + break; + + case 'h': /* Help */ + print_help(); + exit(EXIT_FAILURE); + break; + + default: + usage(); + exit(EXIT_FAILURE); + break; + + } /* switch */ + } /* while(getopt) */ + + if (geteuid()) { + puts("tcp6 needs root privileges to run."); + exit(EXIT_FAILURE); + } + + srandom(time(NULL)); + + /* + If the flood option ("-F") has been specified, but no prefix has been specified, + assume a /64 prefix. + */ + if (floods_f && !idata.srcprefix_f) { + idata.srcpreflen = 64; + } + + if (!(idata.dstaddr_f) && !listen_f) { /* Must specify IPv6 Destination Address if listening mode not used */ + puts("IPv6 Destination Address not specified (and listening mode not selected)"); + exit(EXIT_FAILURE); + } + + if (rhbytes_f && data_f) { + puts("Cannot set '--data' and '--payload-size' at the same time"); + exit(EXIT_FAILURE); + } + + if (!idata.iface_f) { + if (idata.dstaddr_f && IN6_IS_ADDR_LINKLOCAL(&(idata.dstaddr))) { + puts("Must specify a network interface for link-local destinations"); + exit(EXIT_FAILURE); + } + else if (listen_f) { + puts("Must specify a network interface when employing the 'listenging' mode"); + exit(EXIT_FAILURE); + } + } + + if (load_dst_and_pcap(&idata, (idata.dstaddr_f ? LOAD_SRC_NXT_HOP : LOAD_PCAP_ONLY)) == FAILURE) { + puts("Error while learning Source Address and Next Hop"); + exit(EXIT_FAILURE); + } + + release_privileges(); + + if (data_f) { + data[datalen] = 0; + + if (!string_escapes(data, &datalen, DATA_BUFFER_LEN - 1)) { + puts("Error in data string option ('-Z')"); + exit(EXIT_FAILURE); + } + + data[datalen] = 0; + } + + if (!floods_f) + nsources = 1; + + if (!floodp_f) + nports = 1; + + if (!sleep_f) + nsleep = 1; + + if (sleep_f && (pps_f || bps_f)) { + puts("Cannot specify a rate-limit (-r) and a sleep time at the same time"); + exit(EXIT_FAILURE); + } + + if (pps_f && bps_f) { + puts("Cannot specify a rate-limit in bps and pps at the same time"); + exit(EXIT_FAILURE); + } + + if (pps_f) { + if (rate < 1) + rate = 1; + + pktinterval = 1000000 / rate; + } + + if (bps_f) { + packetsize = MIN_IPV6_HLEN + sizeof(struct tcp_hdr) + rhbytes; + + for (i = 0; i < ndstopthdr; i++) + packetsize += dstopthdrlen[i]; + + for (i = 0; i < ndstoptuhdr; i++) + packetsize += dstoptuhdrlen[i]; + + for (i = 0; i < nhbhopthdr; i++) + packetsize += hbhopthdrlen[i]; + + if (idata.fragh_f) + packetsize += sizeof(struct ip6_frag); + + if (rate == 0 || ((packetsize * 8) / rate) <= 0) + pktinterval = 1000000; + else + pktinterval = ((packetsize * 8) / rate) * 1000000; + } + + /* We Default to 1000 pps */ + if (!pps_f && !bps_f) { + rate = 1000; + pktinterval = 1000000 / rate; + } + + if (!idata.fragh_f && dstoptuhdr_f) { + puts("Dst. Options Header (Unfragmentable Part) set, but Fragmentation not specified"); + exit(EXIT_FAILURE); + } + + /* + * If we are going to send packets to a specified target, we must set some default values + */ + if (idata.dstaddr_f) { + if (!tcpflags_auto_f && !tcpflags_f && !tcpopen_f && !tcpclose_f) + tcpflags = tcpflags | TH_ACK; + + if (!tcpack_f && (tcpflags & TH_ACK)) + tcpack = random(); + + if (!tcpseq_f) + tcpseq = random(); + + if (srcport_f) { + if (srcportrnd_f) { + randomize_port(&srcport, srcport, srcportpref); + } + } + else { + srcport = random(); + } + + if (dstport_f) { + if (dstportrnd_f) { + randomize_port(&dstport, dstport, dstportpref); + } + } + else { + dstport = random(); + } + + if (!tcpurg_f) + tcpurg = 0; + } + + /* By default, we randomize the TCP Window */ + if (!tcpwin_f) + tcpwin = ((uint16_t)random() + 1500) & (uint16_t)0x7f00; + + if (!rhbytes_f) + rhbytes = 0; + + if (idata.verbose_f) { + print_attack_info(&idata); + } + + /* + Set filter for IPv6 packets (find_ipv6_router() set its own filter fore receiving RAs) + */ + + if (pcap_compile(idata.pfd, &pcap_filter, PCAP_TCPIPV6_NS_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1) { + printf("pcap_compile(): %s", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } + + if (pcap_setfilter(idata.pfd, &pcap_filter) == -1) { + printf("pcap_setfilter(): %s", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } + + pcap_freecode(&pcap_filter); + + /* Set initial contents of the attack packet */ + init_packet_data(&idata); + addr_key = random(); + + if (sleep_f) + pktinterval = (nsleep * 1000000) / (nsources * nports); + + timeout.tv_sec = pktinterval / 1000000; + timeout.tv_usec = pktinterval % 1000000; + stimeout = timeout; + + if (window_f) { + if (window == WIN_MODULATE && !winmodulate_f) { + win1_size = WIN_MODULATE_CLOSED_SIZE; + time1_len = WIN_MODULATE_CLOSED_LEN; + win2_size = WIN_MODULATE_OPEN_SIZE; + time2_len = WIN_MODULATE_OPEN_LEN; + } + } + + if (window_f && window == WIN_MODULATE) { + if (gettimeofday(&wmtimeout, NULL) == -1) { + if (idata.verbose_f) + perror("tcp6"); + + exit(EXIT_FAILURE); + } + + tcpwinm = win1_size; + } + + if (probemode_f) { + end_f = 0; + + if (dstport_f) { + if (dstportrnd_f) { + randomize_port(&dstport, dstport, dstportpref); + } + } + else { + dstport = 80; + } + + if (srcport_f) { + if (srcportrnd_f) { + randomize_port(&srcport, srcport, srcportpref); + } + } + else { + srcport = 50000 + random() % 15000; /* We select ports from the "high ports" range */ + } + + if (!rto_f) + rto = 1; + + if (!retrans_f) + retrans = 0; + + retr = 0; + retrans++; + + FD_ZERO(&sset); + FD_SET(idata.fd, &sset); + + lastprobe.tv_sec = 0; + lastprobe.tv_usec = 0; + + while (!end_f) { + if (gettimeofday(&curtime, NULL) == -1) { + if (idata.verbose_f) + perror("tcp6"); + + exit(EXIT_FAILURE); + } + + if (is_time_elapsed(&curtime, &lastprobe, rto * 1000000) && retr < retrans) { + retr++; + lastprobe = curtime; + send_packet(&idata, NULL, NULL); + } + + if (is_time_elapsed(&curtime, &lastprobe, rto * 1000000) && retr >= retrans) { + end_f = 1; + break; + } + + rset = sset; + timeout.tv_usec = 0; + timeout.tv_sec = (rto < 1) ? rto : 1; + + if ((sel = select(idata.fd + 1, &rset, NULL, NULL, &timeout)) == -1) { + if (errno == EINTR) { + continue; + } + else { + puts("Error in select()"); + exit(EXIT_FAILURE); + } + } #if !defined(sun) && !defined(__sun) && !defined(__linux__) - if(sel && FD_ISSET(idata.fd, &rset)){ + if (sel && FD_ISSET(idata.fd, &rset)) { #else - if(TRUE){ + if (TRUE) { #endif - /* Read a packet */ - - if((r=pcap_next_ex(idata.pfd, &pkthdr, &pktdata)) == -1){ - printf("pcap_next_ex(): %s", pcap_geterr(idata.pfd)); - exit(EXIT_FAILURE); - } - else if(r == 1 && pktdata != NULL){ - pkt_ether = (struct ether_header *) pktdata; - pkt_ipv6 = (struct ip6_hdr *)((char *) pkt_ether + idata.linkhsize); - pkt_tcp= (struct tcp_hdr *) ( (char *) pkt_ipv6 + MIN_IPV6_HLEN); - pkt_ns= (struct nd_neighbor_solicit *) ( (char *) pkt_ipv6 + MIN_IPV6_HLEN); - pkt_end = (unsigned char *) pktdata + pkthdr->caplen; - pkt_tcp_flags= pkt_tcp->th_flags; - - /* Check that we are able to look into the IPv6 header */ - if( (pkt_end - pktdata) < (idata.linkhsize + MIN_IPV6_HLEN)) - continue; - - if(is_eq_in6_addr(&(pkt_ipv6->ip6_src), &(idata.srcaddr))){ - continue; - } - - if(!is_eq_in6_addr(&(pkt_ipv6->ip6_dst), &(idata.srcaddr))){ - continue; - } - - if(pkt_tcp->th_sport != htons(dstport)){ - continue; - } - - if(pkt_tcp->th_dport != htons(srcport)){ - continue; - } - - /* The TCP checksum must be valid */ - if(in_chksum(pkt_ipv6, pkt_tcp, pkt_end-((unsigned char *)pkt_tcp), IPPROTO_TCP) != 0) - continue; - - printf("RESPONSE:TCP6:%s%s%s%s%s%s:\n", ((pkt_tcp_flags & TH_FIN)?"F":""), \ - ((pkt_tcp_flags & TH_SYN)?"S":""), \ - ((pkt_tcp_flags & TH_RST)?"R":""), ((pkt_tcp_flags & TH_PUSH)?"P":""),\ - ((pkt_tcp_flags & TH_ACK)?"A":""), ((pkt_tcp_flags & TH_URG)?"U":"")); - - exit(EXIT_SUCCESS); - } - } - } - - puts("RESPONSE:TIMEOUT:"); - exit(EXIT_SUCCESS); - } - - - /* Fire a TCP segment if an IPv6 Destination Address was specified */ - if(!listen_f && idata.dstaddr_f){ - - stimeout.tv_sec= pktinterval / 1000000; - stimeout.tv_usec= pktinterval % 1000000; - - if(loop_f || floods_f || floodp_f){ - if(idata.verbose_f){ - if(sleep_f){ - printf("Sending TCP segments every %u second%s...\n", nsleep, \ - ((nsleep>1)?"s":"")); - } - else if(bps_f){ - printf("Sending TCP segments at %lu pps...\n", rate); - } - else{ - printf("Sending TCP segments at %lu pps%s...\n", rate, (pps_f)?"":" (default)"); - } - } - } - - do{ - send_packet(&idata, NULL, NULL); - - timeout= stimeout; - - if(loop_f && (sel=select(0, NULL, NULL, NULL, &timeout)) == -1){ - if(errno == EINTR){ - continue; - } - else{ - puts("Error in select()"); - exit(EXIT_FAILURE); - } - } - }while(loop_f); - - if(idata.verbose_f) - puts("Initial attack packet(s) sent successfully."); - - exit(EXIT_SUCCESS); - } - else if(listen_f){ - FD_ZERO(&sset); - FD_SET(idata.fd, &sset); - - if(idata.verbose_f){ - print_filters(&idata, &filters); - puts("Listening to incoming IPv6 messages..."); - } - - while(listen_f){ - rset= sset; - - timeout= stimeout; + /* Read a packet */ + + if ((r = pcap_next_ex(idata.pfd, &pkthdr, &pktdata)) == -1) { + printf("pcap_next_ex(): %s", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } + else if (r == 1 && pktdata != NULL) { + pkt_ether = (struct ether_header *)pktdata; + pkt_ipv6 = (struct ip6_hdr *)((char *)pkt_ether + idata.linkhsize); + pkt_tcp = (struct tcp_hdr *)((char *)pkt_ipv6 + MIN_IPV6_HLEN); + pkt_ns = (struct nd_neighbor_solicit *)((char *)pkt_ipv6 + MIN_IPV6_HLEN); + pkt_end = (unsigned char *)pktdata + pkthdr->caplen; + pkt_tcp_flags = pkt_tcp->th_flags; + + /* Check that we are able to look into the IPv6 header */ + if ((pkt_end - pktdata) < (idata.linkhsize + MIN_IPV6_HLEN)) + continue; + + if (is_eq_in6_addr(&(pkt_ipv6->ip6_src), &(idata.srcaddr))) { + continue; + } + + if (!is_eq_in6_addr(&(pkt_ipv6->ip6_dst), &(idata.srcaddr))) { + continue; + } + + if (pkt_tcp->th_sport != htons(dstport)) { + continue; + } + + if (pkt_tcp->th_dport != htons(srcport)) { + continue; + } + + /* The TCP checksum must be valid */ + if (in_chksum(pkt_ipv6, pkt_tcp, pkt_end - ((unsigned char *)pkt_tcp), IPPROTO_TCP) != 0) + continue; + + printf("RESPONSE:TCP6:%s%s%s%s%s%s:\n", ((pkt_tcp_flags & TH_FIN) ? "F" : ""), + ((pkt_tcp_flags & TH_SYN) ? "S" : ""), ((pkt_tcp_flags & TH_RST) ? "R" : ""), + ((pkt_tcp_flags & TH_PUSH) ? "P" : ""), ((pkt_tcp_flags & TH_ACK) ? "A" : ""), + ((pkt_tcp_flags & TH_URG) ? "U" : "")); + + exit(EXIT_SUCCESS); + } + } + } + + puts("RESPONSE:TIMEOUT:"); + exit(EXIT_SUCCESS); + } + + /* Fire a TCP segment if an IPv6 Destination Address was specified */ + if (!listen_f && idata.dstaddr_f) { + + stimeout.tv_sec = pktinterval / 1000000; + stimeout.tv_usec = pktinterval % 1000000; + + if (loop_f || floods_f || floodp_f) { + if (idata.verbose_f) { + if (sleep_f) { + printf("Sending TCP segments every %u second%s...\n", nsleep, ((nsleep > 1) ? "s" : "")); + } + else if (bps_f) { + printf("Sending TCP segments at %lu pps...\n", rate); + } + else { + printf("Sending TCP segments at %lu pps%s...\n", rate, (pps_f) ? "" : " (default)"); + } + } + } + + do { + send_packet(&idata, NULL, NULL); + + timeout = stimeout; + + if (loop_f && (sel = select(0, NULL, NULL, NULL, &timeout)) == -1) { + if (errno == EINTR) { + continue; + } + else { + puts("Error in select()"); + exit(EXIT_FAILURE); + } + } + } while (loop_f); + + if (idata.verbose_f) + puts("Initial attack packet(s) sent successfully."); + + exit(EXIT_SUCCESS); + } + else if (listen_f) { + FD_ZERO(&sset); + FD_SET(idata.fd, &sset); + + if (idata.verbose_f) { + print_filters(&idata, &filters); + puts("Listening to incoming IPv6 messages..."); + } + + while (listen_f) { + rset = sset; + + timeout = stimeout; #if !defined(sun) && !defined(__sun) && !defined(__linux__) - if((sel=select(idata.fd+1, &rset, NULL, NULL, ((floods_f || floodp_f) && !donesending_f)?(&timeout):NULL)) == -1){ + if ((sel = select(idata.fd + 1, &rset, NULL, NULL, + ((floods_f || floodp_f) && !donesending_f) ? (&timeout) : NULL)) == -1) { #else - timeout.tv_usec=1000; - timeout.tv_sec= 0; - if((sel=select(idata.fd+1, &rset, NULL, NULL, &timeout)) == -1){ + timeout.tv_usec = 1000; + timeout.tv_sec = 0; + if ((sel = select(idata.fd + 1, &rset, NULL, NULL, &timeout)) == -1) { #endif - if(errno == EINTR){ - continue; - } - else{ - puts("Error in select()"); - exit(EXIT_FAILURE); - } - } - - /* If there are some bits set, we need to check whether it's time to send packets */ + if (errno == EINTR) { + continue; + } + else { + puts("Error in select()"); + exit(EXIT_FAILURE); + } + } + + /* If there are some bits set, we need to check whether it's time to send packets */ #if !defined(sun) && !defined(__sun) && !defined(__linux__) - if(sel){ + if (sel) { #else - if(TRUE){ + if (TRUE) { #endif - if(gettimeofday(&curtime, NULL) == -1){ - if(idata.verbose_f) - perror("tcp6"); - - exit(EXIT_FAILURE); - } - - if(window == WIN_MODULATE){ - if(tcpwinm == win1_size){ - if( (curtime.tv_sec - wmtimeout.tv_sec) >= time1_len){ - wmtimeout= curtime; - tcpwinm = win2_size; - } - } - else{ - if( (curtime.tv_sec - wmtimeout.tv_sec) >= time2_len){ - wmtimeout= curtime; - tcpwinm = win1_size; - } - } - } - } + if (gettimeofday(&curtime, NULL) == -1) { + if (idata.verbose_f) + perror("tcp6"); + + exit(EXIT_FAILURE); + } + + if (window == WIN_MODULATE) { + if (tcpwinm == win1_size) { + if ((curtime.tv_sec - wmtimeout.tv_sec) >= time1_len) { + wmtimeout = curtime; + tcpwinm = win2_size; + } + } + else { + if ((curtime.tv_sec - wmtimeout.tv_sec) >= time2_len) { + wmtimeout = curtime; + tcpwinm = win1_size; + } + } + } + } #if !defined(sun) && !defined(__sun) && !defined(__linux__) - if(sel && FD_ISSET(idata.fd, &rset)){ + if (sel && FD_ISSET(idata.fd, &rset)) { #else - if(TRUE){ + if (TRUE) { #endif - /* Read a packet */ - if((r=pcap_next_ex(idata.pfd, &pkthdr, &pktdata)) == -1){ - printf("pcap_next_ex(): %s", pcap_geterr(idata.pfd)); - exit(EXIT_FAILURE); - } - else if(r == 1 && pktdata != NULL){ - pkt_ether = (struct ether_header *) pktdata; - pkt_ipv6 = (struct ip6_hdr *)((char *) pkt_ether + idata.linkhsize); - pkt_tcp= (struct tcp_hdr *) ( (char *) pkt_ipv6 + MIN_IPV6_HLEN); - pkt_ns= (struct nd_neighbor_solicit *) ( (char *) pkt_ipv6 + MIN_IPV6_HLEN); - pkt_end = (unsigned char *) pktdata + pkthdr->caplen; - - /* Check that we are able to look into the IPv6 header */ - if( (pkt_end - pktdata) < (idata.linkhsize + MIN_IPV6_HLEN)) - continue; - - accepted_f=0; - - if(idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK)){ - if(filters.nblocklinksrc){ - if(match_ether(filters.blocklinksrc, filters.nblocklinksrc, &(pkt_ether->src))){ - if(idata.verbose_f>1) - print_filter_result(&idata, pktdata, BLOCKED); - - continue; - } - } - - if(filters.nblocklinkdst){ - if(match_ether(filters.blocklinkdst, filters.nblocklinkdst, &(pkt_ether->dst))){ - if(idata.verbose_f>1) - print_filter_result(&idata, pktdata, BLOCKED); - - continue; - } - } - } - - if(filters.nblocksrc){ - if(match_ipv6(filters.blocksrc, filters.blocksrclen, filters.nblocksrc, &(pkt_ipv6->ip6_src))){ - if(idata.verbose_f>1) - print_filter_result(&idata, pktdata, BLOCKED); - - continue; - } - } - - if(filters.nblockdst){ - if(match_ipv6(filters.blockdst, filters.blockdstlen, filters.nblockdst, &(pkt_ipv6->ip6_dst))){ - if(idata.verbose_f>1) - print_filter_result(&idata, pktdata, BLOCKED); - - continue; - } - } - - if(idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK)){ - if(filters.nacceptlinksrc){ - if(match_ether(filters.acceptlinksrc, filters.nacceptlinksrc, &(pkt_ether->src))) - accepted_f=1; - } - - if(filters.nacceptlinkdst && !accepted_f){ - if(match_ether(filters.acceptlinkdst, filters.nacceptlinkdst, &(pkt_ether->dst))) - accepted_f= 1; - } - } - - if(filters.nacceptsrc && !accepted_f){ - if(match_ipv6(filters.acceptsrc, filters.acceptsrclen, filters.nacceptsrc, &(pkt_ipv6->ip6_src))) - accepted_f= 1; - } - - if(filters.nacceptdst && !accepted_f){ - if(match_ipv6(filters.acceptdst, filters.acceptdstlen, filters.nacceptdst, &(pkt_ipv6->ip6_dst))) - accepted_f=1; - } - - if(filters.acceptfilters_f && !accepted_f){ - if(idata.verbose_f>1) - print_filter_result(&idata, pktdata, BLOCKED); - - continue; - } - - if(idata.verbose_f>1) - print_filter_result(&idata, pktdata, ACCEPTED); - - if(pkt_ipv6->ip6_nxt == IPPROTO_TCP){ - /* Check that we are able to look into the TCP header */ - if( (pkt_end - pktdata) < (idata.linkhsize + MIN_IPV6_HLEN + sizeof(struct tcp_hdr))){ - continue; - } - - if(idata.dstaddr_f){ - if(!floods_f){ - /* Discard our own packets */ - if(is_eq_in6_addr(&(pkt_ipv6->ip6_src), &(idata.srcaddr))){ - continue; - } - - if(!is_eq_in6_addr(&(pkt_ipv6->ip6_dst), &(idata.srcaddr))){ - continue; - } - } - else{ - /* Discard our own packets */ - if(!is_eq_in6_addr(&(pkt_ipv6->ip6_src), &(idata.dstaddr))){ - continue; - } - - if(useaddrkey_f){ - if( (ntohl(pkt_ipv6->ip6_src.s6_addr32[2]) & 0x0000ffff) == ( (uint16_t)(ntohl(pkt_ipv6->ip6_src.s6_addr32[2])>>16) ^ addr_key) && \ - (ntohl(pkt_ipv6->ip6_src.s6_addr32[3]) & 0x0000ffff) == ( (uint16_t)(ntohl(pkt_ipv6->ip6_src.s6_addr32[3])>>16) ^ addr_key)){ - continue; - } - - if( (ntohl(pkt_ipv6->ip6_dst.s6_addr32[2]) & 0x0000ffff) != ((uint16_t)(ntohl(pkt_ipv6->ip6_dst.s6_addr32[2]) >> 16) ^ addr_key) || \ - (ntohl(pkt_ipv6->ip6_dst.s6_addr32[3]) & 0x0000ffff) != ((uint16_t)(ntohl(pkt_ipv6->ip6_dst.s6_addr32[3])>>16) ^ addr_key)){ - continue; - } - } - } - - /* The TCP checksum must be valid */ - if(in_chksum(pkt_ipv6, pkt_tcp, pkt_end-((unsigned char *)pkt_tcp), IPPROTO_TCP) != 0) - continue; - - if(pkt_tcp->th_sport != htons(dstport)){ - continue; - } - - if(!floodp_f && pkt_tcp->th_dport != htons(srcport)){ - continue; - } - } - - /* Send a TCP segment */ - send_packet(&idata, pktdata, pkthdr); - } - else if(pkt_ipv6->ip6_nxt == IPPROTO_ICMPV6){ - /* Check that we are able to look into the NS header */ - if( (pkt_end - pktdata) < (idata.linkhsize + MIN_IPV6_HLEN + sizeof(struct nd_neighbor_solicit))){ - continue; - } - - if(idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK)){ - if(floods_f){ - if(useaddrkey_f){ - if( (ntohl(pkt_ns->nd_ns_target.s6_addr32[2]) & 0x0000ffff) != ( (ntohl(pkt_ns->nd_ns_target.s6_addr32[2]) >>16) ^ addr_key) || \ - (ntohl(pkt_ns->nd_ns_target.s6_addr32[3]) & 0x0000ffff) != ( (ntohl(pkt_ns->nd_ns_target.s6_addr32[3]) >>16) ^ addr_key)){ - continue; - } - } - - /* Check that the target address belongs to the prefix from which we are sending packets */ - if(!match_ipv6(&(idata.srcaddr), &idata.srcpreflen, 1, &(pkt_ns->nd_ns_target))){ - continue; - } - } - else{ - if(!is_eq_in6_addr( &(pkt_ns->nd_ns_target), &(idata.srcaddr)) ){ - continue; - } - } - - if(send_neighbor_advert(&idata, idata.pfd, pktdata) == -1){ - puts("Error sending Neighbor Advertisement"); - exit(EXIT_FAILURE); - } - } - } - } - } - - if(idata.dstaddr_f && !donesending_f && is_time_elapsed(&curtime, &lastprobe, pktinterval)){ - lastprobe= curtime; - send_packet(&idata, NULL, NULL); - } - } - - exit(EXIT_SUCCESS); - } - - if(!(idata.dstaddr_f) && !listen_f){ - puts("Error: Nothing to send! (Destination Address left unspecified, and not using listening mode)"); - exit(EXIT_FAILURE); - } - - exit(EXIT_SUCCESS); + /* Read a packet */ + if ((r = pcap_next_ex(idata.pfd, &pkthdr, &pktdata)) == -1) { + printf("pcap_next_ex(): %s", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } + else if (r == 1 && pktdata != NULL) { + pkt_ether = (struct ether_header *)pktdata; + pkt_ipv6 = (struct ip6_hdr *)((char *)pkt_ether + idata.linkhsize); + pkt_tcp = (struct tcp_hdr *)((char *)pkt_ipv6 + MIN_IPV6_HLEN); + pkt_ns = (struct nd_neighbor_solicit *)((char *)pkt_ipv6 + MIN_IPV6_HLEN); + pkt_end = (unsigned char *)pktdata + pkthdr->caplen; + + /* Check that we are able to look into the IPv6 header */ + if ((pkt_end - pktdata) < (idata.linkhsize + MIN_IPV6_HLEN)) + continue; + + accepted_f = 0; + + if (idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK)) { + if (filters.nblocklinksrc) { + if (match_ether(filters.blocklinksrc, filters.nblocklinksrc, &(pkt_ether->src))) { + if (idata.verbose_f > 1) + print_filter_result(&idata, pktdata, BLOCKED); + + continue; + } + } + + if (filters.nblocklinkdst) { + if (match_ether(filters.blocklinkdst, filters.nblocklinkdst, &(pkt_ether->dst))) { + if (idata.verbose_f > 1) + print_filter_result(&idata, pktdata, BLOCKED); + + continue; + } + } + } + + if (filters.nblocksrc) { + if (match_ipv6(filters.blocksrc, filters.blocksrclen, filters.nblocksrc, + &(pkt_ipv6->ip6_src))) { + if (idata.verbose_f > 1) + print_filter_result(&idata, pktdata, BLOCKED); + + continue; + } + } + + if (filters.nblockdst) { + if (match_ipv6(filters.blockdst, filters.blockdstlen, filters.nblockdst, + &(pkt_ipv6->ip6_dst))) { + if (idata.verbose_f > 1) + print_filter_result(&idata, pktdata, BLOCKED); + + continue; + } + } + + if (idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK)) { + if (filters.nacceptlinksrc) { + if (match_ether(filters.acceptlinksrc, filters.nacceptlinksrc, &(pkt_ether->src))) + accepted_f = 1; + } + + if (filters.nacceptlinkdst && !accepted_f) { + if (match_ether(filters.acceptlinkdst, filters.nacceptlinkdst, &(pkt_ether->dst))) + accepted_f = 1; + } + } + + if (filters.nacceptsrc && !accepted_f) { + if (match_ipv6(filters.acceptsrc, filters.acceptsrclen, filters.nacceptsrc, + &(pkt_ipv6->ip6_src))) + accepted_f = 1; + } + + if (filters.nacceptdst && !accepted_f) { + if (match_ipv6(filters.acceptdst, filters.acceptdstlen, filters.nacceptdst, + &(pkt_ipv6->ip6_dst))) + accepted_f = 1; + } + + if (filters.acceptfilters_f && !accepted_f) { + if (idata.verbose_f > 1) + print_filter_result(&idata, pktdata, BLOCKED); + + continue; + } + + if (idata.verbose_f > 1) + print_filter_result(&idata, pktdata, ACCEPTED); + + if (pkt_ipv6->ip6_nxt == IPPROTO_TCP) { + /* Check that we are able to look into the TCP header */ + if ((pkt_end - pktdata) < (idata.linkhsize + MIN_IPV6_HLEN + sizeof(struct tcp_hdr))) { + continue; + } + + if (idata.dstaddr_f) { + if (!floods_f) { + /* Discard our own packets */ + if (is_eq_in6_addr(&(pkt_ipv6->ip6_src), &(idata.srcaddr))) { + continue; + } + + if (!is_eq_in6_addr(&(pkt_ipv6->ip6_dst), &(idata.srcaddr))) { + continue; + } + } + else { + /* Discard our own packets */ + if (!is_eq_in6_addr(&(pkt_ipv6->ip6_src), &(idata.dstaddr))) { + continue; + } + + if (useaddrkey_f) { + if ((ntohl(pkt_ipv6->ip6_src.s6_addr32[2]) & 0x0000ffff) == + ((uint16_t)(ntohl(pkt_ipv6->ip6_src.s6_addr32[2]) >> 16) ^ addr_key) && + (ntohl(pkt_ipv6->ip6_src.s6_addr32[3]) & 0x0000ffff) == + ((uint16_t)(ntohl(pkt_ipv6->ip6_src.s6_addr32[3]) >> 16) ^ addr_key)) { + continue; + } + + if ((ntohl(pkt_ipv6->ip6_dst.s6_addr32[2]) & 0x0000ffff) != + ((uint16_t)(ntohl(pkt_ipv6->ip6_dst.s6_addr32[2]) >> 16) ^ addr_key) || + (ntohl(pkt_ipv6->ip6_dst.s6_addr32[3]) & 0x0000ffff) != + ((uint16_t)(ntohl(pkt_ipv6->ip6_dst.s6_addr32[3]) >> 16) ^ addr_key)) { + continue; + } + } + } + + /* The TCP checksum must be valid */ + if (in_chksum(pkt_ipv6, pkt_tcp, pkt_end - ((unsigned char *)pkt_tcp), IPPROTO_TCP) != 0) + continue; + + if (pkt_tcp->th_sport != htons(dstport)) { + continue; + } + + if (!floodp_f && pkt_tcp->th_dport != htons(srcport)) { + continue; + } + } + + /* Send a TCP segment */ + send_packet(&idata, pktdata, pkthdr); + } + else if (pkt_ipv6->ip6_nxt == IPPROTO_ICMPV6) { + /* Check that we are able to look into the NS header */ + if ((pkt_end - pktdata) < + (idata.linkhsize + MIN_IPV6_HLEN + sizeof(struct nd_neighbor_solicit))) { + continue; + } + + if (idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK)) { + if (floods_f) { + if (useaddrkey_f) { + if ((ntohl(pkt_ns->nd_ns_target.s6_addr32[2]) & 0x0000ffff) != + ((ntohl(pkt_ns->nd_ns_target.s6_addr32[2]) >> 16) ^ addr_key) || + (ntohl(pkt_ns->nd_ns_target.s6_addr32[3]) & 0x0000ffff) != + ((ntohl(pkt_ns->nd_ns_target.s6_addr32[3]) >> 16) ^ addr_key)) { + continue; + } + } + + /* Check that the target address belongs to the prefix from which we are sending packets + */ + if (!match_ipv6(&(idata.srcaddr), &idata.srcpreflen, 1, &(pkt_ns->nd_ns_target))) { + continue; + } + } + else { + if (!is_eq_in6_addr(&(pkt_ns->nd_ns_target), &(idata.srcaddr))) { + continue; + } + } + + if (send_neighbor_advert(&idata, idata.pfd, pktdata) == -1) { + puts("Error sending Neighbor Advertisement"); + exit(EXIT_FAILURE); + } + } + } + } + } + + if (idata.dstaddr_f && !donesending_f && is_time_elapsed(&curtime, &lastprobe, pktinterval)) { + lastprobe = curtime; + send_packet(&idata, NULL, NULL); + } + } + + exit(EXIT_SUCCESS); + } + + if (!(idata.dstaddr_f) && !listen_f) { + puts("Error: Nothing to send! (Destination Address left unspecified, and not using listening mode)"); + exit(EXIT_FAILURE); + } + + exit(EXIT_SUCCESS); } - - /* * Function: init_packet_data() * * Initialize the contents of the attack packet (Ethernet header, IPv6 Header, and ICMPv6 header) * that are expected to remain constant for the specified attack. */ -void init_packet_data(struct iface_data *idata){ - struct dlt_null *dlt_null; - ethernet= (struct ether_header *) buffer; - dlt_null= (struct dlt_null *) buffer; - v6buffer = buffer + idata->linkhsize; - ipv6 = (struct ip6_hdr *) v6buffer; - - if(idata->type == DLT_EN10MB){ - ethernet->ether_type = htons(ETHERTYPE_IPV6); - - if(!(idata->flags & IFACE_LOOPBACK)){ - ethernet->src = idata->hsrcaddr; - ethernet->dst = idata->hdstaddr; - } - } - else if(idata->type == DLT_NULL){ - dlt_null->family= PF_INET6; - } -#if defined (__OpenBSD__) - else if(idata->type == DLT_LOOP){ - dlt_null->family= htonl(PF_INET6); - } +void init_packet_data(struct iface_data *idata) { + struct dlt_null *dlt_null; + ethernet = (struct ether_header *)buffer; + dlt_null = (struct dlt_null *)buffer; + v6buffer = buffer + idata->linkhsize; + ipv6 = (struct ip6_hdr *)v6buffer; + + if (idata->type == DLT_EN10MB) { + ethernet->ether_type = htons(ETHERTYPE_IPV6); + + if (!(idata->flags & IFACE_LOOPBACK)) { + ethernet->src = idata->hsrcaddr; + ethernet->dst = idata->hdstaddr; + } + } + else if (idata->type == DLT_NULL) { + dlt_null->family = PF_INET6; + } +#if defined(__OpenBSD__) + else if (idata->type == DLT_LOOP) { + dlt_null->family = htonl(PF_INET6); + } #endif - ipv6->ip6_flow=0; - ipv6->ip6_vfc= 0x60; - ipv6->ip6_hlim= hoplimit; - ipv6->ip6_src= idata->srcaddr; - ipv6->ip6_dst= idata->dstaddr; - - prev_nh = (unsigned char *) &(ipv6->ip6_nxt); - - ptr = (unsigned char *) v6buffer + MIN_IPV6_HLEN; - - if(hbhopthdr_f){ - hbhopthdrs=0; - - while(hbhopthdrs < nhbhopthdr){ - if((ptr+ hbhopthdrlen[hbhopthdrs]) > (v6buffer+ idata->mtu)){ - puts("Packet too large while processing HBH Opt. Header"); - exit(EXIT_FAILURE); - } - - *prev_nh = IPPROTO_HOPOPTS; - prev_nh = ptr; - memcpy(ptr, hbhopthdr[hbhopthdrs], hbhopthdrlen[hbhopthdrs]); - ptr = ptr + hbhopthdrlen[hbhopthdrs]; - hbhopthdrs++; - } - } - - if(dstoptuhdr_f){ - dstoptuhdrs=0; - - while(dstoptuhdrs < ndstoptuhdr){ - if((ptr+ dstoptuhdrlen[dstoptuhdrs]) > (v6buffer+ idata->mtu)){ - puts("Packet too large while processing Dest. Opt. Header (Unfrag. Part)"); - exit(EXIT_FAILURE); - } - - *prev_nh = IPPROTO_DSTOPTS; - prev_nh = ptr; - memcpy(ptr, dstoptuhdr[dstoptuhdrs], dstoptuhdrlen[dstoptuhdrs]); - ptr = ptr + dstoptuhdrlen[dstoptuhdrs]; - dstoptuhdrs++; - } - } - - /* Everything that follows is the Fragmentable Part of the packet */ - fragpart = ptr; - - if(idata->fragh_f){ - /* Check that we are able to send the Unfragmentable Part, together with a - Fragment Header and a chunk data over our link layer - */ - if( (fragpart+sizeof(fraghdr)+nfrags) > (v6buffer+idata->mtu)){ - puts("Unfragmentable part too large for current MTU"); - exit(EXIT_FAILURE); - } - - /* We prepare a separete Fragment Header, but we do not include it in the packet to be sent. - This Fragment Header will be used (an assembled with the rest of the packet by the - send_packet() function. - */ - memset(&fraghdr, 0, FRAG_HDR_SIZE); - *prev_nh = IPPROTO_FRAGMENT; - prev_nh = (unsigned char *) &fraghdr; - } - - if(dstopthdr_f){ - dstopthdrs=0; - - while(dstopthdrs < ndstopthdr){ - if((ptr+ dstopthdrlen[dstopthdrs]) > (v6buffer+ idata->max_packet_size)){ - puts("Packet too large while processing Dest. Opt. Header (should be using the Frag. option?)"); - exit(EXIT_FAILURE); - } - - *prev_nh = IPPROTO_DSTOPTS; - prev_nh = ptr; - memcpy(ptr, dstopthdr[dstopthdrs], dstopthdrlen[dstopthdrs]); - ptr = ptr + dstopthdrlen[dstopthdrs]; - dstopthdrs++; - } - } - - - *prev_nh = IPPROTO_TCP; - - startofprefixes=ptr; + ipv6->ip6_flow = 0; + ipv6->ip6_vfc = 0x60; + ipv6->ip6_hlim = hoplimit; + ipv6->ip6_src = idata->srcaddr; + ipv6->ip6_dst = idata->dstaddr; + + prev_nh = (unsigned char *)&(ipv6->ip6_nxt); + + ptr = (unsigned char *)v6buffer + MIN_IPV6_HLEN; + + if (hbhopthdr_f) { + hbhopthdrs = 0; + + while (hbhopthdrs < nhbhopthdr) { + if ((ptr + hbhopthdrlen[hbhopthdrs]) > (v6buffer + idata->mtu)) { + puts("Packet too large while processing HBH Opt. Header"); + exit(EXIT_FAILURE); + } + + *prev_nh = IPPROTO_HOPOPTS; + prev_nh = ptr; + memcpy(ptr, hbhopthdr[hbhopthdrs], hbhopthdrlen[hbhopthdrs]); + ptr = ptr + hbhopthdrlen[hbhopthdrs]; + hbhopthdrs++; + } + } + + if (dstoptuhdr_f) { + dstoptuhdrs = 0; + + while (dstoptuhdrs < ndstoptuhdr) { + if ((ptr + dstoptuhdrlen[dstoptuhdrs]) > (v6buffer + idata->mtu)) { + puts("Packet too large while processing Dest. Opt. Header (Unfrag. Part)"); + exit(EXIT_FAILURE); + } + + *prev_nh = IPPROTO_DSTOPTS; + prev_nh = ptr; + memcpy(ptr, dstoptuhdr[dstoptuhdrs], dstoptuhdrlen[dstoptuhdrs]); + ptr = ptr + dstoptuhdrlen[dstoptuhdrs]; + dstoptuhdrs++; + } + } + + /* Everything that follows is the Fragmentable Part of the packet */ + fragpart = ptr; + + if (idata->fragh_f) { + /* Check that we are able to send the Unfragmentable Part, together with a + Fragment Header and a chunk data over our link layer + */ + if ((fragpart + sizeof(fraghdr) + nfrags) > (v6buffer + idata->mtu)) { + puts("Unfragmentable part too large for current MTU"); + exit(EXIT_FAILURE); + } + + /* We prepare a separete Fragment Header, but we do not include it in the packet to be sent. + This Fragment Header will be used (an assembled with the rest of the packet by the + send_packet() function. + */ + memset(&fraghdr, 0, FRAG_HDR_SIZE); + *prev_nh = IPPROTO_FRAGMENT; + prev_nh = (unsigned char *)&fraghdr; + } + + if (dstopthdr_f) { + dstopthdrs = 0; + + while (dstopthdrs < ndstopthdr) { + if ((ptr + dstopthdrlen[dstopthdrs]) > (v6buffer + idata->max_packet_size)) { + puts("Packet too large while processing Dest. Opt. Header (should be using the Frag. option?)"); + exit(EXIT_FAILURE); + } + + *prev_nh = IPPROTO_DSTOPTS; + prev_nh = ptr; + memcpy(ptr, dstopthdr[dstopthdrs], dstopthdrlen[dstopthdrs]); + ptr = ptr + dstopthdrlen[dstopthdrs]; + dstopthdrs++; + } + } + + *prev_nh = IPPROTO_TCP; + + startofprefixes = ptr; } - - /* * Function: send_packet() * * Initialize the remaining fields of the TCP segment, and send the attack packet(s). */ -void send_packet(struct iface_data *idata, const u_char *pktdata, struct pcap_pkthdr *pkthdr){ - static unsigned int sources=0, ports=0; - ptr=startofprefixes; - - startclose_f= 0; - senddata_f= 0; - - if(pktdata != NULL){ /* Sending a TCP segment in response to a received packet */ - pkt_ether = (struct ether_header *) pktdata; - pkt_ipv6 = (struct ip6_hdr *)((char *) pkt_ether + idata->linkhsize); - pkt_tcp= (struct tcp_hdr *)( (char *) pkt_ipv6 + sizeof(struct ip6_hdr)); - pkt_end = (unsigned char *) pktdata + pkthdr->caplen; - - /* The packet length is the minimum of what we capured, and what is specified in the - IPv6 Total Lenght field - */ - if( pkt_end > ((unsigned char *)pkt_ipv6 + sizeof(struct ip6_hdr) + ntohs(pkt_ipv6->ip6_plen)) ) - pkt_end = (unsigned char *)pkt_ipv6 + sizeof(struct ip6_hdr) + ntohs(pkt_ipv6->ip6_plen); - - - pkt_ipv6addr = &(pkt_ipv6->ip6_src); - - /* - We don't send any packets if the Source Address of the captured packet is the unspecified - address or a multicast address - */ - if(IN6_IS_ADDR_UNSPECIFIED(pkt_ipv6addr) || IN6_IS_ADDR_MULTICAST(pkt_ipv6addr)){ - return; - } - else{ - ipv6->ip6_dst = pkt_ipv6->ip6_src; - - if(idata->type == DLT_EN10MB && !(idata->flags & IFACE_LOOPBACK)) - ethernet->dst = pkt_ether->src; - } - - pkt_ipv6addr = &(pkt_ipv6->ip6_dst); - - /* - We do not send any packets if the Destination Address of the captured packet is the unspecified - address or a multicast address - */ - if(IN6_IS_ADDR_MULTICAST(pkt_ipv6addr) || IN6_IS_ADDR_MULTICAST(pkt_ipv6addr)){ - return; - } - else{ - ipv6->ip6_src = pkt_ipv6->ip6_dst; - - if(idata->type == DLT_EN10MB && !(idata->flags & IFACE_LOOPBACK)) - ethernet->src = pkt_ether->dst; - } - - - if( (ptr+sizeof(struct tcp_hdr)) > (v6buffer+ idata->max_packet_size)){ - puts("Packet Too Large while inserting TCP header"); - exit(EXIT_FAILURE); - } - - /* If we are setting the flags automatically, do not respond to RST segments */ - if((tcpflags_auto_f || tcpopen_f || tcpclose_f) && pkt_tcp->th_flags & TH_RST) - return; - - tcp = (struct tcp_hdr *) ptr; - memset(tcp, 0, sizeof(struct tcp_hdr)); - - tcp->th_sport= pkt_tcp->th_dport; - tcp->th_dport= pkt_tcp->th_sport; - - if(tcpseq_f) - tcp->th_seq= htonl(tcpseq); - else - tcp->th_seq = pkt_tcp->th_ack; - - if( pkt_tcp->th_flags & TH_SYN){ - if(tcpopen_f){ - if(tcpopen == OPEN_PASSIVE){ - /* If it is a pure SYN, respond with a SYN/ACK */ - if(!(pkt_tcp->th_flags & TH_ACK)){ - tcp->th_flags = tcp->th_flags | TH_SYN | TH_ACK; - tcp->th_seq= random(); - tcp->th_ack= htonl(ntohl(pkt_tcp->th_seq) + ((pkt_end - (unsigned char *)pkt_tcp) - (pkt_tcp->th_off << 2))); - tcp->th_ack= htonl(ntohl(tcp->th_ack) + ((pkt_tcp->th_flags & TH_FIN)?1:0) + \ - ((pkt_tcp->th_flags & TH_SYN)?1:0)); - } - } - else if(tcpopen == OPEN_SIMULTANEOUS){ - /* If it is a pure SYN, respond with a SYN */ - if(!(pkt_tcp->th_flags & TH_ACK)){ - tcp->th_flags = tcp->th_flags | TH_SYN; - tcp->th_seq= random(); - tcp->th_ack= 0; - } - else{ - /* If we receive a SYN/ACK (product of the above SYN), send a SYN/ACK */ - tcp->th_flags = tcp->th_flags | TH_SYN | TH_ACK; - tcp->th_seq= (pkt_tcp->th_ack) - (rhbytes + 1); - tcp->th_ack= htonl(ntohl(pkt_tcp->th_seq) + ((pkt_end - (unsigned char *)pkt_tcp) - (pkt_tcp->th_off << 2))); - tcp->th_ack= htonl(ntohl(tcp->th_ack) + ((pkt_tcp->th_flags & TH_FIN)?1:0) + \ - ((pkt_tcp->th_flags & TH_SYN)?1:0)); - - if(data_f) - senddata_f= 1; - } - } - else if(tcpopen == OPEN_ABORT){ - /* If we receive a SYN, send RST */ - tcp->th_flags = tcp->th_flags | TH_RST | TH_ACK; - if(pkt_tcp->th_flags & TH_ACK) - tcp->th_seq= pkt_tcp->th_ack; - else - tcp->th_seq= 0; - - tcp->th_ack= htonl(ntohl(pkt_tcp->th_seq) + ((pkt_end - (unsigned char *)pkt_tcp) - (pkt_tcp->th_off << 2))); - tcp->th_ack= htonl(ntohl(tcp->th_ack) + ((pkt_tcp->th_flags & TH_FIN)?1:0) + \ - ((pkt_tcp->th_flags & TH_SYN)?1:0)); - } - } - else{ - /* We have received a SYN/ACK */ - if(pkt_tcp->th_flags & TH_ACK){ - /* It's a SYN/ACK, and we are doing an active open */ - if(tcpack_f){ - tcp->th_ack= htonl(tcpack); - } - else{ - if( !tcpflags_f || (tcpflags_f && (tcpflags & TH_ACK))){ - tcp->th_ack= pkt_tcp->th_seq; - - if(ackdata_f){ - tcp->th_ack= htonl(ntohl(tcp->th_ack) + ((pkt_end - (unsigned char *)pkt_tcp) - (pkt_tcp->th_off << 2))); - } - - if(ackflags_f){ - tcp->th_ack= htonl(ntohl(tcp->th_ack) + ((pkt_tcp->th_flags & TH_FIN)?1:0) + \ - ((pkt_tcp->th_flags & TH_SYN)?1:0)); - } - } - } - - if(tcpflags_f){ - tcp->th_flags= tcpflags; - } - else{ - tcp->th_flags= TH_ACK; - - /* If the incoming packet was a SYN, we should respond with a SYN/ACK */ - if( (pkt_tcp->th_flags & TH_SYN) && !(pkt_tcp->th_flags & TH_ACK)) - tcp->th_flags = tcp->th_flags | TH_SYN; - } - - if(data_f) - senddata_f= 1; - - if(tcpclose_f && tcpclose != CLOSE_FIN_WAIT_2 && tcpclose != CLOSE_PASSIVE) - startclose_f= 1; - } - else{ - /* Simple SYN segment */ - if(tcpack_f){ - tcp->th_ack= htonl(tcpack); - } - else{ - if( !tcpflags_f || (tcpflags_f && (tcpflags & TH_ACK))){ - tcp->th_ack= pkt_tcp->th_seq; - - if(ackdata_f){ - tcp->th_ack= htonl(ntohl(tcp->th_ack) + ((pkt_end - (unsigned char *)pkt_tcp) - (pkt_tcp->th_off << 2))); - } - - if(ackflags_f){ - tcp->th_ack= htonl(ntohl(tcp->th_ack) + ((pkt_tcp->th_flags & TH_FIN)?1:0) + \ - ((pkt_tcp->th_flags & TH_SYN)?1:0)); - } - } - } - - if(tcpflags_f){ - tcp->th_flags= tcpflags; - } - else{ - tcp->th_flags= TH_ACK; - - /* If the incoming packet was a SYN, we should respond with a SYN/ACK */ - if( (pkt_tcp->th_flags & TH_SYN) && !(pkt_tcp->th_flags & TH_ACK)) - tcp->th_flags = tcp->th_flags | TH_SYN; - } - } - } - - tcp->th_win= htons(tcpwin); - } - else if(pkt_tcp->th_flags & TH_FIN){ - if(tcpclose_f && (tcpclose == CLOSE_SIMULTANEOUS || tcpclose == CLOSE_PASSIVE || tcpclose == CLOSE_ABORT)){ - if(tcpclose == CLOSE_SIMULTANEOUS){ - tcp->th_flags = TH_ACK | TH_FIN; - tcp->th_seq= pkt_tcp->th_ack; - tcp->th_ack= pkt_tcp->th_seq; - } - else if(tcpclose == CLOSE_PASSIVE){ - tcp->th_flags = TH_ACK | TH_FIN; - tcp->th_seq= pkt_tcp->th_ack; - tcp->th_ack= htonl(ntohl(pkt_tcp->th_seq) + ((pkt_end - (unsigned char *)pkt_tcp) - (pkt_tcp->th_off << 2))); - tcp->th_ack= htonl(ntohl(tcp->th_ack) + ((pkt_tcp->th_flags & TH_FIN)?1:0) + \ - ((pkt_tcp->th_flags & TH_SYN)?1:0)); - } - else if(tcpclose == CLOSE_ABORT){ - tcp->th_flags = TH_ACK | TH_RST; - tcp->th_seq= pkt_tcp->th_ack; - tcp->th_ack= htonl(ntohl(pkt_tcp->th_seq) + ((pkt_end - (unsigned char *)pkt_tcp) - (pkt_tcp->th_off << 2))); - tcp->th_ack= htonl(ntohl(tcp->th_ack) + ((pkt_tcp->th_flags & TH_FIN)?1:0) + \ - ((pkt_tcp->th_flags & TH_SYN)?1:0)); - } - } - else{ - if(tcpflags_f){ - tcp->th_flags= tcpflags; - } - else{ - tcp->th_flags= TH_ACK; - } - - if(tcpack_f){ - tcp->th_ack= htonl(tcpack); - } - else{ - if( !tcpflags_f || (tcpflags_f && (tcpflags & TH_ACK))){ - tcp->th_ack= pkt_tcp->th_seq; - - if(ackdata_f){ - tcp->th_ack= htonl(ntohl(tcp->th_ack) + ((pkt_end - (unsigned char *)pkt_tcp) - (pkt_tcp->th_off << 2))); - } - - if(ackflags_f && !(tcpclose_f && tcpclose == CLOSE_LAST_ACK) && !(tcpclose_f && tcpclose == CLOSE_FIN_WAIT_1)){ - tcp->th_ack= htonl(ntohl(tcp->th_ack) + ((pkt_tcp->th_flags & TH_FIN)?1:0) + \ - ((pkt_tcp->th_flags & TH_SYN)?1:0)); - } - } - } - } - - if(window_f){ - if(window == WIN_CLOSED){ - tcp->th_win= htons(0); - } - else if(window == WIN_MODULATE){ - tcp->th_win= htons(tcpwinm); - } - } - else - tcp->th_win= htons(tcpwin); - } - else if(pkt_tcp->th_flags & TH_ACK){ - if(tcpclose_f && tcpclose == CLOSE_ABORT){ - tcp->th_flags = TH_ACK | TH_RST; - tcp->th_seq= pkt_tcp->th_ack; - tcp->th_ack= htonl(ntohl(pkt_tcp->th_seq) + ((pkt_tcp->th_flags & TH_FIN)?1:0) + \ - ((pkt_tcp->th_flags & TH_SYN)?1:0)); - } - else{ - if(tcpflags_f){ - tcp->th_flags= tcpflags; - } - else{ - tcp->th_flags= TH_ACK; - } - - if(tcpack_f){ - tcp->th_ack= htonl(tcpack); - } - else{ - if( !tcpflags_f || (tcpflags_f && (tcpflags & TH_ACK))){ - tcp->th_ack= pkt_tcp->th_seq; - - if(ackdata_f){ - tcp->th_ack= htonl(ntohl(tcp->th_ack) + ((pkt_end - (unsigned char *)pkt_tcp) - (pkt_tcp->th_off << 2))); - } - - if(ackflags_f){ - tcp->th_ack= htonl(ntohl(tcp->th_ack) + ((pkt_tcp->th_flags & TH_FIN)?1:0) + \ - ((pkt_tcp->th_flags & TH_SYN)?1:0)); - } - } - } - } - - if(window_f){ - if(window == WIN_CLOSED){ - tcp->th_win= htons(0); - } - else if(window == WIN_MODULATE){ - tcp->th_win= htons(tcpwinm); - } - } - else - tcp->th_win= htons(tcpwin); - } - - tcp->th_urp= htons(tcpurg); - - /* Current version of tcp6 does not support sending TCP options */ - tcp->th_off= sizeof(struct tcp_hdr) >> 2; - ptr+= tcp->th_off << 2; - - if(rhbytes_f){ - if( (ptr + rhbytes) > v6buffer+ idata->max_packet_size){ - puts("Packet Too Large while inserting TCP segment"); - exit(EXIT_FAILURE); - } - - while(rhbytes>=4){ - *(uint32_t *)ptr = random(); - ptr += sizeof(uint32_t); - rhbytes -= sizeof(uint32_t); - } - - while(rhbytes>0){ - *(uint8_t *) ptr= (uint8_t) random(); - ptr++; - rhbytes--; - } - } - - - tcp->th_sum = 0; - tcp->th_sum = in_chksum(v6buffer, tcp, ptr-((unsigned char *)tcp), IPPROTO_TCP); - - frag_and_send(idata); - - - if(senddata_f){ - tcp->th_seq= htonl( ntohl(tcp->th_seq) + ptr-((unsigned char *)tcp + (tcp->th_off << 2))); - ptr= (unsigned char *)tcp + sizeof(struct tcp_hdr); - - if((ptr+ datalen) > (v6buffer + idata->max_packet_size)){ - if(idata->verbose_f) - puts("Packet too large while inserting TCP data"); - exit(EXIT_FAILURE); - } - - memcpy(ptr, data, datalen); - ptr+= datalen; - - if(window_f){ - if(window == WIN_CLOSED) - tcp->th_win = htons(0); - else - tcp->th_win = htons((uint16_t) win1_size); - } - else{ - tcp->th_win = htons(tcpwin); - } - - tcp->th_sum = 0; - tcp->th_sum = in_chksum(v6buffer, tcp, ptr-((unsigned char *)tcp), IPPROTO_TCP); - frag_and_send(idata); - } - - if(startclose_f){ - tcp->th_seq= htonl( ntohl(tcp->th_seq) + ptr-((unsigned char *)tcp + (tcp->th_off << 2))); - ptr= (unsigned char *) tcp + sizeof(struct tcp_hdr); - - if(tcpclose == CLOSE_ABORT){ - tcp->th_flags= TH_ACK | TH_RST; - } - else if(tcpclose == CLOSE_ACTIVE || tcpclose == CLOSE_LAST_ACK){ - tcp->th_flags= TH_ACK | TH_FIN; - } - - tcp->th_sum = 0; - tcp->th_sum = in_chksum(v6buffer, tcp, ptr-((unsigned char *)tcp), IPPROTO_TCP); - frag_and_send(idata); - } - - return; - } - else{ - if(ports >= nports){ - sources++; - ports= 0; - } - - if(sources >= nsources){ - if(loop_f){ - sources= 0; - } - else{ - donesending_f= 1; - return; - } - } - - if( (ptr+sizeof(struct tcp_hdr)) > (v6buffer + idata->max_packet_size)){ - puts("Packet Too Large while inserting TCP header"); - exit(EXIT_FAILURE); - } - - tcp= (struct tcp_hdr *) ptr; - memset(ptr, 0, sizeof(struct tcp_hdr)); - - if(floodp_f){ - if(srcportrnd_f){ - randomize_port(&srcport, srcport, srcportpref); - } - else{ - srcport= random(); - } - } - - tcp->th_sport= htons(srcport); - tcp->th_dport= htons(dstport); - tcp->th_seq = htonl(tcpseq); - - if(!tcpack_f && (tcpflags & TH_ACK)){ - tcp->th_ack= htonl(random()); - } - - if(tcpflags_auto_f || tcpopen_f || tcpclose_f){ - tcp->th_flags= TH_SYN; - } - else{ - tcp->th_flags= tcpflags; - } - - tcp->th_urp= htons(tcpurg); - tcp->th_win= htons(tcpwin); - tcp->th_off= sizeof(struct tcp_hdr) >> 2; - - ptr += tcp->th_off << 2; - - if( (ptr + rhbytes) > v6buffer + idata->max_packet_size){ - puts("Packet Too Large while inserting TCP segment"); - exit(EXIT_FAILURE); - } - - while(rhbytes>=4){ - *(uint32_t *)ptr = random(); - ptr += sizeof(uint32_t); - rhbytes -= sizeof(uint32_t); - } - - while(rhbytes>0){ - *(uint8_t *) ptr= (uint8_t) random(); - ptr++; - rhbytes--; - } - - - if(floods_f && ports == 0){ - /* - Randomizing the IPv6 Source address based on the prefix specified by - "srcaddr" and srcpreflen. - */ - - randomize_ipv6_addr( &(ipv6->ip6_src), &(idata->srcaddr), idata->srcpreflen); - - /* - If we need to respond to incomming packets, we set the Interface ID such that we can - detect which IPv6 addresses we have used. - */ - if(listen_f && useaddrkey_f){ - ipv6->ip6_src.s6_addr32[2]= ntohl((uint32_t)random() <<16); - ipv6->ip6_src.s6_addr32[2]= htonl(ntohl(ipv6->ip6_src.s6_addr32[2]) | ((ntohl(ipv6->ip6_src.s6_addr32[2])>>16) ^ addr_key)); - - ipv6->ip6_src.s6_addr32[3]= ntohl((uint32_t)random() <<16); - ipv6->ip6_src.s6_addr32[3]= htonl(ntohl(ipv6->ip6_src.s6_addr32[3]) | (uint32_t)((ntohl(ipv6->ip6_src.s6_addr32[3]) >>16) ^ addr_key)); - } - } - - tcp->th_sum = 0; - tcp->th_sum = in_chksum(v6buffer, tcp, ptr-((unsigned char *)tcp), IPPROTO_TCP); - - frag_and_send(idata); - - ports++; - - return; - } +void send_packet(struct iface_data *idata, const u_char *pktdata, struct pcap_pkthdr *pkthdr) { + static unsigned int sources = 0, ports = 0; + ptr = startofprefixes; + + startclose_f = 0; + senddata_f = 0; + + if (pktdata != NULL) { /* Sending a TCP segment in response to a received packet */ + pkt_ether = (struct ether_header *)pktdata; + pkt_ipv6 = (struct ip6_hdr *)((char *)pkt_ether + idata->linkhsize); + pkt_tcp = (struct tcp_hdr *)((char *)pkt_ipv6 + sizeof(struct ip6_hdr)); + pkt_end = (unsigned char *)pktdata + pkthdr->caplen; + + /* The packet length is the minimum of what we capured, and what is specified in the + IPv6 Total Lenght field + */ + if (pkt_end > ((unsigned char *)pkt_ipv6 + sizeof(struct ip6_hdr) + ntohs(pkt_ipv6->ip6_plen))) + pkt_end = (unsigned char *)pkt_ipv6 + sizeof(struct ip6_hdr) + ntohs(pkt_ipv6->ip6_plen); + + pkt_ipv6addr = &(pkt_ipv6->ip6_src); + + /* + We don't send any packets if the Source Address of the captured packet is the unspecified + address or a multicast address + */ + if (IN6_IS_ADDR_UNSPECIFIED(pkt_ipv6addr) || IN6_IS_ADDR_MULTICAST(pkt_ipv6addr)) { + return; + } + else { + ipv6->ip6_dst = pkt_ipv6->ip6_src; + + if (idata->type == DLT_EN10MB && !(idata->flags & IFACE_LOOPBACK)) + ethernet->dst = pkt_ether->src; + } + + pkt_ipv6addr = &(pkt_ipv6->ip6_dst); + + /* + We do not send any packets if the Destination Address of the captured packet is the unspecified + address or a multicast address + */ + if (IN6_IS_ADDR_MULTICAST(pkt_ipv6addr) || IN6_IS_ADDR_MULTICAST(pkt_ipv6addr)) { + return; + } + else { + ipv6->ip6_src = pkt_ipv6->ip6_dst; + + if (idata->type == DLT_EN10MB && !(idata->flags & IFACE_LOOPBACK)) + ethernet->src = pkt_ether->dst; + } + + if ((ptr + sizeof(struct tcp_hdr)) > (v6buffer + idata->max_packet_size)) { + puts("Packet Too Large while inserting TCP header"); + exit(EXIT_FAILURE); + } + + /* If we are setting the flags automatically, do not respond to RST segments */ + if ((tcpflags_auto_f || tcpopen_f || tcpclose_f) && pkt_tcp->th_flags & TH_RST) + return; + + tcp = (struct tcp_hdr *)ptr; + memset(tcp, 0, sizeof(struct tcp_hdr)); + + tcp->th_sport = pkt_tcp->th_dport; + tcp->th_dport = pkt_tcp->th_sport; + + if (tcpseq_f) + tcp->th_seq = htonl(tcpseq); + else + tcp->th_seq = pkt_tcp->th_ack; + + if (pkt_tcp->th_flags & TH_SYN) { + if (tcpopen_f) { + if (tcpopen == OPEN_PASSIVE) { + /* If it is a pure SYN, respond with a SYN/ACK */ + if (!(pkt_tcp->th_flags & TH_ACK)) { + tcp->th_flags = tcp->th_flags | TH_SYN | TH_ACK; + tcp->th_seq = random(); + tcp->th_ack = htonl(ntohl(pkt_tcp->th_seq) + + ((pkt_end - (unsigned char *)pkt_tcp) - (pkt_tcp->th_off << 2))); + tcp->th_ack = htonl(ntohl(tcp->th_ack) + ((pkt_tcp->th_flags & TH_FIN) ? 1 : 0) + + ((pkt_tcp->th_flags & TH_SYN) ? 1 : 0)); + } + } + else if (tcpopen == OPEN_SIMULTANEOUS) { + /* If it is a pure SYN, respond with a SYN */ + if (!(pkt_tcp->th_flags & TH_ACK)) { + tcp->th_flags = tcp->th_flags | TH_SYN; + tcp->th_seq = random(); + tcp->th_ack = 0; + } + else { + /* If we receive a SYN/ACK (product of the above SYN), send a SYN/ACK */ + tcp->th_flags = tcp->th_flags | TH_SYN | TH_ACK; + tcp->th_seq = (pkt_tcp->th_ack) - (rhbytes + 1); + tcp->th_ack = htonl(ntohl(pkt_tcp->th_seq) + + ((pkt_end - (unsigned char *)pkt_tcp) - (pkt_tcp->th_off << 2))); + tcp->th_ack = htonl(ntohl(tcp->th_ack) + ((pkt_tcp->th_flags & TH_FIN) ? 1 : 0) + + ((pkt_tcp->th_flags & TH_SYN) ? 1 : 0)); + + if (data_f) + senddata_f = 1; + } + } + else if (tcpopen == OPEN_ABORT) { + /* If we receive a SYN, send RST */ + tcp->th_flags = tcp->th_flags | TH_RST | TH_ACK; + if (pkt_tcp->th_flags & TH_ACK) + tcp->th_seq = pkt_tcp->th_ack; + else + tcp->th_seq = 0; + + tcp->th_ack = + htonl(ntohl(pkt_tcp->th_seq) + ((pkt_end - (unsigned char *)pkt_tcp) - (pkt_tcp->th_off << 2))); + tcp->th_ack = htonl(ntohl(tcp->th_ack) + ((pkt_tcp->th_flags & TH_FIN) ? 1 : 0) + + ((pkt_tcp->th_flags & TH_SYN) ? 1 : 0)); + } + } + else { + /* We have received a SYN/ACK */ + if (pkt_tcp->th_flags & TH_ACK) { + /* It's a SYN/ACK, and we are doing an active open */ + if (tcpack_f) { + tcp->th_ack = htonl(tcpack); + } + else { + if (!tcpflags_f || (tcpflags_f && (tcpflags & TH_ACK))) { + tcp->th_ack = pkt_tcp->th_seq; + + if (ackdata_f) { + tcp->th_ack = htonl(ntohl(tcp->th_ack) + + ((pkt_end - (unsigned char *)pkt_tcp) - (pkt_tcp->th_off << 2))); + } + + if (ackflags_f) { + tcp->th_ack = htonl(ntohl(tcp->th_ack) + ((pkt_tcp->th_flags & TH_FIN) ? 1 : 0) + + ((pkt_tcp->th_flags & TH_SYN) ? 1 : 0)); + } + } + } + + if (tcpflags_f) { + tcp->th_flags = tcpflags; + } + else { + tcp->th_flags = TH_ACK; + + /* If the incoming packet was a SYN, we should respond with a SYN/ACK */ + if ((pkt_tcp->th_flags & TH_SYN) && !(pkt_tcp->th_flags & TH_ACK)) + tcp->th_flags = tcp->th_flags | TH_SYN; + } + + if (data_f) + senddata_f = 1; + + if (tcpclose_f && tcpclose != CLOSE_FIN_WAIT_2 && tcpclose != CLOSE_PASSIVE) + startclose_f = 1; + } + else { + /* Simple SYN segment */ + if (tcpack_f) { + tcp->th_ack = htonl(tcpack); + } + else { + if (!tcpflags_f || (tcpflags_f && (tcpflags & TH_ACK))) { + tcp->th_ack = pkt_tcp->th_seq; + + if (ackdata_f) { + tcp->th_ack = htonl(ntohl(tcp->th_ack) + + ((pkt_end - (unsigned char *)pkt_tcp) - (pkt_tcp->th_off << 2))); + } + + if (ackflags_f) { + tcp->th_ack = htonl(ntohl(tcp->th_ack) + ((pkt_tcp->th_flags & TH_FIN) ? 1 : 0) + + ((pkt_tcp->th_flags & TH_SYN) ? 1 : 0)); + } + } + } + + if (tcpflags_f) { + tcp->th_flags = tcpflags; + } + else { + tcp->th_flags = TH_ACK; + + /* If the incoming packet was a SYN, we should respond with a SYN/ACK */ + if ((pkt_tcp->th_flags & TH_SYN) && !(pkt_tcp->th_flags & TH_ACK)) + tcp->th_flags = tcp->th_flags | TH_SYN; + } + } + } + + tcp->th_win = htons(tcpwin); + } + else if (pkt_tcp->th_flags & TH_FIN) { + if (tcpclose_f && + (tcpclose == CLOSE_SIMULTANEOUS || tcpclose == CLOSE_PASSIVE || tcpclose == CLOSE_ABORT)) { + if (tcpclose == CLOSE_SIMULTANEOUS) { + tcp->th_flags = TH_ACK | TH_FIN; + tcp->th_seq = pkt_tcp->th_ack; + tcp->th_ack = pkt_tcp->th_seq; + } + else if (tcpclose == CLOSE_PASSIVE) { + tcp->th_flags = TH_ACK | TH_FIN; + tcp->th_seq = pkt_tcp->th_ack; + tcp->th_ack = + htonl(ntohl(pkt_tcp->th_seq) + ((pkt_end - (unsigned char *)pkt_tcp) - (pkt_tcp->th_off << 2))); + tcp->th_ack = htonl(ntohl(tcp->th_ack) + ((pkt_tcp->th_flags & TH_FIN) ? 1 : 0) + + ((pkt_tcp->th_flags & TH_SYN) ? 1 : 0)); + } + else if (tcpclose == CLOSE_ABORT) { + tcp->th_flags = TH_ACK | TH_RST; + tcp->th_seq = pkt_tcp->th_ack; + tcp->th_ack = + htonl(ntohl(pkt_tcp->th_seq) + ((pkt_end - (unsigned char *)pkt_tcp) - (pkt_tcp->th_off << 2))); + tcp->th_ack = htonl(ntohl(tcp->th_ack) + ((pkt_tcp->th_flags & TH_FIN) ? 1 : 0) + + ((pkt_tcp->th_flags & TH_SYN) ? 1 : 0)); + } + } + else { + if (tcpflags_f) { + tcp->th_flags = tcpflags; + } + else { + tcp->th_flags = TH_ACK; + } + + if (tcpack_f) { + tcp->th_ack = htonl(tcpack); + } + else { + if (!tcpflags_f || (tcpflags_f && (tcpflags & TH_ACK))) { + tcp->th_ack = pkt_tcp->th_seq; + + if (ackdata_f) { + tcp->th_ack = htonl(ntohl(tcp->th_ack) + + ((pkt_end - (unsigned char *)pkt_tcp) - (pkt_tcp->th_off << 2))); + } + + if (ackflags_f && !(tcpclose_f && tcpclose == CLOSE_LAST_ACK) && + !(tcpclose_f && tcpclose == CLOSE_FIN_WAIT_1)) { + tcp->th_ack = htonl(ntohl(tcp->th_ack) + ((pkt_tcp->th_flags & TH_FIN) ? 1 : 0) + + ((pkt_tcp->th_flags & TH_SYN) ? 1 : 0)); + } + } + } + } + + if (window_f) { + if (window == WIN_CLOSED) { + tcp->th_win = htons(0); + } + else if (window == WIN_MODULATE) { + tcp->th_win = htons(tcpwinm); + } + } + else + tcp->th_win = htons(tcpwin); + } + else if (pkt_tcp->th_flags & TH_ACK) { + if (tcpclose_f && tcpclose == CLOSE_ABORT) { + tcp->th_flags = TH_ACK | TH_RST; + tcp->th_seq = pkt_tcp->th_ack; + tcp->th_ack = htonl(ntohl(pkt_tcp->th_seq) + ((pkt_tcp->th_flags & TH_FIN) ? 1 : 0) + + ((pkt_tcp->th_flags & TH_SYN) ? 1 : 0)); + } + else { + if (tcpflags_f) { + tcp->th_flags = tcpflags; + } + else { + tcp->th_flags = TH_ACK; + } + + if (tcpack_f) { + tcp->th_ack = htonl(tcpack); + } + else { + if (!tcpflags_f || (tcpflags_f && (tcpflags & TH_ACK))) { + tcp->th_ack = pkt_tcp->th_seq; + + if (ackdata_f) { + tcp->th_ack = htonl(ntohl(tcp->th_ack) + + ((pkt_end - (unsigned char *)pkt_tcp) - (pkt_tcp->th_off << 2))); + } + + if (ackflags_f) { + tcp->th_ack = htonl(ntohl(tcp->th_ack) + ((pkt_tcp->th_flags & TH_FIN) ? 1 : 0) + + ((pkt_tcp->th_flags & TH_SYN) ? 1 : 0)); + } + } + } + } + + if (window_f) { + if (window == WIN_CLOSED) { + tcp->th_win = htons(0); + } + else if (window == WIN_MODULATE) { + tcp->th_win = htons(tcpwinm); + } + } + else + tcp->th_win = htons(tcpwin); + } + + tcp->th_urp = htons(tcpurg); + + /* Current version of tcp6 does not support sending TCP options */ + tcp->th_off = sizeof(struct tcp_hdr) >> 2; + ptr += tcp->th_off << 2; + + if (rhbytes_f) { + if ((ptr + rhbytes) > v6buffer + idata->max_packet_size) { + puts("Packet Too Large while inserting TCP segment"); + exit(EXIT_FAILURE); + } + + while (rhbytes >= 4) { + *(uint32_t *)ptr = random(); + ptr += sizeof(uint32_t); + rhbytes -= sizeof(uint32_t); + } + + while (rhbytes > 0) { + *(uint8_t *)ptr = (uint8_t)random(); + ptr++; + rhbytes--; + } + } + + tcp->th_sum = 0; + tcp->th_sum = in_chksum(v6buffer, tcp, ptr - ((unsigned char *)tcp), IPPROTO_TCP); + + frag_and_send(idata); + + if (senddata_f) { + tcp->th_seq = htonl(ntohl(tcp->th_seq) + ptr - ((unsigned char *)tcp + (tcp->th_off << 2))); + ptr = (unsigned char *)tcp + sizeof(struct tcp_hdr); + + if ((ptr + datalen) > (v6buffer + idata->max_packet_size)) { + if (idata->verbose_f) + puts("Packet too large while inserting TCP data"); + exit(EXIT_FAILURE); + } + + memcpy(ptr, data, datalen); + ptr += datalen; + + if (window_f) { + if (window == WIN_CLOSED) + tcp->th_win = htons(0); + else + tcp->th_win = htons((uint16_t)win1_size); + } + else { + tcp->th_win = htons(tcpwin); + } + + tcp->th_sum = 0; + tcp->th_sum = in_chksum(v6buffer, tcp, ptr - ((unsigned char *)tcp), IPPROTO_TCP); + frag_and_send(idata); + } + + if (startclose_f) { + tcp->th_seq = htonl(ntohl(tcp->th_seq) + ptr - ((unsigned char *)tcp + (tcp->th_off << 2))); + ptr = (unsigned char *)tcp + sizeof(struct tcp_hdr); + + if (tcpclose == CLOSE_ABORT) { + tcp->th_flags = TH_ACK | TH_RST; + } + else if (tcpclose == CLOSE_ACTIVE || tcpclose == CLOSE_LAST_ACK) { + tcp->th_flags = TH_ACK | TH_FIN; + } + + tcp->th_sum = 0; + tcp->th_sum = in_chksum(v6buffer, tcp, ptr - ((unsigned char *)tcp), IPPROTO_TCP); + frag_and_send(idata); + } + + return; + } + else { + if (ports >= nports) { + sources++; + ports = 0; + } + + if (sources >= nsources) { + if (loop_f) { + sources = 0; + } + else { + donesending_f = 1; + return; + } + } + + if ((ptr + sizeof(struct tcp_hdr)) > (v6buffer + idata->max_packet_size)) { + puts("Packet Too Large while inserting TCP header"); + exit(EXIT_FAILURE); + } + + tcp = (struct tcp_hdr *)ptr; + memset(ptr, 0, sizeof(struct tcp_hdr)); + + if (floodp_f) { + if (srcportrnd_f) { + randomize_port(&srcport, srcport, srcportpref); + } + else { + srcport = random(); + } + } + + tcp->th_sport = htons(srcport); + tcp->th_dport = htons(dstport); + tcp->th_seq = htonl(tcpseq); + + if (!tcpack_f && (tcpflags & TH_ACK)) { + tcp->th_ack = htonl(random()); + } + + if (tcpflags_auto_f || tcpopen_f || tcpclose_f) { + tcp->th_flags = TH_SYN; + } + else { + tcp->th_flags = tcpflags; + } + + tcp->th_urp = htons(tcpurg); + tcp->th_win = htons(tcpwin); + tcp->th_off = sizeof(struct tcp_hdr) >> 2; + + ptr += tcp->th_off << 2; + + if ((ptr + rhbytes) > v6buffer + idata->max_packet_size) { + puts("Packet Too Large while inserting TCP segment"); + exit(EXIT_FAILURE); + } + + while (rhbytes >= 4) { + *(uint32_t *)ptr = random(); + ptr += sizeof(uint32_t); + rhbytes -= sizeof(uint32_t); + } + + while (rhbytes > 0) { + *(uint8_t *)ptr = (uint8_t)random(); + ptr++; + rhbytes--; + } + + if (floods_f && ports == 0) { + /* + Randomizing the IPv6 Source address based on the prefix specified by + "srcaddr" and srcpreflen. + */ + + randomize_ipv6_addr(&(ipv6->ip6_src), &(idata->srcaddr), idata->srcpreflen); + + /* + If we need to respond to incomming packets, we set the Interface ID such that we can + detect which IPv6 addresses we have used. + */ + if (listen_f && useaddrkey_f) { + ipv6->ip6_src.s6_addr32[2] = ntohl((uint32_t)random() << 16); + ipv6->ip6_src.s6_addr32[2] = + htonl(ntohl(ipv6->ip6_src.s6_addr32[2]) | ((ntohl(ipv6->ip6_src.s6_addr32[2]) >> 16) ^ addr_key)); + + ipv6->ip6_src.s6_addr32[3] = ntohl((uint32_t)random() << 16); + ipv6->ip6_src.s6_addr32[3] = htonl(ntohl(ipv6->ip6_src.s6_addr32[3]) | + (uint32_t)((ntohl(ipv6->ip6_src.s6_addr32[3]) >> 16) ^ addr_key)); + } + } + + tcp->th_sum = 0; + tcp->th_sum = in_chksum(v6buffer, tcp, ptr - ((unsigned char *)tcp), IPPROTO_TCP); + + frag_and_send(idata); + + ports++; + + return; + } } - /* * Function: frag_and_send() * * Send an IPv6 datagram, and fragment if selected */ -void frag_and_send(struct iface_data *idata){ - if(!idata->fragh_f){ - ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); - - if((nw=pcap_inject(idata->pfd, buffer, ptr - buffer)) == -1){ - printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); - exit(EXIT_FAILURE); - } - - if(nw != (ptr-buffer)){ - printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", \ - nw, (LUI) (ptr-buffer)); - exit(EXIT_FAILURE); - } - } - else{ - ptrend= ptr; - ptr= fragpart; - fptr = fragbuffer; - fipv6 = (struct ip6_hdr *) (fragbuffer + idata->linkhsize); - fptrend = fptr + idata->linkhsize+MIN_IPV6_HLEN+MAX_IPV6_PAYLOAD; - memcpy(fptr, buffer, fragpart-buffer); - fptr = fptr + (fragpart-buffer); - - if( (fptr+FRAG_HDR_SIZE)> fptrend){ - puts("Unfragmentable Part is Too Large"); - exit(EXIT_FAILURE); - } - - memcpy(fptr, (char *) &fraghdr, FRAG_HDR_SIZE); - fh= (struct ip6_frag *) fptr; - fh->ip6f_ident=random(); - startoffragment = fptr + FRAG_HDR_SIZE; - - /* - * Check that the selected fragment size is not larger than the largest - * fragment size that can be sent - */ - - if(nfrags > (fptrend - fptr)) - nfrags= (fptrend-fptr); - - m=IP6F_MORE_FRAG; - - while((ptr < ptrend) && m==IP6F_MORE_FRAG){ - fptr= startoffragment; - - if( (ptrend-ptr) <= nfrags){ - fragsize= ptrend-ptr; - m=0; - } - else{ - fragsize = (nfrags + 7) & ntohs(IP6F_OFF_MASK); - } - - memcpy(fptr, ptr, fragsize); - fh->ip6f_offlg = (htons(ptr-fragpart) & IP6F_OFF_MASK) | m; - ptr+=fragsize; - fptr+=fragsize; - - fipv6->ip6_plen = htons((fptr - fragbuffer) - MIN_IPV6_HLEN - idata->linkhsize); - - if((nw=pcap_inject(idata->pfd, fragbuffer, fptr - fragbuffer)) == -1){ - printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); - exit(EXIT_FAILURE); - } - - if(nw != (fptr- fragbuffer)){ - printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", \ - nw, (LUI) (ptr-buffer)); - exit(EXIT_FAILURE); - } - } /* Sending fragments */ - } /* Sending fragmented datagram */ +void frag_and_send(struct iface_data *idata) { + if (!idata->fragh_f) { + ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); + + if ((nw = pcap_inject(idata->pfd, buffer, ptr - buffer)) == -1) { + printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); + exit(EXIT_FAILURE); + } + + if (nw != (ptr - buffer)) { + printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, (LUI)(ptr - buffer)); + exit(EXIT_FAILURE); + } + } + else { + ptrend = ptr; + ptr = fragpart; + fptr = fragbuffer; + fipv6 = (struct ip6_hdr *)(fragbuffer + idata->linkhsize); + fptrend = fptr + idata->linkhsize + MIN_IPV6_HLEN + MAX_IPV6_PAYLOAD; + memcpy(fptr, buffer, fragpart - buffer); + fptr = fptr + (fragpart - buffer); + + if ((fptr + FRAG_HDR_SIZE) > fptrend) { + puts("Unfragmentable Part is Too Large"); + exit(EXIT_FAILURE); + } + + memcpy(fptr, (char *)&fraghdr, FRAG_HDR_SIZE); + fh = (struct ip6_frag *)fptr; + fh->ip6f_ident = random(); + startoffragment = fptr + FRAG_HDR_SIZE; + + /* + * Check that the selected fragment size is not larger than the largest + * fragment size that can be sent + */ + + if (nfrags > (fptrend - fptr)) + nfrags = (fptrend - fptr); + + m = IP6F_MORE_FRAG; + + while ((ptr < ptrend) && m == IP6F_MORE_FRAG) { + fptr = startoffragment; + + if ((ptrend - ptr) <= nfrags) { + fragsize = ptrend - ptr; + m = 0; + } + else { + fragsize = (nfrags + 7) & ntohs(IP6F_OFF_MASK); + } + + memcpy(fptr, ptr, fragsize); + fh->ip6f_offlg = (htons(ptr - fragpart) & IP6F_OFF_MASK) | m; + ptr += fragsize; + fptr += fragsize; + + fipv6->ip6_plen = htons((fptr - fragbuffer) - MIN_IPV6_HLEN - idata->linkhsize); + + if ((nw = pcap_inject(idata->pfd, fragbuffer, fptr - fragbuffer)) == -1) { + printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); + exit(EXIT_FAILURE); + } + + if (nw != (fptr - fragbuffer)) { + printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, (LUI)(ptr - buffer)); + exit(EXIT_FAILURE); + } + } /* Sending fragments */ + } /* Sending fragmented datagram */ } - /* * Function: usage() * * Prints the syntax of the tcp6 tool */ -void usage(void){ - puts("usage: tcp6 [-i INTERFACE] [-S LINK_SRC_ADDR] [-D LINK-DST-ADDR] " - "[-s SRC_ADDR[/LEN]] [-d DST_ADDR] [-A HOP_LIMIT] [-y FRAG_SIZE] [-u DST_OPT_HDR_SIZE] " - "[-U DST_OPT_U_HDR_SIZE] [-H HBH_OPT_HDR_SIZE] [-P PAYLOAD_SIZE] [-o SRC_PORT[/LEN]] " - "[-a DST_PORT[/LEN]] [-X TCP_FLAGS] [-q TCP_SEQ] [-Q TCP_ACK] [-V TCP_URP] [-w TCP_WIN] " - "[-c OPEN_MODE] [-C CLOSE_MODE] [-Z DATA] [-P PAYLOAD_SIZE] [-W WIN_MODE]" - "[-M WIN_MOD_MODE] [-r RATE] [-p PROBE_MODE] [-x RETRANS] " - "[-N] [-n] [-j PREFIX[/LEN]] [-k PREFIX[/LEN]] [-J LINK_ADDR] [-K LINK_ADDR] " - "[-b PREFIX[/LEN]] [-g PREFIX[/LEN]] [-B LINK_ADDR] [-G LINK_ADDR] " - "[-F N_SOURCES] [-T N_PORTS] [-L | -l] [-z SECONDS] [-v] [-h]"); +void usage(void) { + puts("usage: tcp6 [-i INTERFACE] [-S LINK_SRC_ADDR] [-D LINK-DST-ADDR] " + "[-s SRC_ADDR[/LEN]] [-d DST_ADDR] [-A HOP_LIMIT] [-y FRAG_SIZE] [-u DST_OPT_HDR_SIZE] " + "[-U DST_OPT_U_HDR_SIZE] [-H HBH_OPT_HDR_SIZE] [-P PAYLOAD_SIZE] [-o SRC_PORT[/LEN]] " + "[-a DST_PORT[/LEN]] [-X TCP_FLAGS] [-q TCP_SEQ] [-Q TCP_ACK] [-V TCP_URP] [-w TCP_WIN] " + "[-c OPEN_MODE] [-C CLOSE_MODE] [-Z DATA] [-P PAYLOAD_SIZE] [-W WIN_MODE]" + "[-M WIN_MOD_MODE] [-r RATE] [-p PROBE_MODE] [-x RETRANS] " + "[-N] [-n] [-j PREFIX[/LEN]] [-k PREFIX[/LEN]] [-J LINK_ADDR] [-K LINK_ADDR] " + "[-b PREFIX[/LEN]] [-g PREFIX[/LEN]] [-B LINK_ADDR] [-G LINK_ADDR] " + "[-F N_SOURCES] [-T N_PORTS] [-L | -l] [-z SECONDS] [-v] [-h]"); } - - /* * Function: print_help() * * Prints help information for the tcp6 tool */ -void print_help(void){ - puts(SI6_TOOLKIT); - puts( "tcp6: Security assessment tool for attack vectors based on TCP/IPv6 packets\n"); - usage(); - - puts("\nOPTIONS:\n" - " --interface, -i Network interface\n" - " --src-addr, -s IPv6 Source Address\n" - " --dst-addr, -d IPv6 Destination Address\n" - " --hop-limit, -A IPv6 Hop Limit\n" - " --frag-hdr. -y Fragment Header\n" - " --dst-opt-hdr, -u Destination Options Header (Fragmentable Part)\n" - " --dst-opt-u-hdr, -U Destination Options Header (Unfragmentable Part)\n" - " --hbh-opt-hdr, -H Hop by Hop Options Header\n" - " --link-src-addr, -S Link-layer Destination Address\n" - " --link-dst-addr, -D Link-layer Source Address\n" - " --payload-size, -P TCP Payload Size\n" - " --src-port, -o TCP Source Port (PORT[/LEN])\n" - " --dst-port, -a TCP Destination Port (PORT[/LEN])\n" - " --tcp-flags, -X TCP Flags\n" - " --tcp-seq, -q TCP Sequence Number\n" - " --tcp-ack, -Q TCP Acknowledgment Number\n" - " --not-ack-data, -N Do not acknowledge the TCP payload\n" - " --not-ack-flags, -n Do not acknowledge the TCP flags\n" - " --tcp-urg, -V TCP Urgent Pointer\n" - " --tcp-win, -w TCP Window\n" - " --window-mode, -W TCP Window mode {close,modulate}\n" - " --win-modulation, -M TCP Window modulation (WIN1:TIME1:WIN2:TIME2)\n" - " --open-mode, -c Open mode {simultaneous,passive,abort,active}\n" - " --close-mode, -C Close mode {simultaneous,passive,abort\n" +void print_help(void) { + puts(SI6_TOOLKIT); + puts("tcp6: Security assessment tool for attack vectors based on TCP/IPv6 packets\n"); + usage(); + + puts("\nOPTIONS:\n" + " --interface, -i Network interface\n" + " --src-addr, -s IPv6 Source Address\n" + " --dst-addr, -d IPv6 Destination Address\n" + " --hop-limit, -A IPv6 Hop Limit\n" + " --frag-hdr. -y Fragment Header\n" + " --dst-opt-hdr, -u Destination Options Header (Fragmentable Part)\n" + " --dst-opt-u-hdr, -U Destination Options Header (Unfragmentable Part)\n" + " --hbh-opt-hdr, -H Hop by Hop Options Header\n" + " --link-src-addr, -S Link-layer Destination Address\n" + " --link-dst-addr, -D Link-layer Source Address\n" + " --payload-size, -P TCP Payload Size\n" + " --src-port, -o TCP Source Port (PORT[/LEN])\n" + " --dst-port, -a TCP Destination Port (PORT[/LEN])\n" + " --tcp-flags, -X TCP Flags\n" + " --tcp-seq, -q TCP Sequence Number\n" + " --tcp-ack, -Q TCP Acknowledgment Number\n" + " --not-ack-data, -N Do not acknowledge the TCP payload\n" + " --not-ack-flags, -n Do not acknowledge the TCP flags\n" + " --tcp-urg, -V TCP Urgent Pointer\n" + " --tcp-win, -w TCP Window\n" + " --window-mode, -W TCP Window mode {close,modulate}\n" + " --win-modulation, -M TCP Window modulation (WIN1:TIME1:WIN2:TIME2)\n" + " --open-mode, -c Open mode {simultaneous,passive,abort,active}\n" + " --close-mode, -C Close mode {simultaneous,passive,abort\n" " active,FIN-WAIT-1,FIN-WAIT-2,LAST-ACK}\n" - " --data, -Z TCP payload data\n" - " --rate-limit, -r Rate limit the address scan to specified rate\n" + " --data, -Z TCP payload data\n" + " --rate-limit, -r Rate limit the address scan to specified rate\n" " --probe-mode, -p TCP probe mode {dump,script}\n" - " --retrans, -x Set number of TCP retransmissions\n" - " --block-src, -j Block IPv6 Source Address prefix\n" - " --block-dst, -k Block IPv6 Destination Address prefix\n" - " --block-link-src, -J Block Ethernet Source Address\n" - " --block-link-dst, -K Block Ethernet Destination Address\n" - " --accept-src, -b Accept IPv6 Source Address prefix\n" - " --accept-dst, -g Accept IPv6 Destination Address prefix\n" - " --accept-link-src, -B Accept Ethernet Source Address\n" - " --accept-link-dst, -G Accept Ethernet Destination Address\n" - " --flood-sources, -F Flood from multiple IPv6 Source Addresses\n" - " --flood-ports, -T Flood from multiple TCP Source Ports\n" - " --listen, -L Listen to incoming packets\n" - " --loop, -l Send periodic TCP segments\n" - " --sleep, -z Pause between sending TCP segments\n" - " --help, -h Print help for the tcp6 tool\n" - " --verbose, -v Be verbose\n" - "\n" - "Programmed by Fernando Gont for SI6 Networks \n" - "Please send any bug reports to \n" - ); + " --retrans, -x Set number of TCP retransmissions\n" + " --block-src, -j Block IPv6 Source Address prefix\n" + " --block-dst, -k Block IPv6 Destination Address prefix\n" + " --block-link-src, -J Block Ethernet Source Address\n" + " --block-link-dst, -K Block Ethernet Destination Address\n" + " --accept-src, -b Accept IPv6 Source Address prefix\n" + " --accept-dst, -g Accept IPv6 Destination Address prefix\n" + " --accept-link-src, -B Accept Ethernet Source Address\n" + " --accept-link-dst, -G Accept Ethernet Destination Address\n" + " --flood-sources, -F Flood from multiple IPv6 Source Addresses\n" + " --flood-ports, -T Flood from multiple TCP Source Ports\n" + " --listen, -L Listen to incoming packets\n" + " --loop, -l Send periodic TCP segments\n" + " --sleep, -z Pause between sending TCP segments\n" + " --help, -h Print help for the tcp6 tool\n" + " --verbose, -v Be verbose\n" + "\n" + "Programmed by Fernando Gont for SI6 Networks \n" + "Please send any bug reports to \n"); } - /* * Function: print_attack_info() * * Prints attack details (when the verbose ("-v") option is specified). */ - -void print_attack_info(struct iface_data *idata){ - puts(SI6_TOOLKIT); - puts( "tcp6: Security assessment tool for attack vectors based on TCP/IPv6 packets\n"); - - if(floods_f && !(loop_f && !sleep_f)) - printf("Flooding the target from %u different IPv6 Source Addresses\n", nsources); - - if(floodp_f && !(loop_f && !sleep_f)) - printf("Flooding the target from %u different TCP ports\n", nports); - - if(idata->type == DLT_EN10MB && !(idata->flags & IFACE_LOOPBACK)){ - if(idata->hsrcaddr_f){ - if(ether_ntop(&(idata->hsrcaddr), plinkaddr, sizeof(plinkaddr)) == 0){ - puts("ether_ntop(): Error converting address"); - exit(EXIT_FAILURE); - } - - printf("Ethernet Source Address: %s\n", plinkaddr); - } - else{ - if(idata->dstaddr_f){ - if(ether_ntop(&(idata->hsrcaddr), plinkaddr, sizeof(plinkaddr)) == 0){ - puts("ether_ntop(): Error converting address"); - exit(EXIT_FAILURE); - } - - printf("Ethernet Source Address: %s%s\n", plinkaddr, ((!(idata->hsrcaddr_f))?" (randomized)":"")); - } - else - puts("Ethernet Source Address: Automatically selected for each packet"); - } - - /* - Ethernet Destination Address only used if a IPv6 Destination Address or an - Ethernet Destination Address were specified. - */ - if(idata->dstaddr_f){ - if(ether_ntop(&(idata->hdstaddr), plinkaddr, sizeof(plinkaddr)) == 0){ - puts("ether_ntop(): Error converting address"); - exit(EXIT_FAILURE); - } - - printf("Ethernet Destination Address: %s\n", plinkaddr); - } - } - - if(!floods_f){ - if(inet_ntop(AF_INET6, &(idata->srcaddr), psrcaddr, sizeof(psrcaddr)) == NULL){ - puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); - exit(EXIT_FAILURE); - } - - if(idata->dstaddr_f){ - printf("IPv6 Source Address: %s%s\n", psrcaddr, ((idata->srcprefix_f)?" (randomized)":"")); - } - } - else{ - - sanitize_ipv6_prefix(&(idata->srcaddr), idata->srcpreflen); - - if(inet_ntop(AF_INET6, &(idata->srcaddr), psrcaddr, sizeof(psrcaddr)) == NULL){ - puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); - exit(EXIT_FAILURE); - } - - printf("IPv6 Source Address: randomized, from the %s/%u prefix%s\n", psrcaddr, idata->srcpreflen, \ - (!idata->srcprefix_f)?" (default)":""); - } - - if(idata->dstaddr_f){ - if(inet_ntop(AF_INET6, &(idata->dstaddr), pdstaddr, sizeof(pdstaddr)) == NULL){ - puts("inet_ntop(): Error converting IPv6 Destination Address to presentation format"); - exit(EXIT_FAILURE); - } - - printf("IPv6 Destination Address: %s\n", pdstaddr); - } - - printf("IPv6 Hop Limit: %u%s\n", hoplimit, (hoplimit_f)?"":" (default)"); - - for(i=0; ifragh_f) - printf("Sending each packet in fragments of %u bytes (plus the Unfragmentable part)\n", nfrags); - - if(idata->dstaddr_f){ - if(!floodp_f){ - printf("Source Port: %u%s\t", srcport, (srcport_f?"":" (randomized)")); - } - else{ - if(srcportrnd_f){ - sanitize_port(&srcport, srcportpref); - printf("Source Port: (randomized from %u/%u)\t", srcport, srcportpref); - } - else{ - printf("Source Port: (randomized)\t"); - } - } - - if(dstport_f && dstportrnd_f){ - pport= dstport; - sanitize_port(&pport, dstportpref); - printf("Destination Port: (randomized from %u/%u)\n", pport, dstportpref); - } - else{ - printf("Destination Port: %u%s\n", dstport, (dstport_f?"":" (randomized)")); - } - - if( (floods_f || floodp_f) && (nsources != 1 || nports != 1)){ - printf("SEQ Number: (randomized)\t"); - } - else{ - printf("SEQ Number: %u%s\t", tcpseq, (tcpseq_f?"":" (randomized)")); - } - - if(tcpack_f || (tcpflags_f && !(tcpflags & TH_ACK))){ - printf("ACK Number: %u%s\n", tcpack, (tcpack_f?"":" (automatically-selected)")); - } - else{ - if( (floods_f || floodp_f) && (nsources != 1 || nports != 1)){ - printf("ACK Number: (randomized)\n"); - } - else{ - printf("ACK Number: %u (randomized)\n", tcpack); - } - } - - if(tcpflags_f){ - printf("Flags: %s%s%s%s%s%s%s%s\t", ((tcpflags & TH_FIN)?"F":""), ((tcpflags & TH_SYN)?"S":""), \ - ((tcpflags & TH_RST)?"R":""), ((tcpflags & TH_PUSH)?"P":""),\ - ((tcpflags & TH_ACK)?"A":""), ((tcpflags & TH_URG)?"U":""),\ - ((!tcpflags)?"none":""), ((!tcpflags_f)?" (default)":"")); - } - else{ - printf("Flags: Auto\t"); - } - - if(window_f){ - printf("Window (initial): %u%s\t", tcpwin, (tcpwin_f?"":" (randomized)")); - - if(window == WIN_CLOSED) - printf("Window: Closed\n"); - else if(window == WIN_MODULATE) - printf("\nWindow: Modulated (%u byte%s (%u second%s), %u byte%s (%u second%s))\n",\ - win1_size, ((win1_size>1)?"s":""), time1_len, ((time1_len>1)?"s":""), \ - win2_size, ((win2_size>1)?"s":""), time2_len, ((time2_len>1)?"s":"")); - } - else{ - printf("Window: %u%s\t", tcpwin, (tcpwin_f?"":" (randomized)")); - } - - printf("URG Pointer: %u%s\n", tcpurg, (tcpurg_f?"":" (default)")); - } - else{ - printf("Source Port: Auto\tDestination Port: Auto\n"); - - if(tcpseq_f){ - printf("SEQ Number: %u\t", tcpseq); - } - else{ - printf("SEQ Number: Auto\t"); - } - - if(tcpack_f){ - printf("ACK Number: %u\n", tcpack); - } - else{ - printf("ACK Number: Auto\n"); - } - - if(tcpflags_f){ - printf("Flags: %s%s%s%s%s%s%s\t", ((tcpflags & TH_FIN)?"F":""), ((tcpflags & TH_SYN)?"S":""), \ - ((tcpflags & TH_RST)?"R":""), ((tcpflags & TH_PUSH)?"P":""),\ - ((tcpflags & TH_ACK)?"A":""), ((tcpflags & TH_URG)?"U":""),\ - ((!tcpflags)?"none":"")); - } - else{ - printf("Flags: Auto\t"); - } - - if(window_f){ - printf("Window (initial): %u%s\t", tcpwin, (tcpwin_f?"":" (randomized)")); - - if(window == WIN_CLOSED) - printf("Window: Closed\n"); - else if(window == WIN_MODULATE) - printf("\nWindow: Modulated (%u byte%s (%u second%s), %u byte%s (%u second%s))\n",\ - win1_size, ((win1_size>1)?"s":""), time1_len, ((time1_len>1)?"s":""), \ - win2_size, ((win2_size>1)?"s":""), time2_len, ((time2_len>1)?"s":"")); - } - else{ - printf("Window: %u%s\n", tcpwin, (tcpwin_f?"":" (randomized)")); - } - - } -} - +void print_attack_info(struct iface_data *idata) { + puts(SI6_TOOLKIT); + puts("tcp6: Security assessment tool for attack vectors based on TCP/IPv6 packets\n"); + + if (floods_f && !(loop_f && !sleep_f)) + printf("Flooding the target from %u different IPv6 Source Addresses\n", nsources); + + if (floodp_f && !(loop_f && !sleep_f)) + printf("Flooding the target from %u different TCP ports\n", nports); + + if (idata->type == DLT_EN10MB && !(idata->flags & IFACE_LOOPBACK)) { + if (idata->hsrcaddr_f) { + if (ether_ntop(&(idata->hsrcaddr), plinkaddr, sizeof(plinkaddr)) == 0) { + puts("ether_ntop(): Error converting address"); + exit(EXIT_FAILURE); + } + + printf("Ethernet Source Address: %s\n", plinkaddr); + } + else { + if (idata->dstaddr_f) { + if (ether_ntop(&(idata->hsrcaddr), plinkaddr, sizeof(plinkaddr)) == 0) { + puts("ether_ntop(): Error converting address"); + exit(EXIT_FAILURE); + } + + printf("Ethernet Source Address: %s%s\n", plinkaddr, ((!(idata->hsrcaddr_f)) ? " (randomized)" : "")); + } + else + puts("Ethernet Source Address: Automatically selected for each packet"); + } + + /* + Ethernet Destination Address only used if a IPv6 Destination Address or an + Ethernet Destination Address were specified. + */ + if (idata->dstaddr_f) { + if (ether_ntop(&(idata->hdstaddr), plinkaddr, sizeof(plinkaddr)) == 0) { + puts("ether_ntop(): Error converting address"); + exit(EXIT_FAILURE); + } + + printf("Ethernet Destination Address: %s\n", plinkaddr); + } + } + + if (!floods_f) { + if (inet_ntop(AF_INET6, &(idata->srcaddr), psrcaddr, sizeof(psrcaddr)) == NULL) { + puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); + exit(EXIT_FAILURE); + } + + if (idata->dstaddr_f) { + printf("IPv6 Source Address: %s%s\n", psrcaddr, ((idata->srcprefix_f) ? " (randomized)" : "")); + } + } + else { + + sanitize_ipv6_prefix(&(idata->srcaddr), idata->srcpreflen); + + if (inet_ntop(AF_INET6, &(idata->srcaddr), psrcaddr, sizeof(psrcaddr)) == NULL) { + puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); + exit(EXIT_FAILURE); + } + + printf("IPv6 Source Address: randomized, from the %s/%u prefix%s\n", psrcaddr, idata->srcpreflen, + (!idata->srcprefix_f) ? " (default)" : ""); + } + + if (idata->dstaddr_f) { + if (inet_ntop(AF_INET6, &(idata->dstaddr), pdstaddr, sizeof(pdstaddr)) == NULL) { + puts("inet_ntop(): Error converting IPv6 Destination Address to presentation format"); + exit(EXIT_FAILURE); + } + + printf("IPv6 Destination Address: %s\n", pdstaddr); + } + + printf("IPv6 Hop Limit: %u%s\n", hoplimit, (hoplimit_f) ? "" : " (default)"); + + for (i = 0; i < ndstoptuhdr; i++) + printf("Destination Options Header (Unfragmentable part): %u bytes\n", dstoptuhdrlen[i]); + + for (i = 0; i < nhbhopthdr; i++) + printf("Hop by Hop Options Header: %u bytes\n", hbhopthdrlen[i]); + + for (i = 0; i < ndstopthdr; i++) + printf("Destination Options Header: %u bytes\n", dstopthdrlen[i]); + + if (idata->fragh_f) + printf("Sending each packet in fragments of %u bytes (plus the Unfragmentable part)\n", nfrags); + + if (idata->dstaddr_f) { + if (!floodp_f) { + printf("Source Port: %u%s\t", srcport, (srcport_f ? "" : " (randomized)")); + } + else { + if (srcportrnd_f) { + sanitize_port(&srcport, srcportpref); + printf("Source Port: (randomized from %u/%u)\t", srcport, srcportpref); + } + else { + printf("Source Port: (randomized)\t"); + } + } + + if (dstport_f && dstportrnd_f) { + pport = dstport; + sanitize_port(&pport, dstportpref); + printf("Destination Port: (randomized from %u/%u)\n", pport, dstportpref); + } + else { + printf("Destination Port: %u%s\n", dstport, (dstport_f ? "" : " (randomized)")); + } + + if ((floods_f || floodp_f) && (nsources != 1 || nports != 1)) { + printf("SEQ Number: (randomized)\t"); + } + else { + printf("SEQ Number: %u%s\t", tcpseq, (tcpseq_f ? "" : " (randomized)")); + } + + if (tcpack_f || (tcpflags_f && !(tcpflags & TH_ACK))) { + printf("ACK Number: %u%s\n", tcpack, (tcpack_f ? "" : " (automatically-selected)")); + } + else { + if ((floods_f || floodp_f) && (nsources != 1 || nports != 1)) { + printf("ACK Number: (randomized)\n"); + } + else { + printf("ACK Number: %u (randomized)\n", tcpack); + } + } + + if (tcpflags_f) { + printf("Flags: %s%s%s%s%s%s%s%s\t", ((tcpflags & TH_FIN) ? "F" : ""), ((tcpflags & TH_SYN) ? "S" : ""), + ((tcpflags & TH_RST) ? "R" : ""), ((tcpflags & TH_PUSH) ? "P" : ""), + ((tcpflags & TH_ACK) ? "A" : ""), ((tcpflags & TH_URG) ? "U" : ""), ((!tcpflags) ? "none" : ""), + ((!tcpflags_f) ? " (default)" : "")); + } + else { + printf("Flags: Auto\t"); + } + + if (window_f) { + printf("Window (initial): %u%s\t", tcpwin, (tcpwin_f ? "" : " (randomized)")); + + if (window == WIN_CLOSED) + printf("Window: Closed\n"); + else if (window == WIN_MODULATE) + printf("\nWindow: Modulated (%u byte%s (%u second%s), %u byte%s (%u second%s))\n", win1_size, + ((win1_size > 1) ? "s" : ""), time1_len, ((time1_len > 1) ? "s" : ""), win2_size, + ((win2_size > 1) ? "s" : ""), time2_len, ((time2_len > 1) ? "s" : "")); + } + else { + printf("Window: %u%s\t", tcpwin, (tcpwin_f ? "" : " (randomized)")); + } + + printf("URG Pointer: %u%s\n", tcpurg, (tcpurg_f ? "" : " (default)")); + } + else { + printf("Source Port: Auto\tDestination Port: Auto\n"); + + if (tcpseq_f) { + printf("SEQ Number: %u\t", tcpseq); + } + else { + printf("SEQ Number: Auto\t"); + } + + if (tcpack_f) { + printf("ACK Number: %u\n", tcpack); + } + else { + printf("ACK Number: Auto\n"); + } + + if (tcpflags_f) { + printf("Flags: %s%s%s%s%s%s%s\t", ((tcpflags & TH_FIN) ? "F" : ""), ((tcpflags & TH_SYN) ? "S" : ""), + ((tcpflags & TH_RST) ? "R" : ""), ((tcpflags & TH_PUSH) ? "P" : ""), + ((tcpflags & TH_ACK) ? "A" : ""), ((tcpflags & TH_URG) ? "U" : ""), ((!tcpflags) ? "none" : "")); + } + else { + printf("Flags: Auto\t"); + } + + if (window_f) { + printf("Window (initial): %u%s\t", tcpwin, (tcpwin_f ? "" : " (randomized)")); + + if (window == WIN_CLOSED) + printf("Window: Closed\n"); + else if (window == WIN_MODULATE) + printf("\nWindow: Modulated (%u byte%s (%u second%s), %u byte%s (%u second%s))\n", win1_size, + ((win1_size > 1) ? "s" : ""), time1_len, ((time1_len > 1) ? "s" : ""), win2_size, + ((win2_size > 1) ? "s" : ""), time2_len, ((time2_len > 1) ? "s" : "")); + } + else { + printf("Window: %u%s\n", tcpwin, (tcpwin_f ? "" : " (randomized)")); + } + } +} /* * Function: queue_data() @@ -2638,62 +2618,61 @@ void print_attack_info(struct iface_data *idata){ * Puts data into a queue */ -unsigned int queue_data(struct tcp_queue *q, unsigned char *data, unsigned int nbytes){ - unsigned int fbytes, nleft; - - /* - We have to scenarios: in >= out and in < out - In the first scenario, the circular buffer may be "split in two". In the second one, - all available space is clustered together. - */ - if(q->in >= q->out){ - fbytes= (q->data+ q->size) - q->in -1; - fbytes= fbytes+ (q->out - q->data); - - if(nbytes > fbytes) - nbytes= fbytes; - - /* There is enough space available on the right side of the buffer */ - if( (q->data + q->size - q->in) >= nbytes){ - memcpy(q->in, data, nbytes); - - q->in= q->in + nbytes; - - if(q->in == (q->data + q->size)) - q->in= q->data; - - return(nbytes); - } - else{ - nleft= nbytes; - memcpy(q->in, data, (q->data + q->size - q->in)); - - nleft= nleft - (q->data + q->size - q->in); - q->in= q->data; - - memcpy(q->in, data, nleft); - return(nbytes); - } - } - else{ - fbytes= q->out - q->in - 1; - - if(nbytes > fbytes) - nbytes= fbytes; - - memcpy(q->in, data, nbytes); - q->in= q->in + nbytes; - - if(q->in == (q->data + q->size)) - q->in= q->data; - - return(nbytes); - } - - /* Should never reach here, but avoid compiler warnings */ - return(0); -} +unsigned int queue_data(struct tcp_queue *q, unsigned char *data, unsigned int nbytes) { + unsigned int fbytes, nleft; + + /* + We have to scenarios: in >= out and in < out + In the first scenario, the circular buffer may be "split in two". In the second one, + all available space is clustered together. + */ + if (q->in >= q->out) { + fbytes = (q->data + q->size) - q->in - 1; + fbytes = fbytes + (q->out - q->data); + + if (nbytes > fbytes) + nbytes = fbytes; + + /* There is enough space available on the right side of the buffer */ + if ((q->data + q->size - q->in) >= nbytes) { + memcpy(q->in, data, nbytes); + + q->in = q->in + nbytes; + + if (q->in == (q->data + q->size)) + q->in = q->data; + return (nbytes); + } + else { + nleft = nbytes; + memcpy(q->in, data, (q->data + q->size - q->in)); + + nleft = nleft - (q->data + q->size - q->in); + q->in = q->data; + + memcpy(q->in, data, nleft); + return (nbytes); + } + } + else { + fbytes = q->out - q->in - 1; + + if (nbytes > fbytes) + nbytes = fbytes; + + memcpy(q->in, data, nbytes); + q->in = q->in + nbytes; + + if (q->in == (q->data + q->size)) + q->in = q->data; + + return (nbytes); + } + + /* Should never reach here, but avoid compiler warnings */ + return (0); +} /* * Function: dequeue_data() @@ -2701,67 +2680,65 @@ unsigned int queue_data(struct tcp_queue *q, unsigned char *data, unsigned int n * Reads data from a queue */ -unsigned int dequeue_data(struct tcp_queue *q, unsigned char *data, unsigned int nbytes){ - unsigned int dbytes, nleft; - - /* - We have to scenarios: out > in and out <= in - In the first scenario, the circular buffer may be "split in two". In the second one, - all available data are clustered together. - */ - if(q->out > q->in){ - dbytes= (q->data+ q->size) - q->out; - dbytes= dbytes+ (q->in - q->out); - - if(nbytes > dbytes) - nbytes= dbytes; - - /* There is enough data available on the right side of the buffer */ - if( (q->data + q->size - q->out) >= nbytes){ - memcpy(data, q->out, nbytes); - - q->out= q->out + nbytes; - - if(q->out == (q->data + q->size)) - q->out= q->data; - - return(nbytes); - } - else{ - /* Data are split in two parts */ - nleft= nbytes; - memcpy(data, q->out, (q->data + q->size - q->out)); - data= data+ (q->data + q->size - q->out); - - nleft= nleft - (q->data + q->size - q->out); - q->out= q->data; - - memcpy(data, q->out, nleft); - q->out= q->out + nleft; - - return(nbytes); - } - } - else{ - dbytes= q->in - q->out; - - if(nbytes > dbytes) - nbytes= dbytes; - - memcpy(data, q->out, nbytes); - q->out= q->out + nbytes; - - if(q->out == (q->data + q->size)) - q->out= q->data; - - return(nbytes); - } - - /* Should never reach here, but avoid compiler warnings */ - return(0); -} +unsigned int dequeue_data(struct tcp_queue *q, unsigned char *data, unsigned int nbytes) { + unsigned int dbytes, nleft; + + /* + We have to scenarios: out > in and out <= in + In the first scenario, the circular buffer may be "split in two". In the second one, + all available data are clustered together. + */ + if (q->out > q->in) { + dbytes = (q->data + q->size) - q->out; + dbytes = dbytes + (q->in - q->out); + + if (nbytes > dbytes) + nbytes = dbytes; + + /* There is enough data available on the right side of the buffer */ + if ((q->data + q->size - q->out) >= nbytes) { + memcpy(data, q->out, nbytes); + q->out = q->out + nbytes; + if (q->out == (q->data + q->size)) + q->out = q->data; + + return (nbytes); + } + else { + /* Data are split in two parts */ + nleft = nbytes; + memcpy(data, q->out, (q->data + q->size - q->out)); + data = data + (q->data + q->size - q->out); + + nleft = nleft - (q->data + q->size - q->out); + q->out = q->data; + + memcpy(data, q->out, nleft); + q->out = q->out + nleft; + + return (nbytes); + } + } + else { + dbytes = q->in - q->out; + + if (nbytes > dbytes) + nbytes = dbytes; + + memcpy(data, q->out, nbytes); + q->out = q->out + nbytes; + + if (q->out == (q->data + q->size)) + q->out = q->data; + + return (nbytes); + } + + /* Should never reach here, but avoid compiler warnings */ + return (0); +} /* * Function: queue_copy() @@ -2769,58 +2746,58 @@ unsigned int dequeue_data(struct tcp_queue *q, unsigned char *data, unsigned int * Copies data from queue, without removing it */ -unsigned int queue_copy(struct tcp_queue *q, unsigned char *org, unsigned int offset, unsigned char *data, unsigned int nbytes){ - unsigned int dbytes, nleft; - - if(org+offset >= (q->data + q->size)){ - org= q->data + offset - (q->data + q->size - org); - } - - /* | in out - We have to scenarios: out > in and out <= in - In the first scenario, the circular buffer may be "split in two". In the second one, - all available data are clustered together. - */ - if(org > q->in){ - dbytes= (q->data+ q->size) - org; - dbytes= dbytes+ (q->in - org); - - if(nbytes > dbytes) - nbytes= dbytes; - - /* There is enough data available on the right side of the buffer */ - if( (q->data + q->size - org) >= nbytes){ - memcpy(data, org, nbytes); - return(nbytes); - } - else{ - /* Data are split in two parts */ - nleft= nbytes; - memcpy(data, org, (q->data + q->size - org)); - data= data + (q->data + q->size - org); - - nleft= nleft - (q->data + q->size - org); - org= q->data; - - memcpy(data, org, nleft); - return(nbytes); - } - } - else{ - dbytes= q->in - org; - - if(nbytes > dbytes) - nbytes= dbytes; - - memcpy(data, org, nbytes); - return(nbytes); - } - - /* Should never reach here, buts avoid compiler warnings */ - return(0); +unsigned int queue_copy(struct tcp_queue *q, unsigned char *org, unsigned int offset, unsigned char *data, + unsigned int nbytes) { + unsigned int dbytes, nleft; + + if (org + offset >= (q->data + q->size)) { + org = q->data + offset - (q->data + q->size - org); + } + + /* | in out + We have to scenarios: out > in and out <= in + In the first scenario, the circular buffer may be "split in two". In the second one, + all available data are clustered together. + */ + if (org > q->in) { + dbytes = (q->data + q->size) - org; + dbytes = dbytes + (q->in - org); + + if (nbytes > dbytes) + nbytes = dbytes; + + /* There is enough data available on the right side of the buffer */ + if ((q->data + q->size - org) >= nbytes) { + memcpy(data, org, nbytes); + return (nbytes); + } + else { + /* Data are split in two parts */ + nleft = nbytes; + memcpy(data, org, (q->data + q->size - org)); + data = data + (q->data + q->size - org); + + nleft = nleft - (q->data + q->size - org); + org = q->data; + + memcpy(data, org, nleft); + return (nbytes); + } + } + else { + dbytes = q->in - org; + + if (nbytes > dbytes) + nbytes = dbytes; + + memcpy(data, org, nbytes); + return (nbytes); + } + + /* Should never reach here, buts avoid compiler warnings */ + return (0); } - /* * Function: queue_remove() * @@ -2829,100 +2806,96 @@ unsigned int queue_copy(struct tcp_queue *q, unsigned char *org, unsigned int of * by the remote TCP endpoint. */ -unsigned int queue_remove(struct tcp_queue *q, unsigned char *data, unsigned int nbytes){ - unsigned int dbytes, nleft; - - /* - We have to scenarios: out > in and out <= in - In the first scenario, the circular buffer may be "split in two". In the second one, - all available data are clustered together. - */ - if(q->out > q->in){ - dbytes= (q->data+ q->size) - q->out; - dbytes= dbytes+ (q->in - q->out); - - if(nbytes > dbytes) - nbytes= dbytes; - - /* There is enough data available on the right side of the buffer */ - if( (q->data + q->size - q->out) >= nbytes){ - q->out= q->out + nbytes; - - if(q->out == (q->data + q->size)) - q->out= q->data; - - return(nbytes); - } - else{ - /* Data are split in two parts */ - nleft= nbytes; - data= data+ (q->data + q->size - q->out); - nleft= nleft - (q->data + q->size - q->out); - q->out= q->data; - q->out= q->out + nleft; - return(nbytes); - } - } - else{ - dbytes= q->in - q->out; - - if(nbytes > dbytes) - nbytes= dbytes; - - memcpy(data, q->out, nbytes); - q->out= q->out + nbytes; - - if(q->out == (q->data + q->size)) - q->out= q->data; - - return(nbytes); - } - - /* Should never reach here, but avoid compiler warnings */ - return(0); +unsigned int queue_remove(struct tcp_queue *q, unsigned char *data, unsigned int nbytes) { + unsigned int dbytes, nleft; + + /* + We have to scenarios: out > in and out <= in + In the first scenario, the circular buffer may be "split in two". In the second one, + all available data are clustered together. + */ + if (q->out > q->in) { + dbytes = (q->data + q->size) - q->out; + dbytes = dbytes + (q->in - q->out); + + if (nbytes > dbytes) + nbytes = dbytes; + + /* There is enough data available on the right side of the buffer */ + if ((q->data + q->size - q->out) >= nbytes) { + q->out = q->out + nbytes; + + if (q->out == (q->data + q->size)) + q->out = q->data; + + return (nbytes); + } + else { + /* Data are split in two parts */ + nleft = nbytes; + data = data + (q->data + q->size - q->out); + nleft = nleft - (q->data + q->size - q->out); + q->out = q->data; + q->out = q->out + nleft; + return (nbytes); + } + } + else { + dbytes = q->in - q->out; + + if (nbytes > dbytes) + nbytes = dbytes; + + memcpy(data, q->out, nbytes); + q->out = q->out + nbytes; + + if (q->out == (q->data + q->size)) + q->out = q->data; + + return (nbytes); + } + + /* Should never reach here, but avoid compiler warnings */ + return (0); } - - /* * Function: tcp_init() * * Initilizes a TCP structure */ -int tcp_init(struct tcp *tcp){ - memset(&(tcp->srcaddr), 0, sizeof(struct in6_addr)); - memset(&(tcp->dstaddr), 0, sizeof(struct in6_addr)); - tcp->srcport= 0; - tcp->dstport= 0; - - tcp->in.in = tcp->in.data; - tcp->in.out= tcp->in.data; - tcp->in.size= sizeof(tcp->in.data); +int tcp_init(struct tcp *tcp) { + memset(&(tcp->srcaddr), 0, sizeof(struct in6_addr)); + memset(&(tcp->dstaddr), 0, sizeof(struct in6_addr)); + tcp->srcport = 0; + tcp->dstport = 0; - tcp->rcv_nxt= 0; - tcp->rcv_nxtwnd= 0; + tcp->in.in = tcp->in.data; + tcp->in.out = tcp->in.data; + tcp->in.size = sizeof(tcp->in.data); - tcp->out.in= tcp->out.data; - tcp->out.out= tcp->out.data; - tcp->out.size= sizeof(tcp->out.data); + tcp->rcv_nxt = 0; + tcp->rcv_nxtwnd = 0; - tcp->out_una= tcp->out.data; - tcp->out_nxt= tcp->out.data; + tcp->out.in = tcp->out.data; + tcp->out.out = tcp->out.data; + tcp->out.size = sizeof(tcp->out.data); - tcp->snd_una=0; - tcp->snd_nxtwnd=0; - - memset(&(tcp->time), 0, sizeof(struct timeval)); - tcp->state= TCP_CLOSED; + tcp->out_una = tcp->out.data; + tcp->out_nxt = tcp->out.data; - tcp->ack= 0; - tcp->win= sizeof(tcp->in.data) - 1; + tcp->snd_una = 0; + tcp->snd_nxtwnd = 0; - return(SUCCESS); -} + memset(&(tcp->time), 0, sizeof(struct timeval)); + tcp->state = TCP_CLOSED; + tcp->ack = 0; + tcp->win = sizeof(tcp->in.data) - 1; + return (SUCCESS); +} /* * Function: tcp_open() @@ -2930,146 +2903,137 @@ int tcp_init(struct tcp *tcp){ * Performs an open (active or passive) on a TCP socket */ -int tcp_open(struct iface_data *idata, struct tcp *tcb, unsigned int mode){ - if(mode == OPEN_ACTIVE){ - tcb->state= TCP_SYN_SENT; - tcb->flags= TH_SYN; - tcb->snd_una= random(); - tcb->snd_nxt= tcb->snd_una + 1; - tcb->pending_write_f= TRUE; - return(SUCCESS); - } - else if(mode == OPEN_PASSIVE){ - tcb->state= TCP_LISTEN; - return(SUCCESS); - } - - return(FAILURE); +int tcp_open(struct iface_data *idata, struct tcp *tcb, unsigned int mode) { + if (mode == OPEN_ACTIVE) { + tcb->state = TCP_SYN_SENT; + tcb->flags = TH_SYN; + tcb->snd_una = random(); + tcb->snd_nxt = tcb->snd_una + 1; + tcb->pending_write_f = TRUE; + return (SUCCESS); + } + else if (mode == OPEN_PASSIVE) { + tcb->state = TCP_LISTEN; + return (SUCCESS); + } + + return (FAILURE); } - /* * Function: tcp_close() * * Performs a close on a TCP socket */ -int tcp_close(struct iface_data *idata, struct tcp *tcb){ - tcb->fin_flag= TRUE; - tcb->fin_seq= tcb->snd_nxt; - tcb->pending_write_f= TRUE; - return(SUCCESS); +int tcp_close(struct iface_data *idata, struct tcp *tcb) { + tcb->fin_flag = TRUE; + tcb->fin_seq = tcb->snd_nxt; + tcb->pending_write_f = TRUE; + return (SUCCESS); } - /* * Function: tcp_send() * * Sends data over TCP (actually copies it to the TCP send buffer) */ -int tcp_send(struct iface_data *idata, struct tcp *tcb, unsigned char *data, unsigned int nbytes){ - if(tcb->fin_flag == TRUE) - return(-1); - else - return(queue_data( &(tcb->out), data, nbytes)); +int tcp_send(struct iface_data *idata, struct tcp *tcb, unsigned char *data, unsigned int nbytes) { + if (tcb->fin_flag == TRUE) + return (-1); + else + return (queue_data(&(tcb->out), data, nbytes)); } - /* * Function: tcp_receive() * * Receive data from a TCP socket */ -int tcp_receive(struct iface_data *idata, struct tcp *tcb, unsigned char *data, unsigned int nbytes){ - unsigned int r; +int tcp_receive(struct iface_data *idata, struct tcp *tcb, unsigned char *data, unsigned int nbytes) { + unsigned int r; - r= dequeue_data(&(tcb->in), data, nbytes); + r = dequeue_data(&(tcb->in), data, nbytes); - if(r > 0) - tcb->pending_write_f= TRUE; + if (r > 0) + tcb->pending_write_f = TRUE; - return(r); + return (r); } - /* * Function: tcp_input() * * Processes an incoming TCP segment */ -int tcp_input(struct iface_data *idata, struct tcp *tcb, const u_char *pktdata, struct pcap_pkthdr *pkthdr, struct packet *packet){ - return(SUCCESS); +int tcp_input(struct iface_data *idata, struct tcp *tcb, const u_char *pktdata, struct pcap_pkthdr *pkthdr, + struct packet *packet) { + return (SUCCESS); } - - /* * Function: tcp_output() * * Sends TCP segments as necessary */ -int tcp_output(struct iface_data *idata, struct tcp *tcb, struct packet *packet, struct timeval *curtime){ - /* Placeholder */ - return(SUCCESS); +int tcp_output(struct iface_data *idata, struct tcp *tcb, struct packet *packet, struct timeval *curtime) { + /* Placeholder */ + return (SUCCESS); } - - /* * Function: is_valid_tcp_segment() * * Performs sanity checks on an incomming TCP/IPv6 segment */ -int is_valid_tcp_segment(struct iface_data *idata, const u_char *pktdata, struct pcap_pkthdr *pkthdr){ - struct ether_header *pkt_ether; - struct ip6_hdr *pkt_ipv6; - struct tcp_hdr *pkt_tcp; - unsigned char *pkt_end; - - pkt_ether = (struct ether_header *) pktdata; - pkt_ipv6 = (struct ip6_hdr *)((char *) pkt_ether + idata->linkhsize); - pkt_tcp = (struct tcp_hdr *) ((char *) pkt_ipv6 + MIN_IPV6_HLEN); - - pkt_end = (unsigned char *) pktdata + pkthdr->caplen; - - /* XXX: We are assuming no extension headers on incoming packets -- this should be improved! */ - - /* The packet length is the minimum of what we capured, and what is specified in the - IPv6 Total Lenght field - */ - if( pkt_end > ((unsigned char *)pkt_tcp + ntohs(pkt_ipv6->ip6_plen)) ) - pkt_end = (unsigned char *)pkt_tcp + ntohs(pkt_ipv6->ip6_plen); - - /* - Discard the packet if it is not of the minimum size to contain a TCP header - */ - if( (pkt_end - (unsigned char *) pkt_tcp) < sizeof(struct tcp_hdr)){ - return FALSE; - } - - /* Check that the TCP checksum is correct */ - if(in_chksum(pkt_ipv6, pkt_tcp, pkt_end-((unsigned char *)pkt_tcp), IPPROTO_TCP) != 0){ - return FALSE; - } - - - /* XXX: Should perform additional checks on the IPv6 header */ - /* - Sanity checks on the Source Address and the Destination Address - */ - if(IN6_IS_ADDR_UNSPECIFIED(&(pkt_ipv6->ip6_src)) || IN6_IS_ADDR_UNSPECIFIED(&(pkt_ipv6->ip6_dst))){ - return FALSE; - } - - if(IN6_IS_ADDR_MULTICAST(&(pkt_ipv6->ip6_src)) || IN6_IS_ADDR_MULTICAST(&(pkt_ipv6->ip6_dst))){ - return FALSE; - } - - return TRUE; +int is_valid_tcp_segment(struct iface_data *idata, const u_char *pktdata, struct pcap_pkthdr *pkthdr) { + struct ether_header *pkt_ether; + struct ip6_hdr *pkt_ipv6; + struct tcp_hdr *pkt_tcp; + unsigned char *pkt_end; + + pkt_ether = (struct ether_header *)pktdata; + pkt_ipv6 = (struct ip6_hdr *)((char *)pkt_ether + idata->linkhsize); + pkt_tcp = (struct tcp_hdr *)((char *)pkt_ipv6 + MIN_IPV6_HLEN); + + pkt_end = (unsigned char *)pktdata + pkthdr->caplen; + + /* XXX: We are assuming no extension headers on incoming packets -- this should be improved! */ + + /* The packet length is the minimum of what we capured, and what is specified in the + IPv6 Total Lenght field + */ + if (pkt_end > ((unsigned char *)pkt_tcp + ntohs(pkt_ipv6->ip6_plen))) + pkt_end = (unsigned char *)pkt_tcp + ntohs(pkt_ipv6->ip6_plen); + + /* + Discard the packet if it is not of the minimum size to contain a TCP header + */ + if ((pkt_end - (unsigned char *)pkt_tcp) < sizeof(struct tcp_hdr)) { + return FALSE; + } + + /* Check that the TCP checksum is correct */ + if (in_chksum(pkt_ipv6, pkt_tcp, pkt_end - ((unsigned char *)pkt_tcp), IPPROTO_TCP) != 0) { + return FALSE; + } + + /* XXX: Should perform additional checks on the IPv6 header */ + /* + Sanity checks on the Source Address and the Destination Address + */ + if (IN6_IS_ADDR_UNSPECIFIED(&(pkt_ipv6->ip6_src)) || IN6_IS_ADDR_UNSPECIFIED(&(pkt_ipv6->ip6_dst))) { + return FALSE; + } + + if (IN6_IS_ADDR_MULTICAST(&(pkt_ipv6->ip6_src)) || IN6_IS_ADDR_MULTICAST(&(pkt_ipv6->ip6_dst))) { + return FALSE; + } + + return TRUE; } - diff --git a/tools/tcp6.h b/tools/tcp6.h index 0499ed3..49fee09 100644 --- a/tools/tcp6.h +++ b/tools/tcp6.h @@ -3,107 +3,100 @@ * */ - /* Constants used for specification of TCP connection establishment */ -#define OPEN_PASSIVE 1 -#define OPEN_SIMULTANEOUS 2 -#define OPEN_ABORT 3 -#define OPEN_ACTIVE 4 - +#define OPEN_PASSIVE 1 +#define OPEN_SIMULTANEOUS 2 +#define OPEN_ABORT 3 +#define OPEN_ACTIVE 4 /* Constants used for specification of TCP connection termination */ -#define CLOSE_ACTIVE 1 -#define CLOSE_PASSIVE 2 -#define CLOSE_SIMULTANEOUS 3 -#define CLOSE_ABORT 4 -#define CLOSE_FIN_WAIT_1 5 -#define CLOSE_FIN_WAIT_2 6 -#define CLOSE_LAST_ACK 7 - +#define CLOSE_ACTIVE 1 +#define CLOSE_PASSIVE 2 +#define CLOSE_SIMULTANEOUS 3 +#define CLOSE_ABORT 4 +#define CLOSE_FIN_WAIT_1 5 +#define CLOSE_FIN_WAIT_2 6 +#define CLOSE_LAST_ACK 7 /* Constants for TCP window operation */ -#define WIN_CLOSED 1 -#define WIN_MODULATE 2 -#define WIN_MODULATE_CLOSED_SIZE 0 -#define WIN_MODULATE_CLOSED_LEN 60 -#define WIN_MODULATE_OPEN_SIZE 10 -#define WIN_MODULATE_OPEN_LEN 30 -#define TCP_RTO 1 +#define WIN_CLOSED 1 +#define WIN_MODULATE 2 +#define WIN_MODULATE_CLOSED_SIZE 0 +#define WIN_MODULATE_CLOSED_LEN 60 +#define WIN_MODULATE_OPEN_SIZE 10 +#define WIN_MODULATE_OPEN_LEN 30 +#define TCP_RTO 1 /* Constants for specifying the TCP connection state */ -#define TCP_CLOSED 1 -#define TCP_LISTEN 2 -#define TCP_SYN_SENT 3 -#define TCP_SYN_RECV 4 -#define TCP_ESTABLISHED 5 -#define TCP_FIN_WAIT_1 6 -#define TCP_FIN_WAIT_2 7 -#define TCP_CLOSE_WAIT 8 -#define TCP_LAST_ACK 9 -#define TCP_CLOSING 10 -#define TCP_TIME_WAIT 11 - +#define TCP_CLOSED 1 +#define TCP_LISTEN 2 +#define TCP_SYN_SENT 3 +#define TCP_SYN_RECV 4 +#define TCP_ESTABLISHED 5 +#define TCP_FIN_WAIT_1 6 +#define TCP_FIN_WAIT_2 7 +#define TCP_CLOSE_WAIT 8 +#define TCP_LAST_ACK 9 +#define TCP_CLOSING 10 +#define TCP_TIME_WAIT 11 /* Constants for debug mode */ -#define PROBE_DUMP 1 -#define PROBE_SCRIPT 2 +#define PROBE_DUMP 1 +#define PROBE_SCRIPT 2 /* Constants for TCP buffers */ -#define TCP_BUFFER_SIZE 65535 -#define TCP_INPUT_BUFFER_SIZE TCP_BUFFER_SIZE -#define TCP_OUTPUT_BUFFER_SIZE TCP_BUFFER_SIZE - - -struct tcp_queue{ - unsigned char data[TCP_BUFFER_SIZE]; - unsigned char *in; - unsigned char *out; - unsigned int size; -/* unsigned int data; */ - unsigned int free; +#define TCP_BUFFER_SIZE 65535 +#define TCP_INPUT_BUFFER_SIZE TCP_BUFFER_SIZE +#define TCP_OUTPUT_BUFFER_SIZE TCP_BUFFER_SIZE + +struct tcp_queue { + unsigned char data[TCP_BUFFER_SIZE]; + unsigned char *in; + unsigned char *out; + unsigned int size; + /* unsigned int data; */ + unsigned int free; }; - -struct tcp{ - struct in6_addr srcaddr; - struct in6_addr dstaddr; - uint16_t srcport; - uint16_t dstport; - - struct tcp_queue in; - uint32_t rcv_nxt; - uint32_t rcv_nxtwnd; - - struct tcp_queue out; - unsigned char *out_una; - unsigned char *out_nxt; /* una nxt */ - uint32_t snd_una; - uint32_t snd_nxt; - uint32_t snd_nxtwnd; - uint32_t snd_seq; /* TCP seq to use for outgoing segments (for RSTs) */ - uint32_t snd_wl1; - uint32_t snd_wl2; - - unsigned char fin_flag; - uint32_t fin_seq; - - struct timeval time; - unsigned int state; - unsigned int open; - unsigned int close; - uint8_t flags; - uint32_t ack; - uint32_t win; - - unsigned int fbytes; - - unsigned char pending_write_f; - unsigned int rto; +struct tcp { + struct in6_addr srcaddr; + struct in6_addr dstaddr; + uint16_t srcport; + uint16_t dstport; + + struct tcp_queue in; + uint32_t rcv_nxt; + uint32_t rcv_nxtwnd; + + struct tcp_queue out; + unsigned char *out_una; + unsigned char *out_nxt; /* una nxt */ + uint32_t snd_una; + uint32_t snd_nxt; + uint32_t snd_nxtwnd; + uint32_t snd_seq; /* TCP seq to use for outgoing segments (for RSTs) */ + uint32_t snd_wl1; + uint32_t snd_wl2; + + unsigned char fin_flag; + uint32_t fin_seq; + + struct timeval time; + unsigned int state; + unsigned int open; + unsigned int close; + uint8_t flags; + uint32_t ack; + uint32_t win; + + unsigned int fbytes; + + unsigned char pending_write_f; + unsigned int rto; }; - -#define SEQ_LT(a,b) ((int)((a)-(b)) < 0) -#define SEQ_LEQ(a,b) ((int)((a)-(b)) <= 0) -#define SEQ_GT(a,b) ((int)((a)-(b)) > 0) -#define SEQ_GEQ(a,b) ((int)((a)-(b)) >= 0) -#define SEQ_EQ(a,b) ((int)((a)-(b)) == 0) +#define SEQ_LT(a, b) ((int)((a) - (b)) < 0) +#define SEQ_LEQ(a, b) ((int)((a) - (b)) <= 0) +#define SEQ_GT(a, b) ((int)((a) - (b)) > 0) +#define SEQ_GEQ(a, b) ((int)((a) - (b)) >= 0) +#define SEQ_EQ(a, b) ((int)((a) - (b)) == 0) diff --git a/tools/udp6.c b/tools/udp6.c index a3dfa7a..40b1bd5 100644 --- a/tools/udp6.c +++ b/tools/udp6.c @@ -18,2009 +18,1980 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . - * + * * Build with: make udp6 - * + * * It requires that the libpcap library be installed on your system. * * Please send any bug reports to Fernando Gont */ -#include -#include #include #include +#include +#include +#include #include +#include #include #include -#include -#include -#include -#include -#include #include -#include #include #include -#include +#include +#include +#include #include +#include +#include #include -#include -#include +#include +#include -#include "udp6.h" #include "ipv6toolkit.h" #include "libipv6.h" - +#include "udp6.h" /* Function prototypes */ -void init_packet_data(struct iface_data *); -void send_packet(struct iface_data *, const u_char *, struct pcap_pkthdr *); -void print_attack_info(struct iface_data *); -void usage(void); -void print_help(void); -void frag_and_send(struct iface_data *); -int is_valid_udp_datagram(struct iface_data *, const u_char *, struct pcap_pkthdr *); +void init_packet_data(struct iface_data *); +void send_packet(struct iface_data *, const u_char *, struct pcap_pkthdr *); +void print_attack_info(struct iface_data *); +void usage(void); +void print_help(void); +void frag_and_send(struct iface_data *); +int is_valid_udp_datagram(struct iface_data *, const u_char *, struct pcap_pkthdr *); /* Flags */ -unsigned char floodt_f=0; -unsigned char listen_f=0, accepted_f=0, loop_f=0, sleep_f=0; -unsigned char hoplimit_f=0, rand_link_src_f=0, rand_src_f=0; -unsigned char floods_f=0, floodp_f=0, donesending_f=0; -unsigned char data_f=0, senddata_f=0, useaddrkey_f=0; +unsigned char floodt_f = 0; +unsigned char listen_f = 0, accepted_f = 0, loop_f = 0, sleep_f = 0; +unsigned char hoplimit_f = 0, rand_link_src_f = 0, rand_src_f = 0; +unsigned char floods_f = 0, floodp_f = 0, donesending_f = 0; +unsigned char data_f = 0, senddata_f = 0, useaddrkey_f = 0; + +/* Flags used for UDP (specifically) */ +unsigned char srcport_f = 0, dstport_f = 0, srcportrnd_f = 0, dstportrnd_f = 0; +unsigned char rhbytes_f = 0; +unsigned char pps_f = 0, bps_f = 0, probemode_f = 0, retrans_f = 0, rto_f = 0; +unsigned int probemode; + +uint16_t srcport, dstport, pport; +uint8_t srcportpref, dstportpref; +unsigned int retrans, rto; +unsigned int rhbytes, currentsize, packetsize; + +/* Used for router discovery */ +struct iface_data idata; -/* Flags used for UDP (specifically) */ -unsigned char srcport_f=0, dstport_f=0, srcportrnd_f=0, dstportrnd_f=0; -unsigned char rhbytes_f=0; -unsigned char pps_f=0, bps_f=0, probemode_f=0, retrans_f=0, rto_f=0; -unsigned int probemode; +/* Data structures for packets read from the wire */ +struct pcap_pkthdr *pkthdr; +const u_char *pktdata; +unsigned char *pkt_end; +struct ether_header *pkt_ether; +struct nd_neighbor_solicit *pkt_ns; +struct ip6_hdr *pkt_ipv6; +struct udp_hdr *pkt_udp; +struct in6_addr *pkt_ipv6addr; +unsigned int pktbytes; + +bpf_u_int32 my_netmask; +bpf_u_int32 my_ip; +struct bpf_program pcap_filter; +char dev[64], errbuf[PCAP_ERRBUF_SIZE]; +unsigned char buffer[65556], buffrh[MIN_IPV6_HLEN + MIN_UDP_HLEN]; +unsigned char *v6buffer, *ptr, *startofprefixes; +char *pref; +char data[DATA_BUFFER_LEN]; +unsigned int datalen; +char iface[IFACE_LENGTH]; +char line[LINE_BUFFER_SIZE]; + +struct ip6_hdr *ipv6; +struct udp_hdr *udp; + +struct ether_header *ethernet; +struct nd_opt_tlla *tllaopt; + +struct in6_addr targetaddr, randprefix; +struct ether_addr linkaddr[MAX_TLLA_OPTION]; +unsigned int nlinkaddr = 0, linkaddrs; + +char *lasts, *rpref; +char *charptr; + +int nw; +unsigned long ul_res, ul_val, rate; +unsigned int i, j, startrand; +unsigned int skip; +unsigned int sources, nsources, ports, nports, nsleep; +unsigned char randpreflen; + +uint16_t mask; +uint8_t hoplimit; +uint16_t addr_key; + +char plinkaddr[ETHER_ADDR_PLEN]; +char psrcaddr[INET6_ADDRSTRLEN], pdstaddr[INET6_ADDRSTRLEN], pv6addr[INET6_ADDRSTRLEN]; -uint16_t srcport, dstport, pport; -uint8_t srcportpref, dstportpref; -unsigned int retrans, rto; -unsigned int rhbytes, currentsize, packetsize; +/* Support for Extension Headers */ +unsigned int dstopthdrs, dstoptuhdrs, hbhopthdrs; +char hbhopthdr_f = 0, dstoptuhdr_f = 0, dstopthdr_f = 0; +unsigned char *dstopthdr[MAX_DST_OPT_HDR], *dstoptuhdr[MAX_DST_OPT_U_HDR]; +unsigned char *hbhopthdr[MAX_HBH_OPT_HDR]; +unsigned int dstopthdrlen[MAX_DST_OPT_HDR], dstoptuhdrlen[MAX_DST_OPT_U_HDR]; +unsigned int hbhopthdrlen[MAX_HBH_OPT_HDR], m, pad; + +struct ip6_frag fraghdr, *fh; +struct ip6_hdr *fipv6; + +unsigned char fragbuffer[ETHER_HDR_LEN + MIN_IPV6_HLEN + MAX_IPV6_PAYLOAD]; +unsigned char *fragpart, *fptr, *fptrend, *ptrend, *ptrhdr, *ptrhdrend; +unsigned int hdrlen, ndstopthdr = 0, nhbhopthdr = 0, ndstoptuhdr = 0; +unsigned int nfrags, fragsize; +unsigned char *prev_nh, *startoffragment; + +struct filters filters; + +int main(int argc, char **argv) { + extern char *optarg; + /* char *endptr; Used by strtoul() */ + fd_set sset, rset; + /* fd_set wset, eset; */ + int r, sel; + struct timeval timeout, stimeout, curtime, lastprobe; + unsigned char end_f = 0; + unsigned long pktinterval = 0; + unsigned int retr = 0; + struct target_ipv6 targetipv6; + + static struct option longopts[] = {{"interface", required_argument, 0, 'i'}, + {"src-addr", required_argument, 0, 's'}, + {"dst-addr", required_argument, 0, 'd'}, + {"hop-limit", required_argument, 0, 'A'}, + {"data", required_argument, 0, 'Z'}, + {"dst-opt-hdr", required_argument, 0, 'u'}, + {"dst-opt-u-hdr", required_argument, 0, 'U'}, + {"hbh-opt-hdr", required_argument, 0, 'H'}, + {"frag-hdr", required_argument, 0, 'y'}, + {"link-src-addr", required_argument, 0, 'S'}, + {"link-dst-addr", required_argument, 0, 'D'}, + {"payload-size", required_argument, 0, 'P'}, + {"src-port", required_argument, 0, 'o'}, + {"dst-port", required_argument, 0, 'a'}, + {"block-src-addr", required_argument, 0, 'j'}, + {"block-dst-addr", required_argument, 0, 'k'}, + {"block-link-src-addr", required_argument, 0, 'J'}, + {"block-link-dst-addr", required_argument, 0, 'K'}, + {"accept-src-addr", required_argument, 0, 'b'}, + {"accept-dst-addr", required_argument, 0, 'g'}, + {"accept-link-src-addr", required_argument, 0, 'B'}, + {"accept-link-dst-addr", required_argument, 0, 'G'}, + {"flood-sources", required_argument, 0, 'F'}, + {"flood-ports", required_argument, 0, 'T'}, + {"loop", no_argument, 0, 'l'}, + {"rate-limit", required_argument, 0, 'r'}, + {"sleep", required_argument, 0, 'z'}, + {"listen", no_argument, 0, 'L'}, + {"probe-mode", required_argument, 0, 'p'}, + {"retrans", required_argument, 0, 'x'}, + {"verbose", no_argument, 0, 'v'}, + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0}}; + + const char shortopts[] = "i:s:d:A:Z:u:U:H:y:S:D:P:o:a:j:k:J:K:b:g:B:G:F:T:lr:z:Lp:x:vh"; + + char option; + + if (argc <= 1) { + usage(); + exit(EXIT_FAILURE); + } + + hoplimit = 255; + + lastprobe.tv_sec = 0; + lastprobe.tv_usec = 0; + + /* Initialize filters structure */ + if (init_filters(&filters) == -1) { + puts("Error initializing internal data structure"); + exit(EXIT_FAILURE); + } + + if (init_iface_data(&idata) == FAILURE) { + puts("Error initializing internal data structure"); + exit(EXIT_FAILURE); + } + + while ((r = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { + option = r; + + switch (option) { + case 'i': /* Interface */ + strncpy(idata.iface, optarg, IFACE_LENGTH); + idata.iface[IFACE_LENGTH - 1] = 0; + idata.ifindex = if_nametoindex(idata.iface); + idata.iface_f = TRUE; + break; + + case 's': /* IPv6 Source Address */ + if (idata.srcaddr_f) { + puts("Error: Multiple '-s' options have been specified"); + exit(EXIT_FAILURE); + } + + if ((charptr = strtok_r(optarg, "/", &lasts)) == NULL) { + puts("Error in Source Address"); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, charptr, &(idata.srcaddr)) <= 0) { + puts("inet_pton(): Source Address not valid"); + exit(EXIT_FAILURE); + } + + idata.srcaddr_f = 1; + + if ((charptr = strtok_r(NULL, " ", &lasts)) != NULL) { + idata.srcpreflen = atoi(charptr); + + if (idata.srcpreflen > 128) { + puts("Prefix length error in IPv6 Source Address"); + exit(EXIT_FAILURE); + } + + if (idata.srcpreflen == 64) + useaddrkey_f = 1; + + sanitize_ipv6_prefix(&(idata.srcaddr), idata.srcpreflen); + idata.srcprefix_f = 1; + } + + break; + + case 'd': /* IPv6 Destination Address */ + strncpy(targetipv6.name, optarg, NI_MAXHOST); + targetipv6.name[NI_MAXHOST - 1] = 0; + targetipv6.flags = AI_CANONNAME; + + if ((r = get_ipv6_target(&targetipv6)) != 0) { + + if (r < 0) { + printf("Unknown Destination: %s\n", gai_strerror(targetipv6.res)); + } + else { + puts("Unknown Destination: No IPv6 address found for specified destination"); + } + + exit(EXIT_FAILURE); + } + + idata.dstaddr = targetipv6.ip6; + idata.dstaddr_f = 1; + break; + + case 'A': /* Hop Limit */ + hoplimit = atoi(optarg); + hoplimit_f = 1; + break; + case 'Z': /* Data */ + datalen = Strnlen(optarg, MAX_CMDLINE_OPT_LEN); -/* Used for router discovery */ -struct iface_data idata; + if (datalen >= DATA_BUFFER_LEN) + datalen = DATA_BUFFER_LEN - 1; -/* Data structures for packets read from the wire */ -struct pcap_pkthdr *pkthdr; -const u_char *pktdata; -unsigned char *pkt_end; -struct ether_header *pkt_ether; -struct nd_neighbor_solicit *pkt_ns; -struct ip6_hdr *pkt_ipv6; -struct udp_hdr *pkt_udp; -struct in6_addr *pkt_ipv6addr; -unsigned int pktbytes; - - -bpf_u_int32 my_netmask; -bpf_u_int32 my_ip; -struct bpf_program pcap_filter; -char dev[64], errbuf[PCAP_ERRBUF_SIZE]; -unsigned char buffer[65556], buffrh[MIN_IPV6_HLEN + MIN_UDP_HLEN]; -unsigned char *v6buffer, *ptr, *startofprefixes; -char *pref; -char data[DATA_BUFFER_LEN]; -unsigned int datalen; -char iface[IFACE_LENGTH]; -char line[LINE_BUFFER_SIZE]; - -struct ip6_hdr *ipv6; -struct udp_hdr *udp; - -struct ether_header *ethernet; -struct nd_opt_tlla *tllaopt; - -struct in6_addr targetaddr, randprefix; -struct ether_addr linkaddr[MAX_TLLA_OPTION]; -unsigned int nlinkaddr=0, linkaddrs; - -char *lasts, *rpref; -char *charptr; - -int nw; -unsigned long ul_res, ul_val, rate; -unsigned int i, j, startrand; -unsigned int skip; -unsigned int sources, nsources, ports, nports, nsleep; -unsigned char randpreflen; - -uint16_t mask; -uint8_t hoplimit; -uint16_t addr_key; - -char plinkaddr[ETHER_ADDR_PLEN]; -char psrcaddr[INET6_ADDRSTRLEN], pdstaddr[INET6_ADDRSTRLEN], pv6addr[INET6_ADDRSTRLEN]; + strncpy(data, optarg, DATA_BUFFER_LEN - 1); + data_f = 1; + break; + + case 'u': /* Destinations Options Header */ + if (ndstopthdr >= MAX_DST_OPT_HDR) { + puts("Too many Destination Options Headers"); + exit(EXIT_FAILURE); + } + + hdrlen = atoi(optarg); + + if (hdrlen < 8) { + puts("Bad length in Destination Options Header"); + exit(EXIT_FAILURE); + } + hdrlen = ((hdrlen + 7) / 8) * 8; + dstopthdrlen[ndstopthdr] = hdrlen; -/* Support for Extension Headers */ -unsigned int dstopthdrs, dstoptuhdrs, hbhopthdrs; -char hbhopthdr_f=0, dstoptuhdr_f=0, dstopthdr_f=0; -unsigned char *dstopthdr[MAX_DST_OPT_HDR], *dstoptuhdr[MAX_DST_OPT_U_HDR]; -unsigned char *hbhopthdr[MAX_HBH_OPT_HDR]; -unsigned int dstopthdrlen[MAX_DST_OPT_HDR], dstoptuhdrlen[MAX_DST_OPT_U_HDR]; -unsigned int hbhopthdrlen[MAX_HBH_OPT_HDR], m, pad; - -struct ip6_frag fraghdr, *fh; -struct ip6_hdr *fipv6; - -unsigned char fragbuffer[ETHER_HDR_LEN+MIN_IPV6_HLEN+MAX_IPV6_PAYLOAD]; -unsigned char *fragpart, *fptr, *fptrend, *ptrend, *ptrhdr, *ptrhdrend; -unsigned int hdrlen, ndstopthdr=0, nhbhopthdr=0, ndstoptuhdr=0; -unsigned int nfrags, fragsize; -unsigned char *prev_nh, *startoffragment; - -struct filters filters; - -int main(int argc, char **argv){ - extern char *optarg; -/* char *endptr; Used by strtoul() */ - fd_set sset, rset; -/* fd_set wset, eset; */ - int r, sel; - struct timeval timeout, stimeout, curtime, lastprobe; - unsigned char end_f=0; - unsigned long pktinterval=0; - unsigned int retr=0; - struct target_ipv6 targetipv6; - - static struct option longopts[] = { - {"interface", required_argument, 0, 'i'}, - {"src-addr", required_argument, 0, 's'}, - {"dst-addr", required_argument, 0, 'd'}, - {"hop-limit", required_argument, 0, 'A'}, - {"data", required_argument, 0, 'Z'}, - {"dst-opt-hdr", required_argument, 0, 'u'}, - {"dst-opt-u-hdr", required_argument, 0, 'U'}, - {"hbh-opt-hdr", required_argument, 0, 'H'}, - {"frag-hdr", required_argument, 0, 'y'}, - {"link-src-addr", required_argument, 0, 'S'}, - {"link-dst-addr", required_argument, 0, 'D'}, - {"payload-size", required_argument, 0, 'P'}, - {"src-port", required_argument, 0, 'o'}, - {"dst-port", required_argument, 0, 'a'}, - {"block-src-addr", required_argument, 0, 'j'}, - {"block-dst-addr", required_argument, 0, 'k'}, - {"block-link-src-addr", required_argument, 0, 'J'}, - {"block-link-dst-addr", required_argument, 0, 'K'}, - {"accept-src-addr", required_argument, 0, 'b'}, - {"accept-dst-addr", required_argument, 0, 'g'}, - {"accept-link-src-addr", required_argument, 0, 'B'}, - {"accept-link-dst-addr", required_argument, 0, 'G'}, - {"flood-sources", required_argument, 0, 'F'}, - {"flood-ports", required_argument, 0, 'T'}, - {"loop", no_argument, 0, 'l'}, - {"rate-limit", required_argument, 0, 'r'}, - {"sleep", required_argument, 0, 'z'}, - {"listen", no_argument, 0, 'L'}, - {"probe-mode", required_argument, 0, 'p'}, - {"retrans", required_argument, 0, 'x'}, - {"verbose", no_argument, 0, 'v'}, - {"help", no_argument, 0, 'h'}, - {0, 0, 0, 0 } - }; - - const char shortopts[]= "i:s:d:A:Z:u:U:H:y:S:D:P:o:a:j:k:J:K:b:g:B:G:F:T:lr:z:Lp:x:vh"; - - char option; - - if(argc<=1){ - usage(); - exit(EXIT_FAILURE); - } - - hoplimit=255; - - lastprobe.tv_sec= 0; - lastprobe.tv_usec= 0; - - /* Initialize filters structure */ - if(init_filters(&filters) == -1){ - puts("Error initializing internal data structure"); - exit(EXIT_FAILURE); - } - - if(init_iface_data(&idata) == FAILURE){ - puts("Error initializing internal data structure"); - exit(EXIT_FAILURE); - } - - while((r=getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { - option= r; - - switch(option){ - case 'i': /* Interface */ - strncpy(idata.iface, optarg, IFACE_LENGTH); - idata.iface[IFACE_LENGTH-1]=0; - idata.ifindex= if_nametoindex(idata.iface); - idata.iface_f=TRUE; - break; - - case 's': /* IPv6 Source Address */ - if(idata.srcaddr_f){ - puts("Error: Multiple '-s' options have been specified"); - exit(EXIT_FAILURE); - } - - if((charptr = strtok_r(optarg, "/", &lasts)) == NULL){ - puts("Error in Source Address"); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, charptr, &(idata.srcaddr)) <= 0){ - puts("inet_pton(): Source Address not valid"); - exit(EXIT_FAILURE); - } - - idata.srcaddr_f = 1; - - if((charptr = strtok_r(NULL, " ", &lasts)) != NULL){ - idata.srcpreflen = atoi(charptr); - - if(idata.srcpreflen>128){ - puts("Prefix length error in IPv6 Source Address"); - exit(EXIT_FAILURE); - } - - if(idata.srcpreflen == 64) - useaddrkey_f= 1; - - sanitize_ipv6_prefix(&(idata.srcaddr), idata.srcpreflen); - idata.srcprefix_f=1; - } - - break; - - case 'd': /* IPv6 Destination Address */ - strncpy( targetipv6.name, optarg, NI_MAXHOST); - targetipv6.name[NI_MAXHOST-1]= 0; - targetipv6.flags= AI_CANONNAME; - - if( (r=get_ipv6_target(&targetipv6)) != 0){ - - if(r < 0){ - printf("Unknown Destination: %s\n", gai_strerror(targetipv6.res)); - } - else{ - puts("Unknown Destination: No IPv6 address found for specified destination"); - } - - exit(EXIT_FAILURE); - } - - idata.dstaddr= targetipv6.ip6; - idata.dstaddr_f = 1; - break; - - case 'A': /* Hop Limit */ - hoplimit= atoi(optarg); - hoplimit_f=1; - break; - - case 'Z': /* Data */ - datalen= Strnlen(optarg, MAX_CMDLINE_OPT_LEN); - - if(datalen >= DATA_BUFFER_LEN) - datalen= DATA_BUFFER_LEN-1; - - strncpy(data, optarg, DATA_BUFFER_LEN-1); - data_f=1; - break; - - case 'u': /* Destinations Options Header */ - if(ndstopthdr >= MAX_DST_OPT_HDR){ - puts("Too many Destination Options Headers"); - exit(EXIT_FAILURE); - } - - hdrlen= atoi(optarg); - - if(hdrlen < 8){ - puts("Bad length in Destination Options Header"); - exit(EXIT_FAILURE); - } - - hdrlen = ((hdrlen+7)/8) * 8; - dstopthdrlen[ndstopthdr]= hdrlen; - - if( (dstopthdr[ndstopthdr]= malloc(hdrlen)) == NULL){ - puts("Not enough memory for Destination Options Header"); - exit(EXIT_FAILURE); - } - - ptrhdr= dstopthdr[ndstopthdr] + 2; - ptrhdrend= dstopthdr[ndstopthdr] + hdrlen; - - while( ptrhdr < ptrhdrend){ - - if( (ptrhdrend-ptrhdr)>257) - pad= 257; - else - pad= ptrhdrend-ptrhdr; - - if(!insert_pad_opt(ptrhdr, ptrhdrend, pad)){ - puts("Destination Options Header Too Big"); - exit(EXIT_FAILURE); - } - - ptrhdr= ptrhdr + pad; - } - - *(dstopthdr[ndstopthdr]+1)= (hdrlen/8)-1; - ndstopthdr++; - dstopthdr_f=1; - break; - - case 'U': /* Destination Options Header (Unfragmentable Part) */ - if(ndstoptuhdr >= MAX_DST_OPT_U_HDR){ - puts("Too many Destination Options Headers (Unfragmentable Part)"); - exit(EXIT_FAILURE); - } - - hdrlen= atoi(optarg); - - if(hdrlen < 8){ - puts("Bad length in Destination Options Header (Unfragmentable Part)"); - exit(EXIT_FAILURE); - } - - hdrlen = ((hdrlen+7)/8) * 8; - dstoptuhdrlen[ndstoptuhdr]= hdrlen; - - if( (dstoptuhdr[ndstoptuhdr]= malloc(hdrlen)) == NULL){ - puts("Not enough memory for Destination Options Header (Unfragmentable Part)"); - exit(EXIT_FAILURE); - } - - ptrhdr= dstoptuhdr[ndstoptuhdr]+2; - ptrhdrend= dstoptuhdr[ndstoptuhdr] + hdrlen; - - while( ptrhdr < ptrhdrend){ - - if( (ptrhdrend-ptrhdr)>257) - pad= 257; - else - pad= ptrhdrend-ptrhdr; - - if(!insert_pad_opt(ptrhdr, ptrhdrend, pad)){ - puts("Destination Options Header (Unfragmentable Part) Too Big"); - exit(EXIT_FAILURE); - } - - ptrhdr = ptrhdr + pad; - } - - *(dstoptuhdr[ndstoptuhdr]+1)= (hdrlen/8) - 1; - ndstoptuhdr++; - dstoptuhdr_f=1; - break; - - case 'H': /* Hop-by-Hop Options Header */ - if(nhbhopthdr >= MAX_HBH_OPT_HDR){ - puts("Too many Hop-by-Hop Options Headers"); - exit(EXIT_FAILURE); - } - - hdrlen= atoi(optarg); - - if(hdrlen < 8){ - puts("Bad length in Hop-by-Hop Options Header"); - exit(EXIT_FAILURE); - } - - hdrlen = ((hdrlen+7)/8) * 8; - hbhopthdrlen[nhbhopthdr]= hdrlen; - - if( (hbhopthdr[nhbhopthdr]= malloc(hdrlen)) == NULL){ - puts("Not enough memory for Hop-by-Hop Options Header"); - exit(EXIT_FAILURE); - } - - ptrhdr= hbhopthdr[nhbhopthdr] + 2; - ptrhdrend= hbhopthdr[nhbhopthdr] + hdrlen; - - - while( ptrhdr < ptrhdrend){ - - if( (ptrhdrend-ptrhdr)>257) - pad= 257; - else - pad= ptrhdrend-ptrhdr; - - if(!insert_pad_opt(ptrhdr, ptrhdrend, pad)){ - puts("Hop-by-Hop Options Header Too Big"); - exit(EXIT_FAILURE); - } - - ptrhdr = ptrhdr + pad; - } - - *(hbhopthdr[nhbhopthdr]+1)= (hdrlen/8) - 1; - nhbhopthdr++; - hbhopthdr_f=1; - break; - - case 'y': /* Fragment header */ - nfrags= atoi(optarg); - if(nfrags < 8){ - puts("Error in Fragmentation option: Fragment Size must be at least 8 bytes"); - exit(EXIT_FAILURE); - } - - idata.fragh_f= 1; - break; - - case 'S': /* Source Ethernet address */ - if(ether_pton(optarg, &(idata.hsrcaddr), sizeof(idata.hsrcaddr)) == 0){ - puts("Error in Source link-layer address."); - exit(EXIT_FAILURE); - } - - idata.hsrcaddr_f = 1; - break; - - case 'D': /* Destination Ethernet Address */ - if(ether_pton(optarg, &(idata.hdstaddr), sizeof(idata.hdstaddr)) == 0){ - puts("Error in Source link-layer address."); - exit(EXIT_FAILURE); - } - - idata.hdstaddr_f = 1; - break; - - case 'P': /* Payload Size*/ - rhbytes= atoi(optarg); - rhbytes_f= 1; - break; - - case 'o': /* UDP Source Port */ - if((charptr = strtok_r(optarg, "/", &lasts)) == NULL){ - puts("Error in UDP Source Port"); - exit(EXIT_FAILURE); - } - - srcport= atoi(charptr); - srcport_f= 1; - - if((charptr = strtok_r(NULL, "/", &lasts)) != NULL){ - srcportpref= atoi(charptr); - srcportrnd_f=1; - sanitize_port(&srcport, srcportpref); - } - - if(srcportpref >= 16) - srcportrnd_f= 0; - - break; - - case 'a': /* UDP Destination Port */ - if((charptr = strtok_r(optarg, "/", &lasts)) == NULL){ - puts("Error UDP Destination Port"); - exit(EXIT_FAILURE); - } - - dstport= atoi(optarg); - dstport_f= 1; - - if((charptr = strtok_r(NULL, "/", &lasts)) != NULL){ - dstportpref= atoi(charptr); - dstportrnd_f=1; - sanitize_port(&dstport, dstportpref); - } - - if(dstportpref >= 16) - dstportrnd_f= 0; - - break; - - case 'j': /* IPv6 Source Address (block) filter */ - if(filters.nblocksrc >= MAX_BLOCK_SRC){ - puts("Too many IPv6 Source Address (block) filters."); - exit(EXIT_FAILURE); - } - - if((pref = strtok_r(optarg, "/", &lasts)) == NULL){ - printf("Error in IPv6 Source Address (block) filter number %u.\n", \ - filters.nblocksrc+1); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, pref, &(filters.blocksrc[filters.nblocksrc])) <= 0){ - printf("Error in IPv6 Source Address (block) filter number %u.", \ - filters.nblocksrc+1); - exit(EXIT_FAILURE); - } - - if((charptr = strtok_r(NULL, " ", &lasts)) == NULL){ - filters.blocksrclen[filters.nblocksrc] = 128; - } - else{ - filters.blocksrclen[filters.nblocksrc] = atoi(charptr); - - if(filters.blocksrclen[filters.nblocksrc]>128){ - printf("Length error in IPv6 Source Address (block) filter number %u.\n", \ - filters.nblocksrc+1); - exit(EXIT_FAILURE); - } - } - - sanitize_ipv6_prefix(&(filters.blocksrc[filters.nblocksrc]), filters.blocksrclen[filters.nblocksrc]); - (filters.nblocksrc)++; - break; - - case 'k': /* IPv6 Destination Address (block) filter */ - if(filters.nblockdst >= MAX_BLOCK_DST){ - puts("Too many IPv6 Destination Address (block) filters."); - exit(EXIT_FAILURE); - } - - if((pref = strtok_r(optarg, "/", &lasts)) == NULL){ - printf("Error in IPv6 Destination Address (block) filter number %u.\n", \ - filters.nblockdst+1); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, pref, &(filters.blockdst[filters.nblockdst])) <= 0){ - printf("Error in IPv6 Source Address (block) filter number %u.", \ - filters.nblockdst+1); - exit(EXIT_FAILURE); - } - - if((charptr = strtok_r(NULL, " ", &lasts)) == NULL){ - filters.blockdstlen[filters.nblockdst] = 128; - } - else{ - filters.blockdstlen[filters.nblockdst] = atoi(charptr); - - if(filters.blockdstlen[filters.nblockdst]>128){ - printf("Length error in IPv6 Source Address (block) filter number %u.\n", \ - filters.nblockdst+1); - exit(EXIT_FAILURE); - } - } - - sanitize_ipv6_prefix(&(filters.blockdst[filters.nblockdst]), filters.blockdstlen[filters.nblockdst]); - (filters.nblockdst)++; - break; - - case 'J': /* Link Source Address (block) filter */ - if(filters.nblocklinksrc > MAX_BLOCK_LINK_SRC){ - puts("Too many link-layer Source Address (accept) filters."); - exit(EXIT_FAILURE); - } - - if(ether_pton(optarg, &(filters.blocklinksrc[filters.nblocklinksrc]), sizeof(struct ether_addr)) == 0){ - printf("Error in link-layer Source Address (blick) filter number %u.\n", \ - filters.nblocklinksrc+1); - exit(EXIT_FAILURE); - } - - (filters.nblocklinksrc)++; - break; - - case 'K': /* Link Destination Address (block) filter */ - if(filters.nblocklinkdst > MAX_BLOCK_LINK_DST){ - puts("Too many link-layer Destination Address (block) filters."); - exit(EXIT_FAILURE); - } - - if(ether_pton(optarg, &(filters.blocklinkdst[filters.nblocklinkdst]), sizeof(struct ether_addr)) == 0){ - printf("Error in link-layer Destination Address (blick) filter number %u.\n", \ - filters.nblocklinkdst+1); - exit(EXIT_FAILURE); - } - - filters.nblocklinkdst++; - break; - - case 'b': /* IPv6 Source Address (accept) filter */ - if(filters.nacceptsrc > MAX_ACCEPT_SRC){ - puts("Too many IPv6 Source Address (accept) filters."); - exit(EXIT_FAILURE); - } - - if((pref = strtok_r(optarg, "/", &lasts)) == NULL){ - printf("Error in IPv6 Source Address (accept) filter number %u.\n", \ - filters.nacceptsrc+1); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, pref, &(filters.acceptsrc[filters.nacceptsrc])) <= 0){ - printf("Error in IPv6 Source Address (accept) filter number %u.\n", \ - filters.nacceptsrc+1); - exit(EXIT_FAILURE); - } - - if((charptr = strtok_r(NULL, " ", &lasts)) == NULL){ - filters.acceptsrclen[filters.nacceptsrc] = 128; - } - else{ - filters.acceptsrclen[filters.nacceptsrc] = atoi(charptr); - - if(filters.acceptsrclen[filters.nacceptsrc]>128){ - printf("Length error in IPv6 Source Address (accept) filter number %u.\n", \ - filters.nacceptsrc+1); - exit(EXIT_FAILURE); - } - } - - sanitize_ipv6_prefix(&(filters.acceptsrc[filters.nacceptsrc]), filters.acceptsrclen[filters.nacceptsrc]); - (filters.nacceptsrc)++; - filters.acceptfilters_f=1; - break; - - - case 'g': /* IPv6 Destination Address (accept) filter */ - if(filters.nacceptdst > MAX_ACCEPT_DST){ - puts("Too many IPv6 Destination Address (accept) filters."); - exit(EXIT_FAILURE); - } - - if((pref = strtok_r(optarg, "/", &lasts)) == NULL){ - printf("Error in IPv6 Destination Address (accept) filter number %u.\n", \ - filters.nacceptdst+1); - exit(EXIT_FAILURE); - } - - if ( inet_pton(AF_INET6, pref, &(filters.acceptdst[filters.nacceptdst])) <= 0){ - printf("Error in IPv6 Source Address (accept) filter number %u.\n", \ - filters.nacceptdst+1); - exit(EXIT_FAILURE); - } - - if((charptr = strtok_r(NULL, " ", &lasts)) == NULL){ - filters.acceptdstlen[filters.nacceptdst] = 128; - } - else{ - filters.acceptdstlen[filters.nacceptdst] = atoi(charptr); - - if(filters.acceptdstlen[filters.nacceptdst] > 128){ - printf("Length error in IPv6 Source Address (accept) filter number %u.\n", \ - filters.nacceptdst+1); - exit(EXIT_FAILURE); - } - } - - sanitize_ipv6_prefix(&(filters.acceptdst[filters.nacceptdst]), filters.acceptdstlen[filters.nacceptdst]); - (filters.nacceptdst)++; - filters.acceptfilters_f=1; - break; - - case 'B': /* Link-layer Source Address (accept) filter */ - if(filters.nacceptlinksrc > MAX_ACCEPT_LINK_SRC){ - puts("Too many link-later Source Address (accept) filters."); - exit(EXIT_FAILURE); - } - - if(ether_pton(optarg, &(filters.acceptlinksrc[filters.nacceptlinksrc]), sizeof(struct ether_addr)) == 0){ - printf("Error in link-layer Source Address (accept) filter number %u.\n", \ - filters.nacceptlinksrc+1); - exit(EXIT_FAILURE); - } - - (filters.nacceptlinksrc)++; - filters.acceptfilters_f=1; - break; - - case 'G': /* Link Destination Address (accept) filter */ - if(filters.nacceptlinkdst > MAX_ACCEPT_LINK_DST){ - puts("Too many link-layer Destination Address (accept) filters."); - exit(EXIT_FAILURE); - } - - if(ether_pton(optarg, &(filters.acceptlinkdst[filters.nacceptlinkdst]), sizeof(struct ether_addr)) == 0){ - printf("Error in link-layer Destination Address (accept) filter number %u.\n",\ - filters.nacceptlinkdst+1); - exit(EXIT_FAILURE); - } - - (filters.nacceptlinkdst)++; - filters.acceptfilters_f=1; - break; - - case 'F': /* Flood source addresses */ - nsources= atoi(optarg); - if(nsources == 0){ - puts("Invalid number of source addresses in option -F"); - exit(EXIT_FAILURE); - } - - floods_f= 1; - break; - - case 'T': /* Flood source ports */ - nports= atoi(optarg); - - if(nports == 0){ - puts("Invalid number of source ports in option -T"); - exit(EXIT_FAILURE); - } - - floodp_f= 1; - break; - - case 'f': - rand_src_f=1; - break; - - case 'R': - rand_link_src_f=1; - break; - - case 'l': /* "Loop mode */ - loop_f = 1; - break; - - case 'r': - if( Strnlen(optarg, LINE_BUFFER_SIZE-1) >= (LINE_BUFFER_SIZE-1)){ - puts("udp6: -r option is too long"); - exit(EXIT_FAILURE); - } - - sscanf(optarg, "%lu%s", &rate, line); - line[LINE_BUFFER_SIZE-1]=0; - - if(strncmp(line, "pps", 3) == 0) - pps_f=1; - else if(strncmp(line, "bps", 3) == 0) - bps_f=1; - else{ - puts("udp6: Unknown unit of for the rate limit ('-r' option). Unit should be 'bps' or 'pps'"); - exit(EXIT_FAILURE); - } - - break; - - - case 'z': /* Sleep option */ - nsleep=atoi(optarg); - if(nsleep==0){ - puts("Invalid number of seconds in '-z' option"); - exit(EXIT_FAILURE); - } - - sleep_f=1; - break; - - case 'L': /* "Listen mode */ - listen_f = 1; - break; - - case 'p': /* Probe mode */ - if(strncmp(optarg, "dump", MAX_CMDLINE_OPT_LEN) == 0){ - probemode= PROBE_DUMP; - } - else if(strncmp(optarg, "script", MAX_CMDLINE_OPT_LEN) == 0){ - probemode= PROBE_SCRIPT; - } - else{ - puts("Error: Unknown open mode in '-Y' option"); - exit(EXIT_FAILURE); - } - - probemode_f=1; - break; - - case 'x': /* Number of retrnasmissions */ - retrans= atoi(optarg); - retrans_f=1; - break; - - case 'v': /* Be verbose */ - (idata.verbose_f)++; - break; - - case 'h': /* Help */ - print_help(); - exit(EXIT_FAILURE); - break; - - default: - usage(); - exit(EXIT_FAILURE); - break; - - } /* switch */ - } /* while(getopt) */ - - if(geteuid()) { - puts("udp6 needs root privileges to run."); - exit(EXIT_FAILURE); - } - - srandom(time(NULL)); - - /* - If the flood option ("-F") has been specified, but no prefix has been specified, - assume a /64 prefix. - */ - if(floods_f && !idata.srcprefix_f){ - idata.srcpreflen=64; - } - - if(!(idata.dstaddr_f) && !listen_f){ /* Must specify IPv6 Destination Address if listening mode not used */ - puts("IPv6 Destination Address not specified (and listening mode not selected)"); - exit(EXIT_FAILURE); - } - - if(rhbytes_f && data_f){ - puts("Cannot set '--data' and '--payload-size' at the same time"); - exit(EXIT_FAILURE); - } - - if(!idata.iface_f){ - if(idata.dstaddr_f && IN6_IS_ADDR_LINKLOCAL(&(idata.dstaddr))){ - puts("Must specify a network interface for link-local destinations"); - exit(EXIT_FAILURE); - } - else if(listen_f){ - puts("Must specify a network interface when employing the 'listenging' mode"); - exit(EXIT_FAILURE); - } - } - - if(load_dst_and_pcap(&idata, (idata.dstaddr_f?LOAD_SRC_NXT_HOP:LOAD_PCAP_ONLY)) == FAILURE){ - puts("Error while learning Source Address and Next Hop"); - exit(EXIT_FAILURE); - } - - release_privileges(); - - if(data_f){ - data[datalen]=0; - - if(!string_escapes(data, &datalen, DATA_BUFFER_LEN-1)){ - puts("Error in data string option ('-Z')"); - exit(EXIT_FAILURE); - } - - data[datalen]=0; - } - - if(!floods_f) - nsources=1; - - if(!floodp_f) - nports=1; - - if(!sleep_f) - nsleep=1; - - if(sleep_f && (pps_f || bps_f)){ - puts("Cannot specify a rate-limit (-r) and a sleep time at the same time"); - exit(EXIT_FAILURE); - } - - if(pps_f && bps_f){ - puts("Cannot specify a rate-limit in bps and pps at the same time"); - exit(EXIT_FAILURE); - } - - if(pps_f){ - if(rate < 1) - rate=1; - - pktinterval= 1000000/rate; - } - - if(bps_f){ - packetsize= MIN_IPV6_HLEN + sizeof(struct udp_hdr) + rhbytes; - - for(i=0; i < ndstopthdr; i++) - packetsize+= dstopthdrlen[i]; - - for(i=0; i < ndstoptuhdr; i++) - packetsize+= dstoptuhdrlen[i]; - - for(i=0; i < nhbhopthdr; i++) - packetsize+= hbhopthdrlen[i]; - - if(idata.fragh_f) - packetsize+= sizeof(struct ip6_frag); - - if(rate == 0 || ((packetsize * 8)/rate) <= 0) - pktinterval= 1000000; - else - pktinterval= ((packetsize * 8)/rate) * 1000000; - } - - /* We Default to 1000 pps */ - if(!pps_f && !bps_f){ - rate= 1000; - pktinterval= 1000000/rate; - } - - if( !idata.fragh_f && dstoptuhdr_f){ - puts("Dst. Options Header (Unfragmentable Part) set, but Fragmentation not specified"); - exit(EXIT_FAILURE); - } - - /* - * If we are going to send packets to a specified target, we must set some default values - */ - if(idata.dstaddr_f){ - if(srcport_f){ - if(srcportrnd_f){ - randomize_port(&srcport, srcport, srcportpref); - } - } - else{ - srcport= random(); - } - - if(dstport_f){ - if(dstportrnd_f){ - randomize_port(&dstport, dstport, dstportpref); - } - } - else{ - dstport= random(); - } - } - - if(!rhbytes_f) - rhbytes=0; - - if(idata.verbose_f){ - print_attack_info(&idata); - } - - /* - Set filter for IPv6 packets (find_ipv6_router() set its own filter fore receiving RAs) - */ - if(pcap_compile(idata.pfd, &pcap_filter, PCAP_UDPIPV6_NS_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1){ - printf("pcap_compile(): %s", pcap_geterr(idata.pfd)); - exit(EXIT_FAILURE); - } - - if(pcap_setfilter(idata.pfd, &pcap_filter) == -1){ - printf("pcap_setfilter(): %s", pcap_geterr(idata.pfd)); - exit(EXIT_FAILURE); - } - - pcap_freecode(&pcap_filter); - - /* Set initial contents of the attack packet */ - init_packet_data(&idata); - addr_key= random(); - - if(sleep_f) - pktinterval= (nsleep * 1000000)/(nsources * nports); - - timeout.tv_sec= pktinterval / 1000000 ; - timeout.tv_usec= pktinterval % 1000000; - stimeout= timeout; - - if(probemode_f){ - end_f=0; - - if(!dstport_f) - dstport= 80; - - if(srcport_f){ - if(srcportrnd_f){ - randomize_port(&srcport, srcport, srcportpref); - } - } - else{ - srcport= 50000 + random() % 15000; /* We select ports from the "high ports" range */ - } - - if(!rto_f) - rto=1; - - if(!retrans_f) - retrans=0; - - retr=0; - retrans++; - - FD_ZERO(&sset); - FD_SET(idata.fd, &sset); - - lastprobe.tv_sec= 0; - lastprobe.tv_usec=0; - - while(!end_f){ - if(gettimeofday(&curtime, NULL) == -1){ - if(idata.verbose_f) - perror("udp6"); - - exit(EXIT_FAILURE); - } - - if(is_time_elapsed(&curtime, &lastprobe, rto * 1000000) && retr < retrans){ - retr++; - lastprobe= curtime; - send_packet(&idata, NULL, NULL); - } - - if(is_time_elapsed(&curtime, &lastprobe, rto * 1000000) && retr >= retrans){ - end_f=1; - break; - } - - rset= sset; - timeout.tv_usec=0; - timeout.tv_sec= (rto < 1)?rto:1; - - if((sel=select(idata.fd+1, &rset, NULL, NULL, &timeout)) == -1){ - if(errno == EINTR){ - continue; - } - else{ - puts("Error in select()"); - exit(EXIT_FAILURE); - } - } + if ((dstopthdr[ndstopthdr] = malloc(hdrlen)) == NULL) { + puts("Not enough memory for Destination Options Header"); + exit(EXIT_FAILURE); + } + + ptrhdr = dstopthdr[ndstopthdr] + 2; + ptrhdrend = dstopthdr[ndstopthdr] + hdrlen; + + while (ptrhdr < ptrhdrend) { + + if ((ptrhdrend - ptrhdr) > 257) + pad = 257; + else + pad = ptrhdrend - ptrhdr; + + if (!insert_pad_opt(ptrhdr, ptrhdrend, pad)) { + puts("Destination Options Header Too Big"); + exit(EXIT_FAILURE); + } + + ptrhdr = ptrhdr + pad; + } + + *(dstopthdr[ndstopthdr] + 1) = (hdrlen / 8) - 1; + ndstopthdr++; + dstopthdr_f = 1; + break; + + case 'U': /* Destination Options Header (Unfragmentable Part) */ + if (ndstoptuhdr >= MAX_DST_OPT_U_HDR) { + puts("Too many Destination Options Headers (Unfragmentable Part)"); + exit(EXIT_FAILURE); + } + + hdrlen = atoi(optarg); + + if (hdrlen < 8) { + puts("Bad length in Destination Options Header (Unfragmentable Part)"); + exit(EXIT_FAILURE); + } + + hdrlen = ((hdrlen + 7) / 8) * 8; + dstoptuhdrlen[ndstoptuhdr] = hdrlen; + + if ((dstoptuhdr[ndstoptuhdr] = malloc(hdrlen)) == NULL) { + puts("Not enough memory for Destination Options Header (Unfragmentable Part)"); + exit(EXIT_FAILURE); + } + + ptrhdr = dstoptuhdr[ndstoptuhdr] + 2; + ptrhdrend = dstoptuhdr[ndstoptuhdr] + hdrlen; + + while (ptrhdr < ptrhdrend) { + + if ((ptrhdrend - ptrhdr) > 257) + pad = 257; + else + pad = ptrhdrend - ptrhdr; + + if (!insert_pad_opt(ptrhdr, ptrhdrend, pad)) { + puts("Destination Options Header (Unfragmentable Part) Too Big"); + exit(EXIT_FAILURE); + } + + ptrhdr = ptrhdr + pad; + } + + *(dstoptuhdr[ndstoptuhdr] + 1) = (hdrlen / 8) - 1; + ndstoptuhdr++; + dstoptuhdr_f = 1; + break; + + case 'H': /* Hop-by-Hop Options Header */ + if (nhbhopthdr >= MAX_HBH_OPT_HDR) { + puts("Too many Hop-by-Hop Options Headers"); + exit(EXIT_FAILURE); + } + + hdrlen = atoi(optarg); + + if (hdrlen < 8) { + puts("Bad length in Hop-by-Hop Options Header"); + exit(EXIT_FAILURE); + } + + hdrlen = ((hdrlen + 7) / 8) * 8; + hbhopthdrlen[nhbhopthdr] = hdrlen; + + if ((hbhopthdr[nhbhopthdr] = malloc(hdrlen)) == NULL) { + puts("Not enough memory for Hop-by-Hop Options Header"); + exit(EXIT_FAILURE); + } + + ptrhdr = hbhopthdr[nhbhopthdr] + 2; + ptrhdrend = hbhopthdr[nhbhopthdr] + hdrlen; + + while (ptrhdr < ptrhdrend) { + + if ((ptrhdrend - ptrhdr) > 257) + pad = 257; + else + pad = ptrhdrend - ptrhdr; + + if (!insert_pad_opt(ptrhdr, ptrhdrend, pad)) { + puts("Hop-by-Hop Options Header Too Big"); + exit(EXIT_FAILURE); + } + + ptrhdr = ptrhdr + pad; + } + + *(hbhopthdr[nhbhopthdr] + 1) = (hdrlen / 8) - 1; + nhbhopthdr++; + hbhopthdr_f = 1; + break; + + case 'y': /* Fragment header */ + nfrags = atoi(optarg); + if (nfrags < 8) { + puts("Error in Fragmentation option: Fragment Size must be at least 8 bytes"); + exit(EXIT_FAILURE); + } + + idata.fragh_f = 1; + break; + + case 'S': /* Source Ethernet address */ + if (ether_pton(optarg, &(idata.hsrcaddr), sizeof(idata.hsrcaddr)) == 0) { + puts("Error in Source link-layer address."); + exit(EXIT_FAILURE); + } + + idata.hsrcaddr_f = 1; + break; + + case 'D': /* Destination Ethernet Address */ + if (ether_pton(optarg, &(idata.hdstaddr), sizeof(idata.hdstaddr)) == 0) { + puts("Error in Source link-layer address."); + exit(EXIT_FAILURE); + } + + idata.hdstaddr_f = 1; + break; + + case 'P': /* Payload Size*/ + rhbytes = atoi(optarg); + rhbytes_f = 1; + break; + + case 'o': /* UDP Source Port */ + if ((charptr = strtok_r(optarg, "/", &lasts)) == NULL) { + puts("Error in UDP Source Port"); + exit(EXIT_FAILURE); + } + + srcport = atoi(charptr); + srcport_f = 1; + + if ((charptr = strtok_r(NULL, "/", &lasts)) != NULL) { + srcportpref = atoi(charptr); + srcportrnd_f = 1; + sanitize_port(&srcport, srcportpref); + } + + if (srcportpref >= 16) + srcportrnd_f = 0; + + break; + + case 'a': /* UDP Destination Port */ + if ((charptr = strtok_r(optarg, "/", &lasts)) == NULL) { + puts("Error UDP Destination Port"); + exit(EXIT_FAILURE); + } + + dstport = atoi(optarg); + dstport_f = 1; + + if ((charptr = strtok_r(NULL, "/", &lasts)) != NULL) { + dstportpref = atoi(charptr); + dstportrnd_f = 1; + sanitize_port(&dstport, dstportpref); + } + + if (dstportpref >= 16) + dstportrnd_f = 0; + + break; + + case 'j': /* IPv6 Source Address (block) filter */ + if (filters.nblocksrc >= MAX_BLOCK_SRC) { + puts("Too many IPv6 Source Address (block) filters."); + exit(EXIT_FAILURE); + } + + if ((pref = strtok_r(optarg, "/", &lasts)) == NULL) { + printf("Error in IPv6 Source Address (block) filter number %u.\n", filters.nblocksrc + 1); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, pref, &(filters.blocksrc[filters.nblocksrc])) <= 0) { + printf("Error in IPv6 Source Address (block) filter number %u.", filters.nblocksrc + 1); + exit(EXIT_FAILURE); + } + + if ((charptr = strtok_r(NULL, " ", &lasts)) == NULL) { + filters.blocksrclen[filters.nblocksrc] = 128; + } + else { + filters.blocksrclen[filters.nblocksrc] = atoi(charptr); + + if (filters.blocksrclen[filters.nblocksrc] > 128) { + printf("Length error in IPv6 Source Address (block) filter number %u.\n", filters.nblocksrc + 1); + exit(EXIT_FAILURE); + } + } + + sanitize_ipv6_prefix(&(filters.blocksrc[filters.nblocksrc]), filters.blocksrclen[filters.nblocksrc]); + (filters.nblocksrc)++; + break; + + case 'k': /* IPv6 Destination Address (block) filter */ + if (filters.nblockdst >= MAX_BLOCK_DST) { + puts("Too many IPv6 Destination Address (block) filters."); + exit(EXIT_FAILURE); + } + + if ((pref = strtok_r(optarg, "/", &lasts)) == NULL) { + printf("Error in IPv6 Destination Address (block) filter number %u.\n", filters.nblockdst + 1); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, pref, &(filters.blockdst[filters.nblockdst])) <= 0) { + printf("Error in IPv6 Source Address (block) filter number %u.", filters.nblockdst + 1); + exit(EXIT_FAILURE); + } + + if ((charptr = strtok_r(NULL, " ", &lasts)) == NULL) { + filters.blockdstlen[filters.nblockdst] = 128; + } + else { + filters.blockdstlen[filters.nblockdst] = atoi(charptr); + + if (filters.blockdstlen[filters.nblockdst] > 128) { + printf("Length error in IPv6 Source Address (block) filter number %u.\n", filters.nblockdst + 1); + exit(EXIT_FAILURE); + } + } + + sanitize_ipv6_prefix(&(filters.blockdst[filters.nblockdst]), filters.blockdstlen[filters.nblockdst]); + (filters.nblockdst)++; + break; + + case 'J': /* Link Source Address (block) filter */ + if (filters.nblocklinksrc > MAX_BLOCK_LINK_SRC) { + puts("Too many link-layer Source Address (accept) filters."); + exit(EXIT_FAILURE); + } + + if (ether_pton(optarg, &(filters.blocklinksrc[filters.nblocklinksrc]), sizeof(struct ether_addr)) == 0) { + printf("Error in link-layer Source Address (blick) filter number %u.\n", filters.nblocklinksrc + 1); + exit(EXIT_FAILURE); + } + + (filters.nblocklinksrc)++; + break; + + case 'K': /* Link Destination Address (block) filter */ + if (filters.nblocklinkdst > MAX_BLOCK_LINK_DST) { + puts("Too many link-layer Destination Address (block) filters."); + exit(EXIT_FAILURE); + } + + if (ether_pton(optarg, &(filters.blocklinkdst[filters.nblocklinkdst]), sizeof(struct ether_addr)) == 0) { + printf("Error in link-layer Destination Address (blick) filter number %u.\n", + filters.nblocklinkdst + 1); + exit(EXIT_FAILURE); + } + + filters.nblocklinkdst++; + break; + + case 'b': /* IPv6 Source Address (accept) filter */ + if (filters.nacceptsrc > MAX_ACCEPT_SRC) { + puts("Too many IPv6 Source Address (accept) filters."); + exit(EXIT_FAILURE); + } + + if ((pref = strtok_r(optarg, "/", &lasts)) == NULL) { + printf("Error in IPv6 Source Address (accept) filter number %u.\n", filters.nacceptsrc + 1); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, pref, &(filters.acceptsrc[filters.nacceptsrc])) <= 0) { + printf("Error in IPv6 Source Address (accept) filter number %u.\n", filters.nacceptsrc + 1); + exit(EXIT_FAILURE); + } + + if ((charptr = strtok_r(NULL, " ", &lasts)) == NULL) { + filters.acceptsrclen[filters.nacceptsrc] = 128; + } + else { + filters.acceptsrclen[filters.nacceptsrc] = atoi(charptr); + + if (filters.acceptsrclen[filters.nacceptsrc] > 128) { + printf("Length error in IPv6 Source Address (accept) filter number %u.\n", filters.nacceptsrc + 1); + exit(EXIT_FAILURE); + } + } + + sanitize_ipv6_prefix(&(filters.acceptsrc[filters.nacceptsrc]), filters.acceptsrclen[filters.nacceptsrc]); + (filters.nacceptsrc)++; + filters.acceptfilters_f = 1; + break; + + case 'g': /* IPv6 Destination Address (accept) filter */ + if (filters.nacceptdst > MAX_ACCEPT_DST) { + puts("Too many IPv6 Destination Address (accept) filters."); + exit(EXIT_FAILURE); + } + + if ((pref = strtok_r(optarg, "/", &lasts)) == NULL) { + printf("Error in IPv6 Destination Address (accept) filter number %u.\n", filters.nacceptdst + 1); + exit(EXIT_FAILURE); + } + + if (inet_pton(AF_INET6, pref, &(filters.acceptdst[filters.nacceptdst])) <= 0) { + printf("Error in IPv6 Source Address (accept) filter number %u.\n", filters.nacceptdst + 1); + exit(EXIT_FAILURE); + } + + if ((charptr = strtok_r(NULL, " ", &lasts)) == NULL) { + filters.acceptdstlen[filters.nacceptdst] = 128; + } + else { + filters.acceptdstlen[filters.nacceptdst] = atoi(charptr); + + if (filters.acceptdstlen[filters.nacceptdst] > 128) { + printf("Length error in IPv6 Source Address (accept) filter number %u.\n", filters.nacceptdst + 1); + exit(EXIT_FAILURE); + } + } + + sanitize_ipv6_prefix(&(filters.acceptdst[filters.nacceptdst]), filters.acceptdstlen[filters.nacceptdst]); + (filters.nacceptdst)++; + filters.acceptfilters_f = 1; + break; + + case 'B': /* Link-layer Source Address (accept) filter */ + if (filters.nacceptlinksrc > MAX_ACCEPT_LINK_SRC) { + puts("Too many link-later Source Address (accept) filters."); + exit(EXIT_FAILURE); + } + + if (ether_pton(optarg, &(filters.acceptlinksrc[filters.nacceptlinksrc]), sizeof(struct ether_addr)) == 0) { + printf("Error in link-layer Source Address (accept) filter number %u.\n", filters.nacceptlinksrc + 1); + exit(EXIT_FAILURE); + } + + (filters.nacceptlinksrc)++; + filters.acceptfilters_f = 1; + break; + + case 'G': /* Link Destination Address (accept) filter */ + if (filters.nacceptlinkdst > MAX_ACCEPT_LINK_DST) { + puts("Too many link-layer Destination Address (accept) filters."); + exit(EXIT_FAILURE); + } + + if (ether_pton(optarg, &(filters.acceptlinkdst[filters.nacceptlinkdst]), sizeof(struct ether_addr)) == 0) { + printf("Error in link-layer Destination Address (accept) filter number %u.\n", + filters.nacceptlinkdst + 1); + exit(EXIT_FAILURE); + } + + (filters.nacceptlinkdst)++; + filters.acceptfilters_f = 1; + break; + + case 'F': /* Flood source addresses */ + nsources = atoi(optarg); + if (nsources == 0) { + puts("Invalid number of source addresses in option -F"); + exit(EXIT_FAILURE); + } + + floods_f = 1; + break; + + case 'T': /* Flood source ports */ + nports = atoi(optarg); + + if (nports == 0) { + puts("Invalid number of source ports in option -T"); + exit(EXIT_FAILURE); + } + + floodp_f = 1; + break; + + case 'f': + rand_src_f = 1; + break; + + case 'R': + rand_link_src_f = 1; + break; + + case 'l': /* "Loop mode */ + loop_f = 1; + break; + + case 'r': + if (Strnlen(optarg, LINE_BUFFER_SIZE - 1) >= (LINE_BUFFER_SIZE - 1)) { + puts("udp6: -r option is too long"); + exit(EXIT_FAILURE); + } + + sscanf(optarg, "%lu%s", &rate, line); + line[LINE_BUFFER_SIZE - 1] = 0; + + if (strncmp(line, "pps", 3) == 0) + pps_f = 1; + else if (strncmp(line, "bps", 3) == 0) + bps_f = 1; + else { + puts("udp6: Unknown unit of for the rate limit ('-r' option). Unit should be 'bps' or 'pps'"); + exit(EXIT_FAILURE); + } + + break; + + case 'z': /* Sleep option */ + nsleep = atoi(optarg); + if (nsleep == 0) { + puts("Invalid number of seconds in '-z' option"); + exit(EXIT_FAILURE); + } + + sleep_f = 1; + break; + + case 'L': /* "Listen mode */ + listen_f = 1; + break; + + case 'p': /* Probe mode */ + if (strncmp(optarg, "dump", MAX_CMDLINE_OPT_LEN) == 0) { + probemode = PROBE_DUMP; + } + else if (strncmp(optarg, "script", MAX_CMDLINE_OPT_LEN) == 0) { + probemode = PROBE_SCRIPT; + } + else { + puts("Error: Unknown open mode in '-Y' option"); + exit(EXIT_FAILURE); + } + + probemode_f = 1; + break; + + case 'x': /* Number of retrnasmissions */ + retrans = atoi(optarg); + retrans_f = 1; + break; + + case 'v': /* Be verbose */ + (idata.verbose_f)++; + break; + + case 'h': /* Help */ + print_help(); + exit(EXIT_FAILURE); + break; + + default: + usage(); + exit(EXIT_FAILURE); + break; + + } /* switch */ + } /* while(getopt) */ + + if (geteuid()) { + puts("udp6 needs root privileges to run."); + exit(EXIT_FAILURE); + } + + srandom(time(NULL)); + + /* + If the flood option ("-F") has been specified, but no prefix has been specified, + assume a /64 prefix. + */ + if (floods_f && !idata.srcprefix_f) { + idata.srcpreflen = 64; + } + + if (!(idata.dstaddr_f) && !listen_f) { /* Must specify IPv6 Destination Address if listening mode not used */ + puts("IPv6 Destination Address not specified (and listening mode not selected)"); + exit(EXIT_FAILURE); + } + + if (rhbytes_f && data_f) { + puts("Cannot set '--data' and '--payload-size' at the same time"); + exit(EXIT_FAILURE); + } + + if (!idata.iface_f) { + if (idata.dstaddr_f && IN6_IS_ADDR_LINKLOCAL(&(idata.dstaddr))) { + puts("Must specify a network interface for link-local destinations"); + exit(EXIT_FAILURE); + } + else if (listen_f) { + puts("Must specify a network interface when employing the 'listenging' mode"); + exit(EXIT_FAILURE); + } + } + + if (load_dst_and_pcap(&idata, (idata.dstaddr_f ? LOAD_SRC_NXT_HOP : LOAD_PCAP_ONLY)) == FAILURE) { + puts("Error while learning Source Address and Next Hop"); + exit(EXIT_FAILURE); + } + + release_privileges(); + + if (data_f) { + data[datalen] = 0; + + if (!string_escapes(data, &datalen, DATA_BUFFER_LEN - 1)) { + puts("Error in data string option ('-Z')"); + exit(EXIT_FAILURE); + } + + data[datalen] = 0; + } + + if (!floods_f) + nsources = 1; + + if (!floodp_f) + nports = 1; + + if (!sleep_f) + nsleep = 1; + + if (sleep_f && (pps_f || bps_f)) { + puts("Cannot specify a rate-limit (-r) and a sleep time at the same time"); + exit(EXIT_FAILURE); + } + + if (pps_f && bps_f) { + puts("Cannot specify a rate-limit in bps and pps at the same time"); + exit(EXIT_FAILURE); + } + + if (pps_f) { + if (rate < 1) + rate = 1; + + pktinterval = 1000000 / rate; + } + + if (bps_f) { + packetsize = MIN_IPV6_HLEN + sizeof(struct udp_hdr) + rhbytes; + + for (i = 0; i < ndstopthdr; i++) + packetsize += dstopthdrlen[i]; + + for (i = 0; i < ndstoptuhdr; i++) + packetsize += dstoptuhdrlen[i]; + + for (i = 0; i < nhbhopthdr; i++) + packetsize += hbhopthdrlen[i]; + + if (idata.fragh_f) + packetsize += sizeof(struct ip6_frag); + + if (rate == 0 || ((packetsize * 8) / rate) <= 0) + pktinterval = 1000000; + else + pktinterval = ((packetsize * 8) / rate) * 1000000; + } + + /* We Default to 1000 pps */ + if (!pps_f && !bps_f) { + rate = 1000; + pktinterval = 1000000 / rate; + } + + if (!idata.fragh_f && dstoptuhdr_f) { + puts("Dst. Options Header (Unfragmentable Part) set, but Fragmentation not specified"); + exit(EXIT_FAILURE); + } + + /* + * If we are going to send packets to a specified target, we must set some default values + */ + if (idata.dstaddr_f) { + if (srcport_f) { + if (srcportrnd_f) { + randomize_port(&srcport, srcport, srcportpref); + } + } + else { + srcport = random(); + } + + if (dstport_f) { + if (dstportrnd_f) { + randomize_port(&dstport, dstport, dstportpref); + } + } + else { + dstport = random(); + } + } + + if (!rhbytes_f) + rhbytes = 0; + + if (idata.verbose_f) { + print_attack_info(&idata); + } + + /* + Set filter for IPv6 packets (find_ipv6_router() set its own filter fore receiving RAs) + */ + if (pcap_compile(idata.pfd, &pcap_filter, PCAP_UDPIPV6_NS_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1) { + printf("pcap_compile(): %s", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } + + if (pcap_setfilter(idata.pfd, &pcap_filter) == -1) { + printf("pcap_setfilter(): %s", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } + + pcap_freecode(&pcap_filter); + + /* Set initial contents of the attack packet */ + init_packet_data(&idata); + addr_key = random(); + + if (sleep_f) + pktinterval = (nsleep * 1000000) / (nsources * nports); + + timeout.tv_sec = pktinterval / 1000000; + timeout.tv_usec = pktinterval % 1000000; + stimeout = timeout; + + if (probemode_f) { + end_f = 0; + + if (!dstport_f) + dstport = 80; + + if (srcport_f) { + if (srcportrnd_f) { + randomize_port(&srcport, srcport, srcportpref); + } + } + else { + srcport = 50000 + random() % 15000; /* We select ports from the "high ports" range */ + } + + if (!rto_f) + rto = 1; + + if (!retrans_f) + retrans = 0; + + retr = 0; + retrans++; + + FD_ZERO(&sset); + FD_SET(idata.fd, &sset); + + lastprobe.tv_sec = 0; + lastprobe.tv_usec = 0; + + while (!end_f) { + if (gettimeofday(&curtime, NULL) == -1) { + if (idata.verbose_f) + perror("udp6"); + + exit(EXIT_FAILURE); + } + + if (is_time_elapsed(&curtime, &lastprobe, rto * 1000000) && retr < retrans) { + retr++; + lastprobe = curtime; + send_packet(&idata, NULL, NULL); + } + + if (is_time_elapsed(&curtime, &lastprobe, rto * 1000000) && retr >= retrans) { + end_f = 1; + break; + } + + rset = sset; + timeout.tv_usec = 0; + timeout.tv_sec = (rto < 1) ? rto : 1; + + if ((sel = select(idata.fd + 1, &rset, NULL, NULL, &timeout)) == -1) { + if (errno == EINTR) { + continue; + } + else { + puts("Error in select()"); + exit(EXIT_FAILURE); + } + } #if !defined(sun) && !defined(__sun) && !defined(__linux__) - if(sel && FD_ISSET(idata.fd, &rset)){ + if (sel && FD_ISSET(idata.fd, &rset)) { #else - if(TRUE){ + if (TRUE) { #endif - /* Read a packet */ - - if((r=pcap_next_ex(idata.pfd, &pkthdr, &pktdata)) == -1){ - printf("pcap_next_ex(): %s", pcap_geterr(idata.pfd)); - exit(EXIT_FAILURE); - } - else if(r == 1 && pktdata != NULL){ - pkt_ether = (struct ether_header *) pktdata; - pkt_ipv6 = (struct ip6_hdr *)((char *) pkt_ether + idata.linkhsize); - pkt_udp= (struct udp_hdr *) ( (char *) pkt_ipv6 + MIN_IPV6_HLEN); - pkt_ns= (struct nd_neighbor_solicit *) ( (char *) pkt_ipv6 + MIN_IPV6_HLEN); - pkt_end = (unsigned char *) pktdata + pkthdr->caplen; - - /* Some preliminar sanity checks. */ - /* XXX: Might need/could remove some of the checks below */ - if(!is_valid_udp_datagram(&idata, pktdata, pkthdr)) - continue; - - /* Check that we are able to look into the IPv6 header */ - if( (pkt_end - pktdata) < (idata.linkhsize + MIN_IPV6_HLEN)) - continue; - - if(is_eq_in6_addr(&(pkt_ipv6->ip6_src), &(idata.srcaddr))){ - continue; - } - - if(!is_eq_in6_addr(&(pkt_ipv6->ip6_dst), &(idata.srcaddr))){ - continue; - } - - if(pkt_udp->uh_sport != htons(dstport)){ - continue; - } - - if(pkt_udp->uh_dport != htons(srcport)){ - continue; - } - - /* The UDP checksum must be valid */ - if(in_chksum(pkt_ipv6, pkt_udp, pkt_end-((unsigned char *)pkt_udp), IPPROTO_UDP) != 0) - continue; - - printf("RESPONSE:UDP6\n"); - exit(EXIT_SUCCESS); - } - } - } - - puts("RESPONSE:TIMEOUT:"); - exit(EXIT_SUCCESS); - } - - - - /* Fire a UDP packet if an IPv6 Destination Address was specified */ - if(!listen_f && idata.dstaddr_f){ - - stimeout.tv_sec= pktinterval / 1000000; - stimeout.tv_usec= pktinterval % 1000000; - - if(loop_f || floods_f || floodp_f){ - if(idata.verbose_f){ - if(sleep_f){ - printf("Sending UDP datagrams every %u second%s...\n", nsleep, \ - ((nsleep>1)?"s":"")); - } - else if(bps_f){ - printf("Sending UDO datagrams at %lu pps...\n", rate); - } - else{ - printf("Sending UDP datagrams at %lu pps%s...\n", rate, (pps_f)?"":" (default)"); - } - } - } - - do{ - - send_packet(&idata, NULL, NULL); - - timeout= stimeout; - - if(loop_f && (sel=select(idata.fd +1, NULL, NULL, NULL, &timeout)) == -1){ - if(errno == EINTR){ - continue; - } - else{ - puts("Error in select()"); - exit(EXIT_FAILURE); - } - } - }while(loop_f); - - if(idata.verbose_f) - puts("Initial attack packet(s) sent successfully."); - - exit(EXIT_SUCCESS); - } - else if(listen_f){ - FD_ZERO(&sset); - FD_SET(idata.fd, &sset); - - if(idata.verbose_f){ - print_filters(&idata, &filters); - puts("Listening to incoming UDP datagrams..."); - } - - while(listen_f){ - rset= sset; - - timeout= stimeout; + /* Read a packet */ + + if ((r = pcap_next_ex(idata.pfd, &pkthdr, &pktdata)) == -1) { + printf("pcap_next_ex(): %s", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } + else if (r == 1 && pktdata != NULL) { + pkt_ether = (struct ether_header *)pktdata; + pkt_ipv6 = (struct ip6_hdr *)((char *)pkt_ether + idata.linkhsize); + pkt_udp = (struct udp_hdr *)((char *)pkt_ipv6 + MIN_IPV6_HLEN); + pkt_ns = (struct nd_neighbor_solicit *)((char *)pkt_ipv6 + MIN_IPV6_HLEN); + pkt_end = (unsigned char *)pktdata + pkthdr->caplen; + + /* Some preliminar sanity checks. */ + /* XXX: Might need/could remove some of the checks below */ + if (!is_valid_udp_datagram(&idata, pktdata, pkthdr)) + continue; + + /* Check that we are able to look into the IPv6 header */ + if ((pkt_end - pktdata) < (idata.linkhsize + MIN_IPV6_HLEN)) + continue; + + if (is_eq_in6_addr(&(pkt_ipv6->ip6_src), &(idata.srcaddr))) { + continue; + } + + if (!is_eq_in6_addr(&(pkt_ipv6->ip6_dst), &(idata.srcaddr))) { + continue; + } + + if (pkt_udp->uh_sport != htons(dstport)) { + continue; + } + + if (pkt_udp->uh_dport != htons(srcport)) { + continue; + } + + /* The UDP checksum must be valid */ + if (in_chksum(pkt_ipv6, pkt_udp, pkt_end - ((unsigned char *)pkt_udp), IPPROTO_UDP) != 0) + continue; + + printf("RESPONSE:UDP6\n"); + exit(EXIT_SUCCESS); + } + } + } + + puts("RESPONSE:TIMEOUT:"); + exit(EXIT_SUCCESS); + } + + /* Fire a UDP packet if an IPv6 Destination Address was specified */ + if (!listen_f && idata.dstaddr_f) { + + stimeout.tv_sec = pktinterval / 1000000; + stimeout.tv_usec = pktinterval % 1000000; + + if (loop_f || floods_f || floodp_f) { + if (idata.verbose_f) { + if (sleep_f) { + printf("Sending UDP datagrams every %u second%s...\n", nsleep, ((nsleep > 1) ? "s" : "")); + } + else if (bps_f) { + printf("Sending UDO datagrams at %lu pps...\n", rate); + } + else { + printf("Sending UDP datagrams at %lu pps%s...\n", rate, (pps_f) ? "" : " (default)"); + } + } + } + + do { + + send_packet(&idata, NULL, NULL); + + timeout = stimeout; + + if (loop_f && (sel = select(idata.fd + 1, NULL, NULL, NULL, &timeout)) == -1) { + if (errno == EINTR) { + continue; + } + else { + puts("Error in select()"); + exit(EXIT_FAILURE); + } + } + } while (loop_f); + + if (idata.verbose_f) + puts("Initial attack packet(s) sent successfully."); + + exit(EXIT_SUCCESS); + } + else if (listen_f) { + FD_ZERO(&sset); + FD_SET(idata.fd, &sset); + + if (idata.verbose_f) { + print_filters(&idata, &filters); + puts("Listening to incoming UDP datagrams..."); + } + + while (listen_f) { + rset = sset; + + timeout = stimeout; /* XXX: need to address the select() thing */ #if !defined(sun) && !defined(__sun) && !defined(__linux__) - if((sel=select(idata.fd+1, &rset, NULL, NULL, ((floods_f || floodp_f) && !donesending_f)?(&timeout):NULL)) == -1){ + if ((sel = select(idata.fd + 1, &rset, NULL, NULL, + ((floods_f || floodp_f) && !donesending_f) ? (&timeout) : NULL)) == -1) { #else - timeout.tv_usec=10000; - timeout.tv_sec= 0; - if((sel=select(idata.fd+1, &rset, NULL, NULL, &timeout)) == -1){ + timeout.tv_usec = 10000; + timeout.tv_sec = 0; + if ((sel = select(idata.fd + 1, &rset, NULL, NULL, &timeout)) == -1) { #endif - if(errno == EINTR){ - continue; - } - else{ - puts("Error in select()"); - exit(EXIT_FAILURE); - } - } - - /* If there are some bits set, we need to check whether it's time to send packets */ + if (errno == EINTR) { + continue; + } + else { + puts("Error in select()"); + exit(EXIT_FAILURE); + } + } + + /* If there are some bits set, we need to check whether it's time to send packets */ #if !defined(sun) && !defined(__sun) && !defined(__linux__) - if(sel){ + if (sel) { #else - if(TRUE){ + if (TRUE) { #endif - if(gettimeofday(&curtime, NULL) == -1){ - if(idata.verbose_f) - perror("udp6"); + if (gettimeofday(&curtime, NULL) == -1) { + if (idata.verbose_f) + perror("udp6"); - exit(EXIT_FAILURE); - } - } + exit(EXIT_FAILURE); + } + } #if !defined(sun) && !defined(__sun) && !defined(__linux__) - if(sel && FD_ISSET(idata.fd, &rset)){ + if (sel && FD_ISSET(idata.fd, &rset)) { #else - if(TRUE){ + if (TRUE) { #endif - /* Read a packet */ - if((r=pcap_next_ex(idata.pfd, &pkthdr, &pktdata)) == -1){ - printf("pcap_next_ex(): %s", pcap_geterr(idata.pfd)); - exit(EXIT_FAILURE); - } - else if(r == 1 && pktdata != NULL){ - pkt_ether = (struct ether_header *) pktdata; - pkt_ipv6 = (struct ip6_hdr *)((char *) pkt_ether + idata.linkhsize); - pkt_udp= (struct udp_hdr *) ( (char *) pkt_ipv6 + MIN_IPV6_HLEN); - pkt_ns= (struct nd_neighbor_solicit *) ( (char *) pkt_ipv6 + MIN_IPV6_HLEN); - pkt_end = (unsigned char *) pktdata + pkthdr->caplen; - - /* Check that we are able to look into the IPv6 header */ - if( (pkt_end - pktdata) < (idata.linkhsize + MIN_IPV6_HLEN)) - continue; - - accepted_f=0; - - if(idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK)){ - if(filters.nblocklinksrc){ - if(match_ether(filters.blocklinksrc, filters.nblocklinksrc, &(pkt_ether->src))){ - if(idata.verbose_f>1) - print_filter_result(&idata, pktdata, BLOCKED); - - continue; - } - } - - if(filters.nblocklinkdst){ - if(match_ether(filters.blocklinkdst, filters.nblocklinkdst, &(pkt_ether->dst))){ - if(idata.verbose_f>1) - print_filter_result(&idata, pktdata, BLOCKED); - - continue; - } - } - } - - if(filters.nblocksrc){ - if(match_ipv6(filters.blocksrc, filters.blocksrclen, filters.nblocksrc, &(pkt_ipv6->ip6_src))){ - if(idata.verbose_f>1) - print_filter_result(&idata, pktdata, BLOCKED); - - continue; - } - } - - if(filters.nblockdst){ - if(match_ipv6(filters.blockdst, filters.blockdstlen, filters.nblockdst, &(pkt_ipv6->ip6_dst))){ - if(idata.verbose_f>1) - print_filter_result(&idata, pktdata, BLOCKED); - - continue; - } - } - - if(idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK)){ - if(filters.nacceptlinksrc){ - if(match_ether(filters.acceptlinksrc, filters.nacceptlinksrc, &(pkt_ether->src))) - accepted_f=1; - } - - if(filters.nacceptlinkdst && !accepted_f){ - if(match_ether(filters.acceptlinkdst, filters.nacceptlinkdst, &(pkt_ether->dst))) - accepted_f= 1; - } - } - - if(filters.nacceptsrc && !accepted_f){ - if(match_ipv6(filters.acceptsrc, filters.acceptsrclen, filters.nacceptsrc, &(pkt_ipv6->ip6_src))) - accepted_f= 1; - } - - if(filters.nacceptdst && !accepted_f){ - if(match_ipv6(filters.acceptdst, filters.acceptdstlen, filters.nacceptdst, &(pkt_ipv6->ip6_dst))) - accepted_f=1; - } - - if(filters.acceptfilters_f && !accepted_f){ - if(idata.verbose_f>1) - print_filter_result(&idata, pktdata, BLOCKED); - - continue; - } - - if(idata.verbose_f>1) - print_filter_result(&idata, pktdata, ACCEPTED); - - if(pkt_ipv6->ip6_nxt == IPPROTO_UDP){ - /* Some preliminar sanity checks. */ - /* XXX: Might need/could remove some of the checks below */ - if(!is_valid_udp_datagram(&idata, pktdata, pkthdr)) - continue; - - /* Check that we are able to look into the UDP header */ - if( (pkt_end - pktdata) < (idata.linkhsize + MIN_IPV6_HLEN + sizeof(struct udp_hdr))){ - continue; - } - - if(idata.dstaddr_f){ - if(!floods_f){ - /* Discard our own packets */ - if(is_eq_in6_addr(&(pkt_ipv6->ip6_src), &(idata.srcaddr))){ - continue; - } - - if(!is_eq_in6_addr(&(pkt_ipv6->ip6_dst), &(idata.srcaddr))){ - continue; - } - } - else{ - /* Discard our own packets */ - if(!is_eq_in6_addr(&(pkt_ipv6->ip6_src), &(idata.dstaddr))){ - continue; - } - - if(useaddrkey_f){ - if( (ntohl(pkt_ipv6->ip6_src.s6_addr32[2]) & 0x0000ffff) == ( (uint16_t)(ntohl(pkt_ipv6->ip6_src.s6_addr32[2])>>16) ^ addr_key) && \ - (ntohl(pkt_ipv6->ip6_src.s6_addr32[3]) & 0x0000ffff) == ( (uint16_t)(ntohl(pkt_ipv6->ip6_src.s6_addr32[3])>>16) ^ addr_key)){ - continue; - } - - if( (ntohl(pkt_ipv6->ip6_dst.s6_addr32[2]) & 0x0000ffff) != ((uint16_t)(ntohl(pkt_ipv6->ip6_dst.s6_addr32[2]) >> 16) ^ addr_key) || \ - (ntohl(pkt_ipv6->ip6_dst.s6_addr32[3]) & 0x0000ffff) != ((uint16_t)(ntohl(pkt_ipv6->ip6_dst.s6_addr32[3])>>16) ^ addr_key)){ - continue; - } - } - } - - /* The UDP checksum must be valid */ - if(in_chksum(pkt_ipv6, pkt_udp, pkt_end-((unsigned char *)pkt_udp), IPPROTO_UDP) != 0) - continue; - - if(pkt_udp->uh_sport != htons(dstport)){ - continue; - } - - if(!floodp_f && pkt_udp->uh_dport != htons(srcport)){ - continue; - } - } - - /* Send a UDP datagram */ - send_packet(&idata, pktdata, pkthdr); - } - else if(pkt_ipv6->ip6_nxt == IPPROTO_ICMPV6){ - - /* Check that we are able to look into the NS header */ - if( (pkt_end - pktdata) < (idata.linkhsize + MIN_IPV6_HLEN + sizeof(struct nd_neighbor_solicit))){ - continue; - } - - if(idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK)){ - if(floods_f){ - if(useaddrkey_f){ - if( (ntohl(pkt_ns->nd_ns_target.s6_addr32[2]) & 0x0000ffff) != ( (ntohl(pkt_ns->nd_ns_target.s6_addr32[2]) >>16) ^ addr_key) || \ - (ntohl(pkt_ns->nd_ns_target.s6_addr32[3]) & 0x0000ffff) != ( (ntohl(pkt_ns->nd_ns_target.s6_addr32[3]) >>16) ^ addr_key)){ - continue; - } - } - - /* Check that the target address belongs to the prefix from which we are sending packets */ - if(!match_ipv6(&(idata.srcaddr), &idata.srcpreflen, 1, &(pkt_ns->nd_ns_target))){ - continue; - } - } - else{ - if(!is_eq_in6_addr( &(pkt_ns->nd_ns_target), &(idata.srcaddr)) ){ - continue; - } - } - - if(send_neighbor_advert(&idata, idata.pfd, pktdata) == -1){ - puts("Error sending Neighbor Advertisement"); - exit(EXIT_FAILURE); - } - } - } - } - } - - if(idata.dstaddr_f && !donesending_f && is_time_elapsed(&curtime, &lastprobe, pktinterval)){ - lastprobe= curtime; - send_packet(&idata, NULL, NULL); - } - } - - exit(EXIT_SUCCESS); - } - - if(!(idata.dstaddr_f) && !listen_f){ - puts("Error: Nothing to send! (Destination Address left unspecified, and not using listening mode)"); - exit(EXIT_FAILURE); - } - - exit(EXIT_SUCCESS); + /* Read a packet */ + if ((r = pcap_next_ex(idata.pfd, &pkthdr, &pktdata)) == -1) { + printf("pcap_next_ex(): %s", pcap_geterr(idata.pfd)); + exit(EXIT_FAILURE); + } + else if (r == 1 && pktdata != NULL) { + pkt_ether = (struct ether_header *)pktdata; + pkt_ipv6 = (struct ip6_hdr *)((char *)pkt_ether + idata.linkhsize); + pkt_udp = (struct udp_hdr *)((char *)pkt_ipv6 + MIN_IPV6_HLEN); + pkt_ns = (struct nd_neighbor_solicit *)((char *)pkt_ipv6 + MIN_IPV6_HLEN); + pkt_end = (unsigned char *)pktdata + pkthdr->caplen; + + /* Check that we are able to look into the IPv6 header */ + if ((pkt_end - pktdata) < (idata.linkhsize + MIN_IPV6_HLEN)) + continue; + + accepted_f = 0; + + if (idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK)) { + if (filters.nblocklinksrc) { + if (match_ether(filters.blocklinksrc, filters.nblocklinksrc, &(pkt_ether->src))) { + if (idata.verbose_f > 1) + print_filter_result(&idata, pktdata, BLOCKED); + + continue; + } + } + + if (filters.nblocklinkdst) { + if (match_ether(filters.blocklinkdst, filters.nblocklinkdst, &(pkt_ether->dst))) { + if (idata.verbose_f > 1) + print_filter_result(&idata, pktdata, BLOCKED); + + continue; + } + } + } + + if (filters.nblocksrc) { + if (match_ipv6(filters.blocksrc, filters.blocksrclen, filters.nblocksrc, + &(pkt_ipv6->ip6_src))) { + if (idata.verbose_f > 1) + print_filter_result(&idata, pktdata, BLOCKED); + + continue; + } + } + + if (filters.nblockdst) { + if (match_ipv6(filters.blockdst, filters.blockdstlen, filters.nblockdst, + &(pkt_ipv6->ip6_dst))) { + if (idata.verbose_f > 1) + print_filter_result(&idata, pktdata, BLOCKED); + + continue; + } + } + + if (idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK)) { + if (filters.nacceptlinksrc) { + if (match_ether(filters.acceptlinksrc, filters.nacceptlinksrc, &(pkt_ether->src))) + accepted_f = 1; + } + + if (filters.nacceptlinkdst && !accepted_f) { + if (match_ether(filters.acceptlinkdst, filters.nacceptlinkdst, &(pkt_ether->dst))) + accepted_f = 1; + } + } + + if (filters.nacceptsrc && !accepted_f) { + if (match_ipv6(filters.acceptsrc, filters.acceptsrclen, filters.nacceptsrc, + &(pkt_ipv6->ip6_src))) + accepted_f = 1; + } + + if (filters.nacceptdst && !accepted_f) { + if (match_ipv6(filters.acceptdst, filters.acceptdstlen, filters.nacceptdst, + &(pkt_ipv6->ip6_dst))) + accepted_f = 1; + } + + if (filters.acceptfilters_f && !accepted_f) { + if (idata.verbose_f > 1) + print_filter_result(&idata, pktdata, BLOCKED); + + continue; + } + + if (idata.verbose_f > 1) + print_filter_result(&idata, pktdata, ACCEPTED); + + if (pkt_ipv6->ip6_nxt == IPPROTO_UDP) { + /* Some preliminar sanity checks. */ + /* XXX: Might need/could remove some of the checks below */ + if (!is_valid_udp_datagram(&idata, pktdata, pkthdr)) + continue; + + /* Check that we are able to look into the UDP header */ + if ((pkt_end - pktdata) < (idata.linkhsize + MIN_IPV6_HLEN + sizeof(struct udp_hdr))) { + continue; + } + + if (idata.dstaddr_f) { + if (!floods_f) { + /* Discard our own packets */ + if (is_eq_in6_addr(&(pkt_ipv6->ip6_src), &(idata.srcaddr))) { + continue; + } + + if (!is_eq_in6_addr(&(pkt_ipv6->ip6_dst), &(idata.srcaddr))) { + continue; + } + } + else { + /* Discard our own packets */ + if (!is_eq_in6_addr(&(pkt_ipv6->ip6_src), &(idata.dstaddr))) { + continue; + } + + if (useaddrkey_f) { + if ((ntohl(pkt_ipv6->ip6_src.s6_addr32[2]) & 0x0000ffff) == + ((uint16_t)(ntohl(pkt_ipv6->ip6_src.s6_addr32[2]) >> 16) ^ addr_key) && + (ntohl(pkt_ipv6->ip6_src.s6_addr32[3]) & 0x0000ffff) == + ((uint16_t)(ntohl(pkt_ipv6->ip6_src.s6_addr32[3]) >> 16) ^ addr_key)) { + continue; + } + + if ((ntohl(pkt_ipv6->ip6_dst.s6_addr32[2]) & 0x0000ffff) != + ((uint16_t)(ntohl(pkt_ipv6->ip6_dst.s6_addr32[2]) >> 16) ^ addr_key) || + (ntohl(pkt_ipv6->ip6_dst.s6_addr32[3]) & 0x0000ffff) != + ((uint16_t)(ntohl(pkt_ipv6->ip6_dst.s6_addr32[3]) >> 16) ^ addr_key)) { + continue; + } + } + } + + /* The UDP checksum must be valid */ + if (in_chksum(pkt_ipv6, pkt_udp, pkt_end - ((unsigned char *)pkt_udp), IPPROTO_UDP) != 0) + continue; + + if (pkt_udp->uh_sport != htons(dstport)) { + continue; + } + + if (!floodp_f && pkt_udp->uh_dport != htons(srcport)) { + continue; + } + } + + /* Send a UDP datagram */ + send_packet(&idata, pktdata, pkthdr); + } + else if (pkt_ipv6->ip6_nxt == IPPROTO_ICMPV6) { + + /* Check that we are able to look into the NS header */ + if ((pkt_end - pktdata) < + (idata.linkhsize + MIN_IPV6_HLEN + sizeof(struct nd_neighbor_solicit))) { + continue; + } + + if (idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK)) { + if (floods_f) { + if (useaddrkey_f) { + if ((ntohl(pkt_ns->nd_ns_target.s6_addr32[2]) & 0x0000ffff) != + ((ntohl(pkt_ns->nd_ns_target.s6_addr32[2]) >> 16) ^ addr_key) || + (ntohl(pkt_ns->nd_ns_target.s6_addr32[3]) & 0x0000ffff) != + ((ntohl(pkt_ns->nd_ns_target.s6_addr32[3]) >> 16) ^ addr_key)) { + continue; + } + } + + /* Check that the target address belongs to the prefix from which we are sending packets + */ + if (!match_ipv6(&(idata.srcaddr), &idata.srcpreflen, 1, &(pkt_ns->nd_ns_target))) { + continue; + } + } + else { + if (!is_eq_in6_addr(&(pkt_ns->nd_ns_target), &(idata.srcaddr))) { + continue; + } + } + + if (send_neighbor_advert(&idata, idata.pfd, pktdata) == -1) { + puts("Error sending Neighbor Advertisement"); + exit(EXIT_FAILURE); + } + } + } + } + } + + if (idata.dstaddr_f && !donesending_f && is_time_elapsed(&curtime, &lastprobe, pktinterval)) { + lastprobe = curtime; + send_packet(&idata, NULL, NULL); + } + } + + exit(EXIT_SUCCESS); + } + + if (!(idata.dstaddr_f) && !listen_f) { + puts("Error: Nothing to send! (Destination Address left unspecified, and not using listening mode)"); + exit(EXIT_FAILURE); + } + + exit(EXIT_SUCCESS); } - - /* * Function: init_packet_data() * * Initialize the contents of the attack packet (Ethernet header, IPv6 Header, and ICMPv6 header) * that are expected to remain constant for the specified attack. */ -void init_packet_data(struct iface_data *idata){ - struct dlt_null *dlt_null; - ethernet= (struct ether_header *) buffer; - dlt_null= (struct dlt_null *) buffer; - v6buffer = buffer + idata->linkhsize; - ipv6 = (struct ip6_hdr *) v6buffer; - - if(idata->type == DLT_EN10MB){ - ethernet->ether_type = htons(ETHERTYPE_IPV6); - - if(!(idata->flags & IFACE_LOOPBACK)){ - ethernet->src = idata->hsrcaddr; - ethernet->dst = idata->hdstaddr; - } - } - else if(idata->type == DLT_NULL){ - dlt_null->family= PF_INET6; - } -#if defined (__OpenBSD__) - else if(idata->type == DLT_LOOP){ - dlt_null->family= htonl(PF_INET6); - } +void init_packet_data(struct iface_data *idata) { + struct dlt_null *dlt_null; + ethernet = (struct ether_header *)buffer; + dlt_null = (struct dlt_null *)buffer; + v6buffer = buffer + idata->linkhsize; + ipv6 = (struct ip6_hdr *)v6buffer; + + if (idata->type == DLT_EN10MB) { + ethernet->ether_type = htons(ETHERTYPE_IPV6); + + if (!(idata->flags & IFACE_LOOPBACK)) { + ethernet->src = idata->hsrcaddr; + ethernet->dst = idata->hdstaddr; + } + } + else if (idata->type == DLT_NULL) { + dlt_null->family = PF_INET6; + } +#if defined(__OpenBSD__) + else if (idata->type == DLT_LOOP) { + dlt_null->family = htonl(PF_INET6); + } #endif - ipv6->ip6_flow=0; - ipv6->ip6_vfc= 0x60; - ipv6->ip6_hlim= hoplimit; - ipv6->ip6_src= idata->srcaddr; - ipv6->ip6_dst= idata->dstaddr; - - prev_nh = (unsigned char *) &(ipv6->ip6_nxt); - - ptr = (unsigned char *) v6buffer + MIN_IPV6_HLEN; - - if(hbhopthdr_f){ - hbhopthdrs=0; - - while(hbhopthdrs < nhbhopthdr){ - if((ptr+ hbhopthdrlen[hbhopthdrs]) > (v6buffer+ idata->mtu)){ - puts("Packet too large while processing HBH Opt. Header"); - exit(EXIT_FAILURE); - } - - *prev_nh = IPPROTO_HOPOPTS; - prev_nh = ptr; - memcpy(ptr, hbhopthdr[hbhopthdrs], hbhopthdrlen[hbhopthdrs]); - ptr = ptr + hbhopthdrlen[hbhopthdrs]; - hbhopthdrs++; - } - } - - if(dstoptuhdr_f){ - dstoptuhdrs=0; - - while(dstoptuhdrs < ndstoptuhdr){ - if((ptr+ dstoptuhdrlen[dstoptuhdrs]) > (v6buffer+ idata->mtu)){ - puts("Packet too large while processing Dest. Opt. Header (Unfrag. Part)"); - exit(EXIT_FAILURE); - } - - *prev_nh = IPPROTO_DSTOPTS; - prev_nh = ptr; - memcpy(ptr, dstoptuhdr[dstoptuhdrs], dstoptuhdrlen[dstoptuhdrs]); - ptr = ptr + dstoptuhdrlen[dstoptuhdrs]; - dstoptuhdrs++; - } - } - - /* Everything that follows is the Fragmentable Part of the packet */ - fragpart = ptr; - - if(idata->fragh_f){ - /* Check that we are able to send the Unfragmentable Part, together with a - Fragment Header and a chunk data over our link layer - */ - if( (fragpart+sizeof(fraghdr)+nfrags) > (v6buffer+idata->mtu)){ - puts("Unfragmentable part too large for current MTU"); - exit(EXIT_FAILURE); - } - - /* We prepare a separete Fragment Header, but we do not include it in the packet to be sent. - This Fragment Header will be used (an assembled with the rest of the packet by the - send_packet() function. - */ - memset(&fraghdr, 0, FRAG_HDR_SIZE); - *prev_nh = IPPROTO_FRAGMENT; - prev_nh = (unsigned char *) &fraghdr; - } - - if(dstopthdr_f){ - dstopthdrs=0; - - while(dstopthdrs < ndstopthdr){ - if((ptr+ dstopthdrlen[dstopthdrs]) > (v6buffer+ idata->max_packet_size)){ - puts("Packet too large while processing Dest. Opt. Header (should be using the Frag. option?)"); - exit(EXIT_FAILURE); - } - - *prev_nh = IPPROTO_DSTOPTS; - prev_nh = ptr; - memcpy(ptr, dstopthdr[dstopthdrs], dstopthdrlen[dstopthdrs]); - ptr = ptr + dstopthdrlen[dstopthdrs]; - dstopthdrs++; - } - } - - - *prev_nh = IPPROTO_UDP; - - startofprefixes=ptr; + ipv6->ip6_flow = 0; + ipv6->ip6_vfc = 0x60; + ipv6->ip6_hlim = hoplimit; + ipv6->ip6_src = idata->srcaddr; + ipv6->ip6_dst = idata->dstaddr; + + prev_nh = (unsigned char *)&(ipv6->ip6_nxt); + + ptr = (unsigned char *)v6buffer + MIN_IPV6_HLEN; + + if (hbhopthdr_f) { + hbhopthdrs = 0; + + while (hbhopthdrs < nhbhopthdr) { + if ((ptr + hbhopthdrlen[hbhopthdrs]) > (v6buffer + idata->mtu)) { + puts("Packet too large while processing HBH Opt. Header"); + exit(EXIT_FAILURE); + } + + *prev_nh = IPPROTO_HOPOPTS; + prev_nh = ptr; + memcpy(ptr, hbhopthdr[hbhopthdrs], hbhopthdrlen[hbhopthdrs]); + ptr = ptr + hbhopthdrlen[hbhopthdrs]; + hbhopthdrs++; + } + } + + if (dstoptuhdr_f) { + dstoptuhdrs = 0; + + while (dstoptuhdrs < ndstoptuhdr) { + if ((ptr + dstoptuhdrlen[dstoptuhdrs]) > (v6buffer + idata->mtu)) { + puts("Packet too large while processing Dest. Opt. Header (Unfrag. Part)"); + exit(EXIT_FAILURE); + } + + *prev_nh = IPPROTO_DSTOPTS; + prev_nh = ptr; + memcpy(ptr, dstoptuhdr[dstoptuhdrs], dstoptuhdrlen[dstoptuhdrs]); + ptr = ptr + dstoptuhdrlen[dstoptuhdrs]; + dstoptuhdrs++; + } + } + + /* Everything that follows is the Fragmentable Part of the packet */ + fragpart = ptr; + + if (idata->fragh_f) { + /* Check that we are able to send the Unfragmentable Part, together with a + Fragment Header and a chunk data over our link layer + */ + if ((fragpart + sizeof(fraghdr) + nfrags) > (v6buffer + idata->mtu)) { + puts("Unfragmentable part too large for current MTU"); + exit(EXIT_FAILURE); + } + + /* We prepare a separete Fragment Header, but we do not include it in the packet to be sent. + This Fragment Header will be used (an assembled with the rest of the packet by the + send_packet() function. + */ + memset(&fraghdr, 0, FRAG_HDR_SIZE); + *prev_nh = IPPROTO_FRAGMENT; + prev_nh = (unsigned char *)&fraghdr; + } + + if (dstopthdr_f) { + dstopthdrs = 0; + + while (dstopthdrs < ndstopthdr) { + if ((ptr + dstopthdrlen[dstopthdrs]) > (v6buffer + idata->max_packet_size)) { + puts("Packet too large while processing Dest. Opt. Header (should be using the Frag. option?)"); + exit(EXIT_FAILURE); + } + + *prev_nh = IPPROTO_DSTOPTS; + prev_nh = ptr; + memcpy(ptr, dstopthdr[dstopthdrs], dstopthdrlen[dstopthdrs]); + ptr = ptr + dstopthdrlen[dstopthdrs]; + dstopthdrs++; + } + } + + *prev_nh = IPPROTO_UDP; + + startofprefixes = ptr; } - - /* * Function: send_packet() * * Initialize the remaining fields of the UDP datagram, and send the attack packet(s). */ -void send_packet(struct iface_data *idata, const u_char *pktdata, struct pcap_pkthdr *pkthdr){ - static unsigned int sources=0, ports=0; - ptr=startofprefixes; - senddata_f= 0; - - if(pktdata != NULL){ /* Sending an UDP datagram in response to a received packet */ - pkt_ether = (struct ether_header *) pktdata; - pkt_ipv6 = (struct ip6_hdr *)((char *) pkt_ether + idata->linkhsize); - pkt_udp= (struct udp_hdr *)( (char *) pkt_ipv6 + sizeof(struct ip6_hdr)); - pkt_end = (unsigned char *) pktdata + pkthdr->caplen; - - /* The packet length is the minimum of what we capured, and what is specified in the - IPv6 Total Lenght field - */ - if( pkt_end > ((unsigned char *)pkt_ipv6 + sizeof(struct ip6_hdr) + ntohs(pkt_ipv6->ip6_plen)) ) - pkt_end = (unsigned char *)pkt_ipv6 + sizeof(struct ip6_hdr) + ntohs(pkt_ipv6->ip6_plen); - - - pkt_ipv6addr = &(pkt_ipv6->ip6_src); - - /* - We don't send any packets if the Source Address of the captured packet is the unspecified - address or a multicast address - */ - if(IN6_IS_ADDR_UNSPECIFIED(pkt_ipv6addr) || IN6_IS_ADDR_MULTICAST(pkt_ipv6addr)){ - return; - } - else{ - ipv6->ip6_dst = pkt_ipv6->ip6_src; - - if(idata->type == DLT_EN10MB && !(idata->flags & IFACE_LOOPBACK)) - ethernet->dst = pkt_ether->src; - } - - pkt_ipv6addr = &(pkt_ipv6->ip6_dst); - - /* - We do not send any packets if the Destination Address of the captured packet is the unspecified - address or a multicast address - */ - if(IN6_IS_ADDR_MULTICAST(pkt_ipv6addr) || IN6_IS_ADDR_MULTICAST(pkt_ipv6addr)){ - return; - } - else{ - ipv6->ip6_src = pkt_ipv6->ip6_dst; - - if(idata->type == DLT_EN10MB && !(idata->flags & IFACE_LOOPBACK)) - ethernet->src = pkt_ether->dst; - } - - - if( (ptr+sizeof(struct udp_hdr)) > (v6buffer+ idata->max_packet_size)){ - puts("Packet Too Large while inserting UDP header"); - exit(EXIT_FAILURE); - } - - udp = (struct udp_hdr *) ptr; - memset(udp, 0, sizeof(struct udp_hdr)); - - udp->uh_sport= pkt_udp->uh_dport; - udp->uh_dport= pkt_udp->uh_sport; - ptr+= sizeof(struct udp_hdr); - - if(rhbytes_f){ - if( (ptr + rhbytes) > v6buffer+ idata->max_packet_size){ - puts("Packet Too Large while inserting UDP datagram"); - exit(EXIT_FAILURE); - } - - while(rhbytes>=4){ - *(uint32_t *)ptr = random(); - ptr += sizeof(uint32_t); - rhbytes -= sizeof(uint32_t); - } - - while(rhbytes>0){ - *(uint8_t *) ptr= (uint8_t) random(); - ptr++; - rhbytes--; - } - } - else if(data_f){ - ptr= (unsigned char *)udp + sizeof(struct udp_hdr); - - if((ptr+ datalen) > (v6buffer + idata->max_packet_size)){ - if(idata->verbose_f) - puts("Packet too large while inserting UDP data"); - exit(EXIT_FAILURE); - } - - memcpy(ptr, data, datalen); - ptr+= datalen; - } - - udp->uh_ulen= htons(ptr - (unsigned char *) udp); - udp->uh_sum = 0; - udp->uh_sum = in_chksum(v6buffer, udp, ptr-((unsigned char *)udp), IPPROTO_UDP); - - frag_and_send(idata); - - return; - } - else{ - if(ports >= nports){ - sources++; - ports= 0; - } - - if(sources >= nsources){ - if(loop_f){ - sources= 0; - } - else{ - donesending_f= 1; - return; - } - } - - if( (ptr+sizeof(struct udp_hdr)) > (v6buffer + idata->max_packet_size)){ - puts("Packet Too Large while inserting UDP header"); - exit(EXIT_FAILURE); - } - - udp= (struct udp_hdr *) ptr; - memset(ptr, 0, sizeof(struct udp_hdr)); - - if(floodp_f){ - if(srcportrnd_f){ - randomize_port(&srcport, srcport, srcportpref); - } - else{ - srcport= random(); - } - } - - udp->uh_sport= htons(srcport); - udp->uh_dport= htons(dstport); - ptr += sizeof(struct udp_hdr); - - if(rhbytes_f){ - if( (ptr + rhbytes) > v6buffer + idata->max_packet_size){ - puts("Packet Too Large while inserting UDP datagram"); - exit(EXIT_FAILURE); - } - - while(rhbytes>=4){ - *(uint32_t *)ptr = random(); - ptr += sizeof(uint32_t); - rhbytes -= sizeof(uint32_t); - } - - while(rhbytes>0){ - *(uint8_t *) ptr= (uint8_t) random(); - ptr++; - rhbytes--; - } - } - else if(data_f){ - ptr= (unsigned char *)udp + sizeof(struct udp_hdr); - - if((ptr+ datalen) > (v6buffer + idata->max_packet_size)){ - if(idata->verbose_f) - puts("Packet too large while inserting UDP data"); - exit(EXIT_FAILURE); - } - - memcpy(ptr, data, datalen); - ptr+= datalen; - } - - udp->uh_ulen= htons(ptr - (unsigned char *) udp); - - if(floods_f && ports == 0){ - /* - Randomizing the IPv6 Source address based on the prefix specified by - "srcaddr" and srcpreflen. - */ - - randomize_ipv6_addr( &(ipv6->ip6_src), &(idata->srcaddr), idata->srcpreflen); - - /* - If we need to respond to incomming packets, we set the Interface ID such that we can - detect which IPv6 addresses we have used. - */ - if(listen_f && useaddrkey_f){ - ipv6->ip6_src.s6_addr32[2]= ntohl((uint32_t)random() <<16); - ipv6->ip6_src.s6_addr32[2]= htonl(ntohl(ipv6->ip6_src.s6_addr32[2]) | ((ntohl(ipv6->ip6_src.s6_addr32[2])>>16) ^ addr_key)); - - ipv6->ip6_src.s6_addr32[3]= ntohl((uint32_t)random() <<16); - ipv6->ip6_src.s6_addr32[3]= htonl(ntohl(ipv6->ip6_src.s6_addr32[3]) | (uint32_t)((ntohl(ipv6->ip6_src.s6_addr32[3]) >>16) ^ addr_key)); - } - - if(idata->type == DLT_EN10MB && !(idata->flags & IFACE_LOOPBACK) && !(idata->hsrcaddr_f)){ - for(i=0; i<6; i++) - ethernet->src.a[i]= random(); - } - } - - udp->uh_sum = 0; - udp->uh_sum = in_chksum(v6buffer, udp, ptr-((unsigned char *)udp), IPPROTO_UDP); - - frag_and_send(idata); - - ports++; - - return; - } +void send_packet(struct iface_data *idata, const u_char *pktdata, struct pcap_pkthdr *pkthdr) { + static unsigned int sources = 0, ports = 0; + ptr = startofprefixes; + senddata_f = 0; + + if (pktdata != NULL) { /* Sending an UDP datagram in response to a received packet */ + pkt_ether = (struct ether_header *)pktdata; + pkt_ipv6 = (struct ip6_hdr *)((char *)pkt_ether + idata->linkhsize); + pkt_udp = (struct udp_hdr *)((char *)pkt_ipv6 + sizeof(struct ip6_hdr)); + pkt_end = (unsigned char *)pktdata + pkthdr->caplen; + + /* The packet length is the minimum of what we capured, and what is specified in the + IPv6 Total Lenght field + */ + if (pkt_end > ((unsigned char *)pkt_ipv6 + sizeof(struct ip6_hdr) + ntohs(pkt_ipv6->ip6_plen))) + pkt_end = (unsigned char *)pkt_ipv6 + sizeof(struct ip6_hdr) + ntohs(pkt_ipv6->ip6_plen); + + pkt_ipv6addr = &(pkt_ipv6->ip6_src); + + /* + We don't send any packets if the Source Address of the captured packet is the unspecified + address or a multicast address + */ + if (IN6_IS_ADDR_UNSPECIFIED(pkt_ipv6addr) || IN6_IS_ADDR_MULTICAST(pkt_ipv6addr)) { + return; + } + else { + ipv6->ip6_dst = pkt_ipv6->ip6_src; + + if (idata->type == DLT_EN10MB && !(idata->flags & IFACE_LOOPBACK)) + ethernet->dst = pkt_ether->src; + } + + pkt_ipv6addr = &(pkt_ipv6->ip6_dst); + + /* + We do not send any packets if the Destination Address of the captured packet is the unspecified + address or a multicast address + */ + if (IN6_IS_ADDR_MULTICAST(pkt_ipv6addr) || IN6_IS_ADDR_MULTICAST(pkt_ipv6addr)) { + return; + } + else { + ipv6->ip6_src = pkt_ipv6->ip6_dst; + + if (idata->type == DLT_EN10MB && !(idata->flags & IFACE_LOOPBACK)) + ethernet->src = pkt_ether->dst; + } + + if ((ptr + sizeof(struct udp_hdr)) > (v6buffer + idata->max_packet_size)) { + puts("Packet Too Large while inserting UDP header"); + exit(EXIT_FAILURE); + } + + udp = (struct udp_hdr *)ptr; + memset(udp, 0, sizeof(struct udp_hdr)); + + udp->uh_sport = pkt_udp->uh_dport; + udp->uh_dport = pkt_udp->uh_sport; + ptr += sizeof(struct udp_hdr); + + if (rhbytes_f) { + if ((ptr + rhbytes) > v6buffer + idata->max_packet_size) { + puts("Packet Too Large while inserting UDP datagram"); + exit(EXIT_FAILURE); + } + + while (rhbytes >= 4) { + *(uint32_t *)ptr = random(); + ptr += sizeof(uint32_t); + rhbytes -= sizeof(uint32_t); + } + + while (rhbytes > 0) { + *(uint8_t *)ptr = (uint8_t)random(); + ptr++; + rhbytes--; + } + } + else if (data_f) { + ptr = (unsigned char *)udp + sizeof(struct udp_hdr); + + if ((ptr + datalen) > (v6buffer + idata->max_packet_size)) { + if (idata->verbose_f) + puts("Packet too large while inserting UDP data"); + exit(EXIT_FAILURE); + } + + memcpy(ptr, data, datalen); + ptr += datalen; + } + + udp->uh_ulen = htons(ptr - (unsigned char *)udp); + udp->uh_sum = 0; + udp->uh_sum = in_chksum(v6buffer, udp, ptr - ((unsigned char *)udp), IPPROTO_UDP); + + frag_and_send(idata); + + return; + } + else { + if (ports >= nports) { + sources++; + ports = 0; + } + + if (sources >= nsources) { + if (loop_f) { + sources = 0; + } + else { + donesending_f = 1; + return; + } + } + + if ((ptr + sizeof(struct udp_hdr)) > (v6buffer + idata->max_packet_size)) { + puts("Packet Too Large while inserting UDP header"); + exit(EXIT_FAILURE); + } + + udp = (struct udp_hdr *)ptr; + memset(ptr, 0, sizeof(struct udp_hdr)); + + if (floodp_f) { + if (srcportrnd_f) { + randomize_port(&srcport, srcport, srcportpref); + } + else { + srcport = random(); + } + } + + udp->uh_sport = htons(srcport); + udp->uh_dport = htons(dstport); + ptr += sizeof(struct udp_hdr); + + if (rhbytes_f) { + if ((ptr + rhbytes) > v6buffer + idata->max_packet_size) { + puts("Packet Too Large while inserting UDP datagram"); + exit(EXIT_FAILURE); + } + + while (rhbytes >= 4) { + *(uint32_t *)ptr = random(); + ptr += sizeof(uint32_t); + rhbytes -= sizeof(uint32_t); + } + + while (rhbytes > 0) { + *(uint8_t *)ptr = (uint8_t)random(); + ptr++; + rhbytes--; + } + } + else if (data_f) { + ptr = (unsigned char *)udp + sizeof(struct udp_hdr); + + if ((ptr + datalen) > (v6buffer + idata->max_packet_size)) { + if (idata->verbose_f) + puts("Packet too large while inserting UDP data"); + exit(EXIT_FAILURE); + } + + memcpy(ptr, data, datalen); + ptr += datalen; + } + + udp->uh_ulen = htons(ptr - (unsigned char *)udp); + + if (floods_f && ports == 0) { + /* + Randomizing the IPv6 Source address based on the prefix specified by + "srcaddr" and srcpreflen. + */ + + randomize_ipv6_addr(&(ipv6->ip6_src), &(idata->srcaddr), idata->srcpreflen); + + /* + If we need to respond to incomming packets, we set the Interface ID such that we can + detect which IPv6 addresses we have used. + */ + if (listen_f && useaddrkey_f) { + ipv6->ip6_src.s6_addr32[2] = ntohl((uint32_t)random() << 16); + ipv6->ip6_src.s6_addr32[2] = + htonl(ntohl(ipv6->ip6_src.s6_addr32[2]) | ((ntohl(ipv6->ip6_src.s6_addr32[2]) >> 16) ^ addr_key)); + + ipv6->ip6_src.s6_addr32[3] = ntohl((uint32_t)random() << 16); + ipv6->ip6_src.s6_addr32[3] = htonl(ntohl(ipv6->ip6_src.s6_addr32[3]) | + (uint32_t)((ntohl(ipv6->ip6_src.s6_addr32[3]) >> 16) ^ addr_key)); + } + + if (idata->type == DLT_EN10MB && !(idata->flags & IFACE_LOOPBACK) && !(idata->hsrcaddr_f)) { + for (i = 0; i < 6; i++) + ethernet->src.a[i] = random(); + } + } + + udp->uh_sum = 0; + udp->uh_sum = in_chksum(v6buffer, udp, ptr - ((unsigned char *)udp), IPPROTO_UDP); + + frag_and_send(idata); + + ports++; + + return; + } } - /* * Function: frag_and_send() * * Send an IPv6 datagram, and fragment if selected */ -void frag_and_send(struct iface_data *idata){ - if(!idata->fragh_f){ - ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); - - if((nw=pcap_inject(idata->pfd, buffer, ptr - buffer)) == -1){ - printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); - exit(EXIT_FAILURE); - } - - if(nw != (ptr-buffer)){ - printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", \ - nw, (LUI) (ptr-buffer)); - exit(EXIT_FAILURE); - } - } - else{ - ptrend= ptr; - ptr= fragpart; - fptr = fragbuffer; - fipv6 = (struct ip6_hdr *) (fragbuffer + idata->linkhsize); - fptrend = fptr + idata->linkhsize+MIN_IPV6_HLEN+MAX_IPV6_PAYLOAD; - memcpy(fptr, buffer, fragpart-buffer); - fptr = fptr + (fragpart-buffer); - - if( (fptr+FRAG_HDR_SIZE)> fptrend){ - puts("Unfragmentable Part is Too Large"); - exit(EXIT_FAILURE); - } - - memcpy(fptr, (char *) &fraghdr, FRAG_HDR_SIZE); - fh= (struct ip6_frag *) fptr; - fh->ip6f_ident=random(); - startoffragment = fptr + FRAG_HDR_SIZE; - - /* - * Check that the selected fragment size is not larger than the largest - * fragment size that can be sent - */ - if(nfrags > (fptrend - fptr)) - nfrags= (fptrend-fptr); - - m=IP6F_MORE_FRAG; - - while((ptr< ptrend) && m==IP6F_MORE_FRAG){ - fptr= startoffragment; - - if( (ptrend-ptr) <= nfrags){ - fragsize= ptrend-ptr; - m=0; - } - else{ - fragsize = (nfrags + 7) & ntohs(IP6F_OFF_MASK); - } - - memcpy(fptr, ptr, fragsize); - fh->ip6f_offlg = (htons(ptr-fragpart) & IP6F_OFF_MASK) | m; - ptr+=fragsize; - fptr+=fragsize; - - fipv6->ip6_plen = htons((fptr - fragbuffer) - MIN_IPV6_HLEN - idata->linkhsize); - - if((nw=pcap_inject(idata->pfd, fragbuffer, fptr - fragbuffer)) == -1){ - printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); - exit(EXIT_FAILURE); - } - - if(nw != (fptr- fragbuffer)){ - printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", \ - nw, (LUI) (ptr-buffer)); - exit(EXIT_FAILURE); - } - } /* Sending fragments */ - } /* Sending fragmented datagram */ +void frag_and_send(struct iface_data *idata) { + if (!idata->fragh_f) { + ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); + + if ((nw = pcap_inject(idata->pfd, buffer, ptr - buffer)) == -1) { + printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); + exit(EXIT_FAILURE); + } + + if (nw != (ptr - buffer)) { + printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, (LUI)(ptr - buffer)); + exit(EXIT_FAILURE); + } + } + else { + ptrend = ptr; + ptr = fragpart; + fptr = fragbuffer; + fipv6 = (struct ip6_hdr *)(fragbuffer + idata->linkhsize); + fptrend = fptr + idata->linkhsize + MIN_IPV6_HLEN + MAX_IPV6_PAYLOAD; + memcpy(fptr, buffer, fragpart - buffer); + fptr = fptr + (fragpart - buffer); + + if ((fptr + FRAG_HDR_SIZE) > fptrend) { + puts("Unfragmentable Part is Too Large"); + exit(EXIT_FAILURE); + } + + memcpy(fptr, (char *)&fraghdr, FRAG_HDR_SIZE); + fh = (struct ip6_frag *)fptr; + fh->ip6f_ident = random(); + startoffragment = fptr + FRAG_HDR_SIZE; + + /* + * Check that the selected fragment size is not larger than the largest + * fragment size that can be sent + */ + if (nfrags > (fptrend - fptr)) + nfrags = (fptrend - fptr); + + m = IP6F_MORE_FRAG; + + while ((ptr < ptrend) && m == IP6F_MORE_FRAG) { + fptr = startoffragment; + + if ((ptrend - ptr) <= nfrags) { + fragsize = ptrend - ptr; + m = 0; + } + else { + fragsize = (nfrags + 7) & ntohs(IP6F_OFF_MASK); + } + + memcpy(fptr, ptr, fragsize); + fh->ip6f_offlg = (htons(ptr - fragpart) & IP6F_OFF_MASK) | m; + ptr += fragsize; + fptr += fragsize; + + fipv6->ip6_plen = htons((fptr - fragbuffer) - MIN_IPV6_HLEN - idata->linkhsize); + + if ((nw = pcap_inject(idata->pfd, fragbuffer, fptr - fragbuffer)) == -1) { + printf("pcap_inject(): %s\n", pcap_geterr(idata->pfd)); + exit(EXIT_FAILURE); + } + + if (nw != (fptr - fragbuffer)) { + printf("pcap_inject(): only wrote %d bytes (rather than %lu bytes)\n", nw, (LUI)(ptr - buffer)); + exit(EXIT_FAILURE); + } + } /* Sending fragments */ + } /* Sending fragmented datagram */ } - /* * Function: usage() * * Prints the syntax of the udp6 tool */ -void usage(void){ - puts("usage: udp6 [-i INTERFACE] [-S LINK_SRC_ADDR] [-D LINK-DST-ADDR] " - "[-s SRC_ADDR[/LEN]] [-d DST_ADDR] [-A HOP_LIMIT] [-y FRAG_SIZE] [-u DST_OPT_HDR_SIZE] " - "[-U DST_OPT_U_HDR_SIZE] [-H HBH_OPT_HDR_SIZE] [-P PAYLOAD_SIZE] [-o SRC_PORT[/LEN]] " - "[-a DST_PORT[/LEN]] " - "[-N] [-f] [-j PREFIX[/LEN]] [-k PREFIX[/LEN]] [-J LINK_ADDR] [-K LINK_ADDR] " - "[-b PREFIX[/LEN]] [-g PREFIX[/LEN]] [-B LINK_ADDR] [-G LINK_ADDR] " - "[-F N_SOURCES] [-T N_PORTS] [-L | -l] [-z SECONDS] [-v] [-h]"); +void usage(void) { + puts("usage: udp6 [-i INTERFACE] [-S LINK_SRC_ADDR] [-D LINK-DST-ADDR] " + "[-s SRC_ADDR[/LEN]] [-d DST_ADDR] [-A HOP_LIMIT] [-y FRAG_SIZE] [-u DST_OPT_HDR_SIZE] " + "[-U DST_OPT_U_HDR_SIZE] [-H HBH_OPT_HDR_SIZE] [-P PAYLOAD_SIZE] [-o SRC_PORT[/LEN]] " + "[-a DST_PORT[/LEN]] " + "[-N] [-f] [-j PREFIX[/LEN]] [-k PREFIX[/LEN]] [-J LINK_ADDR] [-K LINK_ADDR] " + "[-b PREFIX[/LEN]] [-g PREFIX[/LEN]] [-B LINK_ADDR] [-G LINK_ADDR] " + "[-F N_SOURCES] [-T N_PORTS] [-L | -l] [-z SECONDS] [-v] [-h]"); } - /* * Function: print_help() * * Prints help information for the udp6 tool */ -void print_help(void){ - puts(SI6_TOOLKIT); - puts( "udp6: Security assessment tool for attack vectors based on UDP/IPv6 packets\n"); - usage(); - - puts("\nOPTIONS:\n" - " --interface, -i Network interface\n" - " --src-addr, -s IPv6 Source Address (ADDRESSS[/LEN])\n" - " --dst-addr, -d IPv6 Destination Address\n" - " --hop-limit, -A IPv6 Hop Limit\n" - " --frag-hdr. -y Fragment Header\n" - " --dst-opt-hdr, -u Destination Options Header (Fragmentable Part)\n" - " --dst-opt-u-hdr, -U Destination Options Header (Unfragmentable Part)\n" - " --hbh-opt-hdr, -H Hop by Hop Options Header\n" - " --link-src-addr, -S Link-layer Destination Address\n" - " --link-dst-addr, -D Link-layer Source Address\n" - " --payload-size, -P UDP Payload Size\n" - " --src-port, -o UDP Source Port (PORT[/LEN])\n" - " --dst-port, -a UDP Destination Port (PORT[/LEN])\n" - " --data, -Z UDP payload data\n" - " --rate-limit, -r Rate limit the address scan to specified rate\n" - " --probe-mode, -p UDP probe mode {dump,script}\n" - " --block-src, -j Block IPv6 Source Address prefix\n" - " --block-dst, -k Block IPv6 Destination Address prefix\n" - " --block-link-src, -J Block Ethernet Source Address\n" - " --block-link-dst, -K Block Ethernet Destination Address\n" - " --accept-src, -b Accept IPv6 Source Address prefix\n" - " --accept-dst, -g Accept IPv6 Destination Address prefix\n" - " --accept-link-src, -B Accept Ethernet Source Address\n" - " --accept-link-dst, -G Accept Ethernet Destination Address\n" - " --flood-sources, -F Flood from multiple IPv6 Source Addresses\n" - " --flood-ports, -T Flood from multiple UDP Source Ports\n" - " --listen, -L Listen to incoming packets\n" - " --loop, -l Send periodic UDP segments\n" - " --sleep, -z Pause between sending UDP segments\n" - " --help, -h Print help for the udp6 tool\n" - " --verbose, -v Be verbose\n" - "\n" - "Programmed by Fernando Gont for SI6 Networks \n" - "Please send any bug reports to \n" - ); +void print_help(void) { + puts(SI6_TOOLKIT); + puts("udp6: Security assessment tool for attack vectors based on UDP/IPv6 packets\n"); + usage(); + + puts("\nOPTIONS:\n" + " --interface, -i Network interface\n" + " --src-addr, -s IPv6 Source Address (ADDRESSS[/LEN])\n" + " --dst-addr, -d IPv6 Destination Address\n" + " --hop-limit, -A IPv6 Hop Limit\n" + " --frag-hdr. -y Fragment Header\n" + " --dst-opt-hdr, -u Destination Options Header (Fragmentable Part)\n" + " --dst-opt-u-hdr, -U Destination Options Header (Unfragmentable Part)\n" + " --hbh-opt-hdr, -H Hop by Hop Options Header\n" + " --link-src-addr, -S Link-layer Destination Address\n" + " --link-dst-addr, -D Link-layer Source Address\n" + " --payload-size, -P UDP Payload Size\n" + " --src-port, -o UDP Source Port (PORT[/LEN])\n" + " --dst-port, -a UDP Destination Port (PORT[/LEN])\n" + " --data, -Z UDP payload data\n" + " --rate-limit, -r Rate limit the address scan to specified rate\n" + " --probe-mode, -p UDP probe mode {dump,script}\n" + " --block-src, -j Block IPv6 Source Address prefix\n" + " --block-dst, -k Block IPv6 Destination Address prefix\n" + " --block-link-src, -J Block Ethernet Source Address\n" + " --block-link-dst, -K Block Ethernet Destination Address\n" + " --accept-src, -b Accept IPv6 Source Address prefix\n" + " --accept-dst, -g Accept IPv6 Destination Address prefix\n" + " --accept-link-src, -B Accept Ethernet Source Address\n" + " --accept-link-dst, -G Accept Ethernet Destination Address\n" + " --flood-sources, -F Flood from multiple IPv6 Source Addresses\n" + " --flood-ports, -T Flood from multiple UDP Source Ports\n" + " --listen, -L Listen to incoming packets\n" + " --loop, -l Send periodic UDP segments\n" + " --sleep, -z Pause between sending UDP segments\n" + " --help, -h Print help for the udp6 tool\n" + " --verbose, -v Be verbose\n" + "\n" + "Programmed by Fernando Gont for SI6 Networks \n" + "Please send any bug reports to \n"); } - /* * Function: print_attack_info() * * Prints attack details (when the verbose ("-v") option is specified). */ - -void print_attack_info(struct iface_data *idata){ - puts(SI6_TOOLKIT); - puts( "udp6: Security assessment tool for attack vectors based on UDP/IPv6 packets\n"); - - if(floods_f && !(loop_f && !sleep_f)) - printf("Flooding the target from %u different IPv6 Source Addresses\n", nsources); - - if(floodp_f && !(loop_f && !sleep_f)) - printf("Flooding the target from %u different UDP ports\n", nports); - - if(idata->type == DLT_EN10MB && !(idata->flags & IFACE_LOOPBACK)){ - if(idata->hsrcaddr_f){ - if(ether_ntop(&(idata->hsrcaddr), plinkaddr, sizeof(plinkaddr)) == 0){ - puts("ether_ntop(): Error converting address"); - exit(EXIT_FAILURE); - } - - printf("Ethernet Source Address: %s\n", plinkaddr); - } - else{ - if(idata->dstaddr_f){ - if(ether_ntop(&(idata->hsrcaddr), plinkaddr, sizeof(plinkaddr)) == 0){ - puts("ether_ntop(): Error converting address"); - exit(EXIT_FAILURE); - } - - printf("Ethernet Source Address: %s%s\n", plinkaddr, ((!(idata->hsrcaddr_f))?" (randomized)":"")); - } - else - puts("Ethernet Source Address: Automatically selected for each packet"); - } - - /* - Ethernet Destination Address only used if a IPv6 Destination Address or an - Ethernet Destination Address were specified. - */ - if(idata->dstaddr_f){ - if(ether_ntop(&(idata->hdstaddr), plinkaddr, sizeof(plinkaddr)) == 0){ - puts("ether_ntop(): Error converting address"); - exit(EXIT_FAILURE); - } - - printf("Ethernet Destination Address: %s\n", plinkaddr); - } - } - - if(!floods_f){ - if(inet_ntop(AF_INET6, &(idata->srcaddr), psrcaddr, sizeof(psrcaddr)) == NULL){ - puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); - exit(EXIT_FAILURE); - } - - if(idata->dstaddr_f){ - printf("IPv6 Source Address: %s%s\n", psrcaddr, ((idata->srcprefix_f)?" (randomized)":"")); - } - } - else{ - - sanitize_ipv6_prefix(&(idata->srcaddr), idata->srcpreflen); - - if(inet_ntop(AF_INET6, &(idata->srcaddr), psrcaddr, sizeof(psrcaddr)) == NULL){ - puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); - exit(EXIT_FAILURE); - } - - printf("IPv6 Source Address: randomized, from the %s/%u prefix%s\n", psrcaddr, idata->srcpreflen, \ - (!idata->srcprefix_f)?" (default)":""); - } - - - if(idata->dstaddr_f){ - if(inet_ntop(AF_INET6, &(idata->dstaddr), pdstaddr, sizeof(pdstaddr)) == NULL){ - puts("inet_ntop(): Error converting IPv6 Destination Address to presentation format"); - exit(EXIT_FAILURE); - } - - printf("IPv6 Destination Address: %s\n", pdstaddr); - } - - printf("IPv6 Hop Limit: %u%s\n", hoplimit, (hoplimit_f)?"":" (default)"); - - for(i=0; ifragh_f) - printf("Sending each packet in fragments of %u bytes (plus the Unfragmentable part)\n", nfrags); - - if(idata->dstaddr_f){ - if(!floodp_f){ - printf("Source Port: %u%s\t", srcport, (srcport_f?"":" (randomized)")); - } - else{ - if(srcportrnd_f){ - sanitize_port(&srcport, srcportpref); - printf("Source Port: (randomized from %u/%u)\t", srcport, srcportpref); - } - else{ - printf("Source Port: (randomized)\t"); - } - } - - if(dstport_f && dstportrnd_f){ - pport= dstport; - sanitize_port(&pport, dstportpref); - printf("Destination Port: (randomized from %u/%u)\n", pport, dstportpref); - } - else{ - printf("Destination Port: %u%s\n", dstport, (dstport_f?"":" (randomized)")); - } - } - else{ - printf("Source Port: Auto\tDestination Port: Auto\n"); - } -} - - +void print_attack_info(struct iface_data *idata) { + puts(SI6_TOOLKIT); + puts("udp6: Security assessment tool for attack vectors based on UDP/IPv6 packets\n"); + + if (floods_f && !(loop_f && !sleep_f)) + printf("Flooding the target from %u different IPv6 Source Addresses\n", nsources); + + if (floodp_f && !(loop_f && !sleep_f)) + printf("Flooding the target from %u different UDP ports\n", nports); + + if (idata->type == DLT_EN10MB && !(idata->flags & IFACE_LOOPBACK)) { + if (idata->hsrcaddr_f) { + if (ether_ntop(&(idata->hsrcaddr), plinkaddr, sizeof(plinkaddr)) == 0) { + puts("ether_ntop(): Error converting address"); + exit(EXIT_FAILURE); + } + + printf("Ethernet Source Address: %s\n", plinkaddr); + } + else { + if (idata->dstaddr_f) { + if (ether_ntop(&(idata->hsrcaddr), plinkaddr, sizeof(plinkaddr)) == 0) { + puts("ether_ntop(): Error converting address"); + exit(EXIT_FAILURE); + } + + printf("Ethernet Source Address: %s%s\n", plinkaddr, ((!(idata->hsrcaddr_f)) ? " (randomized)" : "")); + } + else + puts("Ethernet Source Address: Automatically selected for each packet"); + } + + /* + Ethernet Destination Address only used if a IPv6 Destination Address or an + Ethernet Destination Address were specified. + */ + if (idata->dstaddr_f) { + if (ether_ntop(&(idata->hdstaddr), plinkaddr, sizeof(plinkaddr)) == 0) { + puts("ether_ntop(): Error converting address"); + exit(EXIT_FAILURE); + } + + printf("Ethernet Destination Address: %s\n", plinkaddr); + } + } + + if (!floods_f) { + if (inet_ntop(AF_INET6, &(idata->srcaddr), psrcaddr, sizeof(psrcaddr)) == NULL) { + puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); + exit(EXIT_FAILURE); + } + + if (idata->dstaddr_f) { + printf("IPv6 Source Address: %s%s\n", psrcaddr, ((idata->srcprefix_f) ? " (randomized)" : "")); + } + } + else { + + sanitize_ipv6_prefix(&(idata->srcaddr), idata->srcpreflen); + + if (inet_ntop(AF_INET6, &(idata->srcaddr), psrcaddr, sizeof(psrcaddr)) == NULL) { + puts("inet_ntop(): Error converting IPv6 Source Address to presentation format"); + exit(EXIT_FAILURE); + } + + printf("IPv6 Source Address: randomized, from the %s/%u prefix%s\n", psrcaddr, idata->srcpreflen, + (!idata->srcprefix_f) ? " (default)" : ""); + } + + if (idata->dstaddr_f) { + if (inet_ntop(AF_INET6, &(idata->dstaddr), pdstaddr, sizeof(pdstaddr)) == NULL) { + puts("inet_ntop(): Error converting IPv6 Destination Address to presentation format"); + exit(EXIT_FAILURE); + } + + printf("IPv6 Destination Address: %s\n", pdstaddr); + } + + printf("IPv6 Hop Limit: %u%s\n", hoplimit, (hoplimit_f) ? "" : " (default)"); + + for (i = 0; i < ndstoptuhdr; i++) + printf("Destination Options Header (Unfragmentable part): %u bytes\n", dstoptuhdrlen[i]); + + for (i = 0; i < nhbhopthdr; i++) + printf("Hop by Hop Options Header: %u bytes\n", hbhopthdrlen[i]); + + for (i = 0; i < ndstopthdr; i++) + printf("Destination Options Header: %u bytes\n", dstopthdrlen[i]); + + if (idata->fragh_f) + printf("Sending each packet in fragments of %u bytes (plus the Unfragmentable part)\n", nfrags); + + if (idata->dstaddr_f) { + if (!floodp_f) { + printf("Source Port: %u%s\t", srcport, (srcport_f ? "" : " (randomized)")); + } + else { + if (srcportrnd_f) { + sanitize_port(&srcport, srcportpref); + printf("Source Port: (randomized from %u/%u)\t", srcport, srcportpref); + } + else { + printf("Source Port: (randomized)\t"); + } + } + + if (dstport_f && dstportrnd_f) { + pport = dstport; + sanitize_port(&pport, dstportpref); + printf("Destination Port: (randomized from %u/%u)\n", pport, dstportpref); + } + else { + printf("Destination Port: %u%s\n", dstport, (dstport_f ? "" : " (randomized)")); + } + } + else { + printf("Source Port: Auto\tDestination Port: Auto\n"); + } +} /* * Function: is_valid_udp_datagram() @@ -2028,58 +1999,56 @@ void print_attack_info(struct iface_data *idata){ * Performs sanity checks on an incomming UDP/IPv6 segment */ -int is_valid_udp_datagram(struct iface_data *idata, const u_char *pktdata, struct pcap_pkthdr *pkthdr){ - struct ether_header *pkt_ether; - struct ip6_hdr *pkt_ipv6; - struct udp_hdr *pkt_udp; - unsigned char *pkt_end; - - pkt_ether = (struct ether_header *) pktdata; - pkt_ipv6 = (struct ip6_hdr *)((char *) pkt_ether + idata->linkhsize); - pkt_udp = (struct udp_hdr *) ((char *) pkt_ipv6 + MIN_IPV6_HLEN); - - pkt_end = (unsigned char *) pktdata + pkthdr->caplen; - - /* XXX: We are assuming no extension headers on incoming packets -- this should be improved! */ - - /* The packet length is the minimum of what we capured, and what is specified in the - IPv6 Total Lenght field - */ - if( pkt_end > ((unsigned char *)pkt_udp + ntohs(pkt_ipv6->ip6_plen)) ) - pkt_end = (unsigned char *)pkt_udp + ntohs(pkt_ipv6->ip6_plen); - - /* - Discard the packet if it is not of the minimum size to contain a UDP header - */ - if( (pkt_end - (unsigned char *) pkt_udp) < sizeof(struct udp_hdr)){ - return FALSE; - } - - /* - Discard the packet if it is not of the minimum size to contain a UDP header - */ - if( (pkt_end - (unsigned char *) pkt_udp) < ntohs(pkt_udp->uh_ulen)){ - return FALSE; - } - - /* Check that the UDP checksum is correct */ - if(in_chksum(pkt_ipv6, pkt_udp, pkt_end-((unsigned char *)pkt_udp), IPPROTO_UDP) != 0){ - return FALSE; - } - - - /* XXX: Should perform additional checks on the IPv6 header */ - /* - Sanity checks on the Source Address and the Destination Address - */ - if(IN6_IS_ADDR_UNSPECIFIED(&(pkt_ipv6->ip6_src)) || IN6_IS_ADDR_UNSPECIFIED(&(pkt_ipv6->ip6_dst))){ - return FALSE; - } - - if(IN6_IS_ADDR_MULTICAST(&(pkt_ipv6->ip6_src)) || IN6_IS_ADDR_MULTICAST(&(pkt_ipv6->ip6_dst))){ - return FALSE; - } - - return TRUE; +int is_valid_udp_datagram(struct iface_data *idata, const u_char *pktdata, struct pcap_pkthdr *pkthdr) { + struct ether_header *pkt_ether; + struct ip6_hdr *pkt_ipv6; + struct udp_hdr *pkt_udp; + unsigned char *pkt_end; + + pkt_ether = (struct ether_header *)pktdata; + pkt_ipv6 = (struct ip6_hdr *)((char *)pkt_ether + idata->linkhsize); + pkt_udp = (struct udp_hdr *)((char *)pkt_ipv6 + MIN_IPV6_HLEN); + + pkt_end = (unsigned char *)pktdata + pkthdr->caplen; + + /* XXX: We are assuming no extension headers on incoming packets -- this should be improved! */ + + /* The packet length is the minimum of what we capured, and what is specified in the + IPv6 Total Lenght field + */ + if (pkt_end > ((unsigned char *)pkt_udp + ntohs(pkt_ipv6->ip6_plen))) + pkt_end = (unsigned char *)pkt_udp + ntohs(pkt_ipv6->ip6_plen); + + /* + Discard the packet if it is not of the minimum size to contain a UDP header + */ + if ((pkt_end - (unsigned char *)pkt_udp) < sizeof(struct udp_hdr)) { + return FALSE; + } + + /* + Discard the packet if it is not of the minimum size to contain a UDP header + */ + if ((pkt_end - (unsigned char *)pkt_udp) < ntohs(pkt_udp->uh_ulen)) { + return FALSE; + } + + /* Check that the UDP checksum is correct */ + if (in_chksum(pkt_ipv6, pkt_udp, pkt_end - ((unsigned char *)pkt_udp), IPPROTO_UDP) != 0) { + return FALSE; + } + + /* XXX: Should perform additional checks on the IPv6 header */ + /* + Sanity checks on the Source Address and the Destination Address + */ + if (IN6_IS_ADDR_UNSPECIFIED(&(pkt_ipv6->ip6_src)) || IN6_IS_ADDR_UNSPECIFIED(&(pkt_ipv6->ip6_dst))) { + return FALSE; + } + + if (IN6_IS_ADDR_MULTICAST(&(pkt_ipv6->ip6_src)) || IN6_IS_ADDR_MULTICAST(&(pkt_ipv6->ip6_dst))) { + return FALSE; + } + + return TRUE; } - diff --git a/tools/udp6.h b/tools/udp6.h index 44ec7c1..7a76b2e 100644 --- a/tools/udp6.h +++ b/tools/udp6.h @@ -3,13 +3,11 @@ * */ - /* Constants for debug mode */ -#define PROBE_DUMP 1 -#define PROBE_SCRIPT 2 +#define PROBE_DUMP 1 +#define PROBE_SCRIPT 2 /* Constants for UDP buffers */ -#define UDP_BUFFER_SIZE 65535 -#define UDP_INPUT_BUFFER_SIZE TCP_BUFFER_SIZE -#define UDP_OUTPUT_BUFFER_SIZE TCP_BUFFER_SIZE - +#define UDP_BUFFER_SIZE 65535 +#define UDP_INPUT_BUFFER_SIZE TCP_BUFFER_SIZE +#define UDP_OUTPUT_BUFFER_SIZE TCP_BUFFER_SIZE