/* * 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 && idata.flags != IFACE_LOOPBACK){ ethernet->src = idata.hsrcaddr; ethernet->dst = idata.hdstaddr; ethernet->ether_type = htons(ETHERTYPE_IPV6); } 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= 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); }
void RS_SendDataPack(serial_driver_t *rs, unsigned char *buf, unsigned short size) { unsigned short cs; TMyBuf *packet=bget(1); PRSHeader ch=(PRSHeader)(packet->buf); memset(packet->buf, 0, sizeof(TRSHeader)); packet->len=sizeof(TRSHeader)+size; ch->HeaderTag[0]=THEDID; ch->HeaderTag[1]=THEDID; ch->Cmd=(char)CMD_RS; ch->CmdCheck=0xFF-CMD_RS; ch->Len=size; memcpy(packet->buf+sizeof(TRSHeader), buf, size); ch->CheckSum=in_chksum(packet->buf, packet->len); #ifdef MAIN_PRG if(rs==&st232) { int dd=gOptions.RS232BaudRate/10000; RS485_setmode(TRUE); if(dd>0) dd=4*115200/dd; else dd=4*115200; cs=0; while(cs<packet->len) { rs->write(packet->buf[cs++]); if(cs%256==0) { DelayUS(dd); } } rs->flush_output(); // DelayUS(3000); //for 115200 DelayUS(3000*115200/gOptions.RS232BaudRate); RS485_setmode(FALSE); } else #endif { for(cs=0;cs<packet->len;cs++) rs->write(packet->buf[cs]); rs->flush_output(); } packet->len=0; }
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-address", required_argument, 0, 's'}, {"dst-address", 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 } }; 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-1); 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(1); } 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); } nfrags = (nfrags +7) & 0xfff8; 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 Souce 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){ #else 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 defined(sun) || defined(__sun) || defined(__linux__) if(TRUE){ #else 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); } /* * 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); } #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; } /* * 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){ 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(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 %lu bytes (rather than %lu bytes)\n", (LUI) 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)) fragsize=nfrags; else fragsize= (fptrend-fptr) & IP6F_OFF_MASK; 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 - 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 %lu bytes (rather than %lu bytes)\n"\ , (LUI) 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]"); } /* * 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(); puts("\nOPTIONS:\n" " --interface, -i Network interface\n" " --src-address, -s IPv6 Source Address\n" " --dst-address, -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-address, -S Link-layer Destination Address\n" " --link-dst-address, -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 Addres prefix\n" " --accept-dst, -g Accept IPv6 Destination Addres 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 <http://www.si6networks.com>\n" "Please send any bug reports to <*****@*****.**>\n" ); }
/* * Function: send_packet() * * Initialize the remaining fields of the Router Solicitation Message, and * send the attack apcket(s). */ void send_packet(void) { sources=0; do { if(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 highest-order 16 bits (srcaddr.s6_addr16[1] in our case) are not zero. */ /* Randomize the IPv6 Source address based on the specified prefix and prefix length (defaults to fe80::/64). */ startrand= srcpreflen/16; for(i=0; i<startrand; i++) ipv6->ip6_src.s6_addr16[i]= 0; for(i=startrand; i<8; i++) ipv6->ip6_src.s6_addr16[i]=random(); if(srcpreflen%16) { mask=0xffff; for(i=0; i<(srcpreflen%16); i++) mask= mask>>1; ipv6->ip6_src.s6_addr16[startrand]= ipv6->ip6_src.s6_addr16[startrand] & htons(mask); } for(i=0; i<=(srcpreflen/16); i++) ipv6->ip6_src.s6_addr16[i]= ipv6->ip6_src.s6_addr16[i] | srcaddr.s6_addr16[i]; if(!hsrcaddr_f) { for(i=0; i<6; i++) ethernet->src.a[i]= random(); /* 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) { bcopy(ethernet->src.a, sllaopt->address, 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)<=max_packet_size) { sllaopt = (struct nd_opt_slla *) ptr; sllaopt->type= ND_OPT_SOURCE_LINKADDR; sllaopt->length= SLLA_OPT_LEN; bcopy(linkaddr[linkaddrs].a, sllaopt->address, 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-((char *)rs)); if(!fragh_f) { ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN); if((nw=pcap_inject(pfd, buffer, ptr - buffer)) == -1) { printf("pcap_inject(): %s\n", pcap_geterr(pfd)); exit(1); } if(nw != (ptr-buffer)) { printf("pcap_inject(): only wrote %lu bytes (rather than %lu bytes)\n", (LUI) nw, \ (LUI) (ptr-buffer)); exit(1); } } 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(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)) fragsize=nfrags; else fragsize= (fptrend-fptr) & IP6F_OFF_MASK; 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 - ETHER_HDR_LEN); if((nw=pcap_inject(pfd, fragbuffer, fptr - fragbuffer)) == -1) { printf("pcap_inject(): %s\n", pcap_geterr(pfd)); exit(1); } if(nw != (fptr- fragbuffer)) { printf("pcap_inject(): only wrote %lu bytes (rather than %lu bytes)\n", (LUI) nw,\ (LUI) (ptr-buffer)); exit(1); } } } } while(linkaddrs>nlinkaddr && newdata_f); sources++; } while(sources<nsources);
/* * 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 && idata->flags != IFACE_LOOPBACK){ ethernet->src = idata->hsrcaddr; ethernet->dst = idata->hdstaddr; ethernet->ether_type = htons(ETHERTYPE_IPV6); } 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; 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= (u_int32_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++){ *(u_int32_t *)ptr = random(); ptr += sizeof(u_int32_t); } icmp6->icmp6_cksum = in_chksum(v6buffer, icmp6, ptr-((unsigned char *)icmp6), IPPROTO_ICMPV6); startofprefixes=ptr; }
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 + 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) + \ 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 + 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) + \ + 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; }
/* * Function: send_packet() * * 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(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 %lu bytes (rather than %lu bytes)\n", (LUI) 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)) fragsize=nfrags; else fragsize= (fptrend-fptr) & IP6F_OFF_MASK; 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 - 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 %lu bytes (rather than %lu bytes)\n", (LUI) nw, \ (LUI) (ptr-buffer)); exit(EXIT_FAILURE); } } } }while(linkaddrs<nlinkaddr && newdata_f); targets++; }while(targets<ntargets); sources++; }while(sources<nsources); }
int tcp_input(struct ifnet * __if, struct iphdr * iph, struct tcphdr * th, int len) { struct tcp_listen_pcb * mux; struct tcp_pcb * tp; #if (ENABLE_NET_TCP_CHECKSUM) unsigned int sum; #endif int ti_len; int acked = 0; int ourfinisacked = 0; int needoutput = 0; unsigned int optlen; int tiflags; int todrop; uint32_t snd_una; uint32_t snd_nxt; uint32_t snd_max; uint32_t ti_seq; uint32_t ti_ack; int rcv_wnd; int tiwin; int hdrlen; uint8_t * data; int ret; #if (ENABLE_TCPDUMP) tcp_dump(iph, th, TCPDUMP_RX); #endif /* get TCP options, if any */ optlen = ((th->th_off << 2) - sizeof(struct tcphdr)); hdrlen = sizeof(struct tcphdr) + optlen; data = (uint8_t *)&th->th_opt[optlen]; ti_len = len - hdrlen; #if (ENABLE_NET_TCP_CHECKSUM) /* initialize checksum */ sum = htons(len) + (IPPROTO_TCP << 8); sum = in_chksum(sum, &iph->saddr, 8); sum = in_chksum(sum, th, hdrlen); if (ti_len) { sum = in_chksum(sum, data, ti_len); } if (sum != 0x0000ffff) { DCC_LOG3(LOG_WARNING, "checksum error: 0x%04x hdrlen=%d, len=%d", sum, hdrlen, len); TCP_PROTO_STAT_ADD(rx_err, 1); goto drop; } #endif tiflags = th->th_flags; /* convert TCP protocol specific fields to host format */ tiwin = ntohs(th->th_win); ti_seq = ntohl(th->th_seq); ti_ack = ntohl(th->th_ack); TCP_PROTO_STAT_ADD(rx_ok, 1); /* Serch in active list first */ if ((tp = tcp_active_lookup(iph->saddr, th->th_sport, iph->daddr, th->th_dport)) == NULL) { /* lookup into listening pcb list */ if ((mux = tcp_listen_lookup(iph->saddr, th->th_sport, iph->daddr, th->th_dport)) == NULL) { DCC_LOG(LOG_WARNING, "invalid peer ???"); goto dropwithreset; } if ((tiflags & TH_ACK)) { DCC_LOG(LOG_WARNING, "listen ACK ?"); goto dropwithreset; } if (ti_len != 0) { DCC_LOG(LOG_WARNING, "ti_len != 0"); goto dropwithreset; } /* Completion of Passive Open Ref.: TCP/IP Illustrated Volume 2, pg. 942 */ if (!(tiflags & TH_SYN)) { DCC_LOG(LOG_WARNING, "listen !SYN ?"); goto drop; } /* In the LISTEN state, we check for incoming SYN segments, creates a new PCB, and responds with a SYN|ACK. */ if ((tiflags & TH_RST)) { DCC_LOG(LOG_WARNING, "listen RST?"); goto drop; } if ((tp = tcp_passive_open(mux, iph, th, optlen)) == NULL) { DCC_LOG(LOG_WARNING, "tcp_passive_open()"); goto dropwithreset; } /* schedule output */ tcp_output_sched(tp); /* packet handled */ return 0; } DCC_LOG1(LOG_MSG, "<%05x> active", (int)tp); snd_una = tp->snd_seq; snd_nxt = tp->snd_seq + tp->snd_off; snd_max = tp->snd_seq + tp->snd_max; /* Remove acknowledged bytes from the send buffer */ /* Wakeup processes waiting on send buffer */ /* Segment received on a connection. Reset the idle detection timer Ref.: TCP/IP Illustrated Volume 2, pg. 932 */ tp->t_conn_tmr = tcp_idle_det_tmo; if (tp->t_flags & TF_IDLE) { /* exits from the idle state */ tp->t_flags &= ~TF_IDLE; DCC_LOG1(LOG_INFO, "<%05x> IDLE exit", (int)tp); } #if 0 /* Process options, we don't need to check if the socket is in the LISTEN state, because only active (non LISTENING) sockets will actually fall into this code. XXX: options after connection stablished ??? */ if (optlen) tcp_parse_options(tp, th, th->th_opt, optlen); #endif /* Ref.: TCP/IP Illustrated Volume 2, pg. 934 */ #if (TCP_ENABLE_HEADER_PREDICTION) if ((tp->t_state == TCPS_ESTABLISHED) && (tiflags & (TH_SYN | TH_FIN | TH_RST | TH_URG | TH_ACK)) == TH_ACK && (ti_seq == tp->rcv_nxt) && (tiwin) && (tiwin == tp->snd_wnd) && (snd_nxt == snd_max)) { if (ti_len == 0) { if (SEQ_GT(ti_ack, snd_una) && SEQ_LEQ(ti_ack, snd_max)) { acked = ti_ack - snd_una; DCC_LOG(LOG_INFO, "header prediction, ACK ..."); mbuf_queue_trim(&tp->snd_q, acked); snd_una = ti_ack; tp->snd_seq = snd_una; tp->snd_off = snd_nxt - tp->snd_seq; tp->snd_max = snd_max - tp->snd_seq; if (snd_una == snd_max) { tp->t_rxmt_tmr = 0; tp->t_rxmt_cnt = 0; DCC_LOG(LOG_INFO, "acked all data, rxmt tmr stopped"); } else { if (tp->t_rxmt_tmr == 0) { DCC_LOG(LOG_INFO, "not all data acked restart rxmt tmr"); tp->t_rxmt_tmr = tcp_rxmtintvl[tp->t_rxmt_cnt / 2]; } } thinkos_cond_broadcast(tp->t_cond); if (tp->snd_q.len) { /* schedule output */ tcp_output_sched(tp); } return 0; } } else { if ((ti_ack == snd_una) && ti_len <= (tcp_maxrcv - tp->rcv_q.len)) { int len; DCC_LOG1(LOG_INFO, "header prediction, data (%d)", ti_len); /* append data */ len = mbuf_queue_add(&tp->rcv_q, data, ti_len); tp->rcv_nxt += len; thinkos_cond_broadcast(tp->t_cond); if (len != ti_len) { DCC_LOG1(LOG_WARNING, "<%05x> no more mbufs", (int)tp); tp->t_flags |= TF_ACKNOW; /* schedule output */ tcp_output_sched(tp); } else { tp->t_flags |= TF_DELACK; } return 0; } } } #endif /* TCP_ENABLE_HEADER_PREDICTION */ /* Slow path input processing Ref.: TCP/IP Illustrated Volume 2, pg. 941 */ /* TODO: Drop TCP, IP headers and TCP options. Well, only if these structures were dynamic allocated... */ if (ti_len == 0) { DCC_LOG(LOG_INFO, "slow path ACK"); } else { DCC_LOG1(LOG_INFO, "slow path (%d)", ti_len); } /* Calculate the amount of space in receive window, and then do TCP input processing. Receive window is amount of space in rcv queue, but not less than advertise window. Ref.: TCP/IP Illustrated Volume 2, pg. 941 */ { int win; /* space left in the input queue */ win = tcp_maxrcv - tp->rcv_q.len; if (win <= 0) { win = 0; DCC_LOG(LOG_INFO, "receive buffer full!"); } // rcv_wnd = MAX(win, tp->rcv_adv_wnd); rcv_wnd = win; DCC_LOG3(LOG_INFO, "adv_wnd=%d rcv_wnd=%d win=%d", tp->rcv_adv_wnd, rcv_wnd, win); } if (tp->t_state == TCPS_SYN_SENT) { /* response to an active open. Ref.: TCP/IP Illustrated Volume 2, pg. 947 */ /* Common proccessing for receipt of SYN. Ref.: TCP/IP Illustrated Volume 2, pg. 950 */ if ((tiflags & TH_RST)) { goto close; } if (!(tiflags & TH_SYN)) { DCC_LOG(LOG_WARNING, "SYN_SENT SYN ?"); /* TODO: reset */ goto close_and_reset; } if (!(tiflags & TH_ACK)) { DCC_LOG(LOG_WARNING, "SYN_SENT ACK ?"); /* TODO: reset */ goto close_and_reset; } if (ti_len != 0) { DCC_LOG(LOG_WARNING, "ti_len != 0"); /* TODO: reset */ goto close_and_reset; } /* update the send sequence */ tp->snd_seq++; if (tp->snd_seq != ti_ack) { DCC_LOG3(LOG_WARNING, "<%05x> tp->snd_seq(%d) != ti_ack(%d)", (int)tp, tp->snd_seq, ti_ack); /* TODO: reset */ goto close_and_reset; } tp->snd_off--; tp->snd_max--; // tp->snd_off = 0; // tp->snd_max = 0; if (optlen) tcp_parse_options(tp, th, th->th_opt, optlen); /* Advance tp->ti_seq to correspond to first data byte. */ ti_seq++; if (ti_len > rcv_wnd) { DCC_LOG3(LOG_WARNING, "<%05x> ti_len(%d) > rcv_wnd(%d)", (int)tp, ti_len, rcv_wnd); /* TODO: if data, trim to stay within window. */ ti_len = rcv_wnd; } /* update the sequence number */ tp->rcv_nxt = ti_seq; /* update the window size */ tp->snd_wnd = ntohs(th->th_win); tp->t_state = TCPS_ESTABLISHED; DCC_LOG1(LOG_INFO, "<%05x> [ESTABLISHED]", (int)tp); /* TODO: initialization of receive urgent pointer tcp->rcv_up = ti_seq; */ /* XXX: */ tp->t_flags |= TF_ACKNOW; thinkos_cond_broadcast(tp->t_cond); goto step6; close_and_reset: tp->t_state = TCPS_CLOSED; pcb_move((struct pcb *)tp, &__tcp__.active, &__tcp__.closed); DCC_LOG1(LOG_INFO, "<%05x> [CLOSED]", (int)tp); /* XXX: discard the data */ mbuf_queue_free(&tp->snd_q); mbuf_queue_free(&tp->rcv_q); /* notify the upper layer */ thinkos_cond_broadcast(tp->t_cond); goto dropwithreset; } /* States other than LISTEN or SYN_SENT First check timestamp, if present. Then check that at least some bytes of segment are within receive window. If segment begins before rcv_nxt, drop leading data (and SYN); if nothing left, just ti_ack. */ /* Trim Segment so Data is Within Window Ref.: TCP/IP Illustrated Volume 2, pg. 954 */ todrop = tp->rcv_nxt - ti_seq; if (todrop > 0) { if (tiflags & TH_SYN) { DCC_LOG(LOG_INFO, "SYN"); tiflags &= ~TH_SYN; ti_seq++; todrop--; } if ((todrop > ti_len) || ((todrop == ti_len) && ((tiflags & TH_FIN) == 0))) { tiflags &= ~TH_FIN; tp->t_flags |= TF_ACKNOW; todrop = ti_len; } DCC_LOG4(LOG_WARNING, "<%05x> drop: len=%d drop=%d rem=%d!", (int)tp, ti_len, todrop, ti_len - todrop); /* adjust the data pointer */ data += todrop; ti_seq += todrop; ti_len -= todrop; /* TODO: adjust the urgent pointer */ } /* FIXME: only reset the connection if there are no more application to handle the incomming data, half-close */ if ((tp->t_state > TCPS_FIN_WAIT_1) && (ti_len)) { DCC_LOG1(LOG_INFO, "<%05x> segment received after FIN", (int)tp); /* TODO: stat */ goto dropwithreset; } /* If segment ends after window, drop trailing data and (PUSH and FIN); if nothing left, just ACK. Ref.: TCP/IP Illustrated Volume 2, pg. 958 */ todrop = (ti_seq + ti_len) - (tp->rcv_nxt + rcv_wnd); DCC_LOG4(LOG_INFO, "ti_seq=%u ti_len=%d rcv_nxt=%u rcv_wnd=%d", ti_seq, ti_len, tp->rcv_nxt, rcv_wnd); /* */ if (todrop > 0) { // TCP_LOG(tp, "tcp_input: trailing data drop"); if (todrop >= ti_len) { /* * If a new connection request is received * while in TIME_WAIT, drop the old connection ... * Ref.: TCP/IP Illustrated Volume 2, pg. 958 if ((tiflags & TH_SYN) && (tp->t_state == TCPS_TIMEWAIT) && (SEQ_GT(ti_seq, tp->rcv_nxt))) { __tcp__.iss += tcp_issincr; tcp_rst(tp); goto findpcb; } */ if ((rcv_wnd == 0) && (ti_seq == tp->rcv_nxt)) { tp->t_flags |= TF_ACKNOW; } else goto dropafterack; } DCC_LOG2(LOG_WARNING, "<%05x> data drop: %d!", (int)tp, todrop); ti_len -= todrop; tiflags &= ~(TH_PSH | TH_FIN); } /* If the RST bit is set eximine the state: ... Ref.: TCP/IP Illustrated Volume 2, pg. 964 */ if ((tiflags & TH_RST)) { DCC_LOG1(LOG_WARNING, "<%05x> RST received", (int)tp); switch(tp->t_state) { case TCPS_SYN_RCVD: // tp->errno = ECONNREFUSED; goto close; case TCPS_ESTABLISHED: case TCPS_CLOSE_WAIT: // tp->errno = ECONNRESET; close: /* discard the data */ mbuf_queue_free(&tp->snd_q); mbuf_queue_free(&tp->rcv_q); tp->t_state = TCPS_CLOSED; pcb_move((struct pcb *)tp, &__tcp__.active, &__tcp__.closed); DCC_LOG1(LOG_INFO, "<%05x> [CLOSED]", (int)tp); /* notify the upper layer */ thinkos_cond_broadcast(tp->t_cond); /* PCBs in the close state should be cleared by the application */ goto drop; case TCPS_FIN_WAIT_1: case TCPS_FIN_WAIT_2: case TCPS_CLOSING: case TCPS_LAST_ACK: case TCPS_TIME_WAIT: /* Our side was already closed */ tcp_pcb_free(tp); goto drop; } } /* If a SYN is in the window, then this is an error and we send an RST and drop the connection. Ref.: TCP/IP Illustrated Volume 2, pg. 965 */ if ((tiflags & TH_SYN)) { DCC_LOG1(LOG_WARNING, "<%05x> the SYN bit is set inside the window", (int)tp); goto dropwithreset; } /* If the ACK bit is off we drop the segment and return. */ if ((!(tiflags & TH_ACK))) { DCC_LOG1(LOG_WARNING, "<%05x> the ACK bit is off", (int)tp); goto drop; } /* * ACK processing. * Ref.: TCP/IP Illustrated Volume 2, pg. 969 * */ DCC_LOG4(LOG_INFO, "ack=%u una=%u nxt=%u max=%u", ti_ack, snd_una, snd_nxt, snd_max); switch(tp->t_state) { case TCPS_SYN_RCVD: if (SEQ_GT(snd_una, ti_ack) || SEQ_GT(ti_ack, snd_max)) { DCC_LOG1(LOG_WARNING, "<%05x> ti_ack < snd_una || snd_max < ti_ack", (int)tp); goto dropwithreset; } tp->t_state = TCPS_ESTABLISHED; tp->snd_off--; tp->snd_max--; DCC_LOG1(LOG_INFO, "<%05x> SYN ackd [ESTABLISHED]", (int)tp); /* notify the upper layer*/ // thinkos_cond_signal(tp->t_cond); /* TODO: tcp reassembly tcp_reass(tp); */ case TCPS_ESTABLISHED: case TCPS_FIN_WAIT_1: case TCPS_FIN_WAIT_2: case TCPS_CLOSE_WAIT: case TCPS_CLOSING: case TCPS_LAST_ACK: case TCPS_TIME_WAIT: /* TODO: tcp reassembly tcp_reass(tp); */ if (SEQ_LEQ(ti_ack, snd_una)) { /* TODO: check for completly duplicated ACKs. Ref.: TCP/IP Illustrated Volume 2, pg. 971 */ if ((ti_len == 0) && (tiwin == tp->snd_wnd)) { if ((tp->t_rxmt_tmr == 0) || ti_ack != snd_una) { // dupacks = 0; } else { DCC_LOG2(LOG_INFO, "duplicated ACK. ti_ack=%u snd_una=%u", ti_ack, snd_una); } } else { // dupacks = 0; } break; } /* Check out of range ACK */ /* Ref.: TCP/IP Illustrated Volume 2, pg. 974 */ if (SEQ_GT(ti_ack, snd_max)) { /* TODO: tcpstat.tcps_rcvacktoomuch++; */ DCC_LOG3(LOG_WARNING, "(%04x) out of range ACK. " "th_ack=%u > snd_max=%u !", (int)tp, ti_ack, snd_max); goto dropafterack; } acked = ti_ack - snd_una; /* TODO: tcpstat.tcps_rcvackpack++; tcpstat.tcps_rcvackbyte += acked; */ DCC_LOG1(LOG_INFO, "acked=%d", acked); /* If all outstanding data is acked, stop retransmit timer else restarts it .... Ref.: TCP/IP Illustrated Volume 2, pg. 976 */ if (ti_ack == snd_max) { tp->t_rxmt_tmr = 0; tp->t_rxmt_cnt = 0; needoutput = 1; DCC_LOG(LOG_INFO, "acked all data, rxmt tmr stopped"); } else { /* TODO: peristent timer */ // if (tp->t_persist_tmr == 0) { DCC_LOG(LOG_INFO, "not all data acked restart rxmt tmr"); tp->t_rxmt_tmr = tcp_rxmtintvl[tp->t_rxmt_cnt / 2]; // } } /* TODO: tcpstat.tcps_rcvackpack++; tcpstat.tcps_rcvackbyte += acked; */ /* TODO: remove acknowledged data from send buffer Ref.: TCP/IP Illustrated Volume 2, pg. 978 */ /* FIXME: send buffer bytes count */ if (acked > tp->snd_q.len) { mbuf_queue_trim(&tp->snd_q, tp->snd_q.len); ourfinisacked = 1; } else { /* TODO: estimate the send window */ mbuf_queue_trim(&tp->snd_q, acked); ourfinisacked = 0; } /* awaken a thread waiting on the send buffer ... */ thinkos_cond_broadcast(tp->t_cond); snd_una = ti_ack; if (SEQ_LT(snd_nxt, snd_una)) { snd_nxt = snd_una; } tp->snd_seq = snd_una; tp->snd_off = snd_nxt - tp->snd_seq; tp->snd_max = snd_max - tp->snd_seq; DCC_LOG4(LOG_INFO, "<%05x> snd_seq=%u snd_max=%u snd_q.len=%d", (int)tp, tp->snd_seq, snd_max, tp->snd_q.len); switch(tp->t_state) { case TCPS_FIN_WAIT_1: if (ourfinisacked) { /* FIXME: If we can't receive any more data.. Ref.: TCP/IP Illustrated Volume 2, pg. 979 */ tp->t_conn_tmr = 4 * tcp_msl; tp->t_state = TCPS_FIN_WAIT_2; DCC_LOG1(LOG_INFO, "<%05x> [FIN_WAIT_2]", (int)tp); } break; case TCPS_CLOSING: if (ourfinisacked) { mbuf_queue_free(&tp->snd_q); mbuf_queue_free(&tp->rcv_q); tp->t_state = TCPS_TIME_WAIT; DCC_LOG1(LOG_INFO, "<%05x> [TIME_WAIT]", (int)tp); tp->t_rxmt_tmr = 0; tp->t_conn_tmr = 2 * tcp_msl; DCC_LOG1(LOG_INFO, "stop rxmt tmr, start 2MSL tmr: %d", tp->t_conn_tmr); } break; case TCPS_LAST_ACK: if (ourfinisacked) { tcp_pcb_free(tp); goto drop; } break; case TCPS_TIME_WAIT: /* restart the finack timer Ref.: TCP/IP Illustrated Volume 2, pg. 981 */ tp->t_conn_tmr = 2 * tcp_msl; goto dropafterack; } break; } DCC_LOG4(LOG_INFO, "<%05x> recvd=%d acked=%d rcv_q.len=%d", (int)tp, ti_len, acked, tp->rcv_q.len); step6: /* Update window information Ref.: TCP/IP Illustrated Volume 2, pg. 982 */ DCC_LOG(LOG_MSG, "setp6"); // if ((tiflags & TH_ACK) && (tiwin > tp->snd_wnd)) { if ((tiflags & TH_ACK) && (tiwin != tp->snd_wnd)) { /* Keep track of pure window updates */ /* TODO: TCP Statistics */ /* TODO: Update window information */ DCC_LOG1(LOG_INFO, "window update, win=%d", tiwin); tp->snd_wnd = tiwin; needoutput = 1; } /* TODO: Urgent mode processing */ /* Process the segment text, merging it into the TCP sequencing queue, dodata: ... Ref.: TCP/IP Illustrated Volume 2, pg. 988 */ if ((ti_len || (tiflags & TH_FIN)) && TCPS_HAVERCVDFIN(tp->t_state) == 0) { if ((ti_seq == tp->rcv_nxt) && (tp->t_state == TCPS_ESTABLISHED)) { /* append data */ int n; tp->t_flags |= TF_DELACK; n = mbuf_queue_add(&tp->rcv_q, data, ti_len); if (n != ti_len) { DCC_LOG2(LOG_WARNING, "no more mbufs, %d != %d", n, ti_len); } ti_len = n; tp->rcv_nxt += ti_len; /* TODO: statistics */ tiflags &= TH_FIN; // if (tp->rcv_q.len == ti_len) { // DCC_LOG3(LOG_INFO, "<%05x> rcvd %d, signaling %d ...", // (int)tp, ti_len, tp->t_cond); /* * notify the upper layer of the data arrival... */ thinkos_cond_signal(tp->t_cond); // } else { // DCC_LOG2(LOG_INFO, "<%05x> rcvd %d", (int)tp, ti_len); // } } else { /* TODO: half-close */ /* TODO: reassembly */ // m = mlink_free(m); if (tp->t_state == TCPS_ESTABLISHED) { // DCC_LOG(LOG_WARNING, "out of order, drop!"); DCC_LOG(LOG_WARNING, "out of order, drop"); TCP_PROTO_STAT_ADD(rx_drop, 1); } tp->t_flags |= TF_ACKNOW; } } else { DCC_LOG(LOG_INFO, "!!!!!!!!!"); tiflags &= ~TH_FIN; } /* FIN Processing */ if (tiflags & TH_FIN) { if (TCPS_HAVERCVDFIN(tp->t_state) == 0) { tp->t_flags |= TF_ACKNOW; tp->rcv_nxt++; } switch(tp->t_state) { case TCPS_SYN_RCVD: case TCPS_ESTABLISHED: tp->t_state = TCPS_CLOSE_WAIT; DCC_LOG1(LOG_INFO, "<%05x> [CLOSE_WAIT]", (int)tp); /* notify the application that our peer has closed its side. Sockets: marks the socket as write-only */ if (tp->rcv_q.len == 0) { thinkos_cond_broadcast(tp->t_cond); } break; case TCPS_FIN_WAIT_1: tp->t_state = TCPS_CLOSING; DCC_LOG1(LOG_INFO, "<%05x> [CLOSING]", (int)tp); break; case TCPS_FIN_WAIT_2: mbuf_queue_free(&tp->rcv_q); mbuf_queue_free(&tp->snd_q); tp->t_state = TCPS_TIME_WAIT; DCC_LOG1(LOG_INFO, "<%05x> [TIME_WAIT]", (int)tp); tp->t_rxmt_tmr = 0; tp->t_conn_tmr = 2 * tcp_msl; DCC_LOG1(LOG_INFO, "stop rxmt tmr, start 2MSL tmr: %d", tp->t_conn_tmr); break; case TCPS_TIME_WAIT: /* restart the counter */ tp->t_conn_tmr = 2 * tcp_msl; break; } } /* Final Processing */ if (needoutput || (tp->t_flags & TF_ACKNOW)) { if (needoutput) { DCC_LOG(LOG_INFO, "needoutput, call tcp_out."); } if (tp->t_flags & TF_ACKNOW) { DCC_LOG(LOG_INFO, "ACKNOW set, call tcp_out."); } /* schedule output */ tcp_output_sched(tp); } return 0; dropafterack: DCC_LOG1(LOG_INFO, "<%05x> drop and ACK", (int)tp); if (tiflags & TH_RST) goto drop; tp->t_flags |= TF_ACKNOW; /* schedule output */ tcp_output_sched(tp); return 0; dropwithreset: DCC_LOG1(LOG_TRACE, "<%05x> drop and RST", (int)tp); ret = 0; /* TODO: check for a broadcast/multicast */ if (!(tiflags & TH_RST)) { if (tiflags & TH_ACK) { ret = tcp_respond(iph, th, 0, ti_ack, TH_RST); } else if (tiflags & TH_SYN) { ti_len++; ret = tcp_respond(iph, th, ti_seq + ti_len, 0, TH_ACK | TH_RST); } } TCP_PROTO_STAT_ADD(rx_drop, 1); return ret; drop: DCC_LOG(LOG_TRACE, "drop"); TCP_PROTO_STAT_ADD(rx_drop, 1); return 0; }
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; /* Arrays for storing the Flow ID samples */ u_int32_t test1[NSAMPLES], test2[NSAMPLES]; unsigned int ntest1=0, ntest2=0; unsigned char testtype; static struct option longopts[] = { {"interface", required_argument, 0, 'i'}, {"src-address", required_argument, 0, 's'}, {"dst-address", 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'} }; 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-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 */ 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 '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 Souce 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= ((u_int16_t) random() + 1500) & (u_int16_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_addr16[5]= addr_sig; idata.srcaddr.s6_addr16[7] = idata.srcaddr.s6_addr16[6] ^ 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; timeout.tv_usec=0; timeout.tv_sec= 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(sel == 0) continue; /* 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 == 0){ continue; /* Should never happen */ } 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(pkt_ns->nd_ns_target.s6_addr16[5] != addr_sig || \ pkt_ns->nd_ns_target.s6_addr16[7] != (pkt_ns->nd_ns_target.s6_addr16[6] ^ 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(pkt_ipv6->ip6_dst.s6_addr16[5] != addr_sig || \ pkt_ipv6->ip6_dst.s6_addr16[7] != (pkt_ipv6->ip6_dst.s6_addr16[6] ^ 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); }
int udp_sendto(struct udp_pcb * __up, void * __buf, int __len, const struct sockaddr_in * __sin) { struct iphdr * ip; struct udphdr * uh; in_addr_t daddr; int dport; in_addr_t saddr; struct route * rt; #if (ENABLE_NET_UDP_CHECKSUM) unsigned int sum; #endif uint8_t * ptr; int mtu; struct ifnet * ifn; int ret; int retry = 0; DCC_LOG2(LOG_INFO, "<%05x> len=%d", (int)__up, __len); if (__up == NULL) { DCC_LOG1(LOG_WARNING, "<%05x> invalid pcb", (int)__up); return -EFAULT; } if (__buf == NULL) { DCC_LOG1(LOG_WARNING, "<%05x> invalid buffer", (int)__up); return -EFAULT; } tcpip_net_lock(); #if (ENABLE_NET_SANITY_CHECK) if (pcb_find((struct pcb *)__up, &__udp__.pcb) < 0) { DCC_LOG1(LOG_ERROR, "<%05x> pcb_find()", (int)__up); tcpip_net_unlock(); /* TODO: errno */ return -1; } #endif if ((__up->u_lport) == 0) { DCC_LOG1(LOG_WARNING, "<%05x> not bound", (int)__up); tcpip_net_unlock(); /* TODO: errno */ return -3; } if (__sin == NULL) { if ((dport = __up->u_fport) == 0) { DCC_LOG1(LOG_WARNING, "<%05x> connection refused", (int)__up); tcpip_net_unlock(); return -ECONNREFUSED; } if ((daddr = __up->u_faddr) == INADDR_ANY) { DCC_LOG1(LOG_WARNING, "<%05x> not connected", (int)__up); tcpip_net_unlock(); return -ENOTCONN; } } else { if ((dport = __sin->sin_port) == 0) { DCC_LOG1(LOG_WARNING, "<%05x> invalid port", (int)__up); tcpip_net_unlock(); return -ECONNREFUSED; } if ((daddr = __sin->sin_addr.s_addr) == INADDR_ANY) { DCC_LOG1(LOG_WARNING, "<%05x> invalid address", (int)__up); tcpip_net_unlock(); return -EDESTADDRREQ; } } if ((rt = __route_lookup(daddr)) == NULL) { DCC_LOG2(LOG_WARNING, "<%05x> no route to host: %I", (int)__up, daddr); tcpip_net_unlock(); UDP_PROTO_STAT_ADD(tx_drop, 1); UDP_PROTO_STAT_ADD(tx_err, 1); return -EHOSTUNREACH; } ifn = (struct ifnet *)rt->rt_ifn; mtu = ifn->if_mtu - sizeof(struct iphdr); if ((__len <= 0) || (__len > mtu)) { DCC_LOG3(LOG_WARNING, "<%04x> invalid length %d (max: %d)", (int)__up, __len, mtu); tcpip_net_unlock(); /* TODO: errno */ return -7; } /* get the source address */ if ((saddr = __up->u_laddr) == INADDR_ANY) { saddr = ifn->if_ipv4_addr; } again: ip = (struct iphdr *)ifn_mmap(ifn, sizeof(struct iphdr) + sizeof(struct udphdr) + __len); if (ip == NULL) { DCC_LOG1(LOG_WARNING, "<%04x> ifn_mmap() fail", (int)__up); tcpip_net_unlock(); /* TODO: errno */ return -1; } DCC_LOG2(LOG_TRACE, "<%05x> ip=%p", (int)__up, ip); iph_template(ip, IPPROTO_UDP, udp_def_ttl, udp_def_tos); uh = (struct udphdr *)ip->opt; /* build the ip header */ ip = mk_iphdr(ip, saddr, daddr, sizeof(struct udphdr) + __len); /* fill the udp header fields */ uh = (struct udphdr *)ip->opt; uh->dport = dport; uh->sport = __up->u_lport; uh->len = htons(__len + sizeof(struct udphdr)); #if (ENABLE_NET_UDP_CHECKSUM) /* initialize the udp checksum */ sum = uh->len << 1; sum += uh->dport; sum += uh->sport; sum += (IPPROTO_UDP << 8); sum += ((uint16_t *)(void *)&(ip->saddr))[0] + ((uint16_t *)(void *)&(ip->saddr))[1]; sum += ((uint16_t *)(void *)&(ip->daddr))[0] + ((uint16_t *)(void *)&(ip->daddr))[1]; #endif ptr = (uint8_t *)uh + sizeof(struct udphdr); memcpy(ptr, __buf, __len); #if (ENABLE_NET_UDP_CHECKSUM) if (__len) { sum = in_chksum(sum, ptr, __len); } uh->chksum = ~sum; #else uh->chksum = 0; #endif #if 0 DCC_LOG(LOG_INFO, "IP %d.%d.%d.%d:%d > %d.%d.%d.%d:%d: %d", IP4_ADDR1(ip->saddr), IP4_ADDR2(ip->saddr), IP4_ADDR3(ip->saddr), IP4_ADDR4(ip->saddr), ntohs(uh->sport), IP4_ADDR1(ip->daddr), IP4_ADDR2(ip->daddr), IP4_ADDR3(ip->daddr), IP4_ADDR4(ip->daddr), ntohs(uh->dport), ntohs(uh->len)); #endif if ((ret = ip_output(ifn, rt, ip)) < 0) { ifn_munmap(ifn, ip); /* if the reason to fail was an arp failure try query an address pending for resolution ... */ if ((ret == -EAGAIN) && (retry < 10)) { etharp_query_pending(); tcpip_net_unlock(); DCC_LOG2(LOG_WARNING, "<%05x> again, retry=%d!", (int)__up, retry); thinkos_sleep(10 + retry * 10); retry++; tcpip_net_lock(); goto again; } DCC_LOG1(LOG_ERROR, "<%05x> ip_output() fail!", (int)__up); UDP_PROTO_STAT_ADD(tx_drop, 1); } else { UDP_PROTO_STAT_ADD(tx_ok, 1); DCC_LOG5(LOG_INFO, "IP %I:%d > %I:%d: %d", ip->saddr, ntohs(uh->sport), ip->daddr, ntohs(uh->dport), ntohs(uh->len)); #if (LOG_LEVEL < LOG_INFO) DCC_LOG(LOG_INFO, "sent."); #endif ret = __len; } tcpip_net_unlock(); return ret; }
int RS232Check(serial_driver_t *rs) { int i, j; U32 ch,sum; TMyBuf *packet; PRSHeader pch; if(rs->poll()==0) return 0; i=0;sum=0; packet=bget(0); pch=(PRSHeader)(packet->buf); rsc++; while(1) { j=200; while(rs->poll()==0) { DelayUS(2000); if(++j>=220) { if(i>8) //FIFO溢出,要求重发 { PCmdHeader chdr=(PCmdHeader)(packet->buf+sizeof(TRSHeader)); PCommSession session=GetSession(chdr->SessionID); if(session) { chdr->Command=CMD_ACK_RETRY; chdr->CheckSum=0; chdr->CheckSum=in_chksum((BYTE*)chdr,sizeof(TCmdHeader)); session->Send((char *)chdr,sizeof(TCmdHeader),session->Sender); PS1[PSIndex]=i; PS2[PSIndex++]=rsc; PSIndex &= 0xFF; j=0; //等待重发 i=0; sum=0; continue; } } // ExBeep(5); return -1; } } ch=rs->read(); packet->buf[i]=ch; if(i<=1) { #ifdef MAIN_PRG if(rs==&st232 && (ch!=(U32)THEDID)) break; #endif } else if(i==3) { if(pch->Cmd+pch->CmdCheck!=0xFF) break; if(pch->Cmd!=CMD_RS) break; } else if(i==sizeof(TRSHeader)-1) { if(pch->Len>BUFSZ-sizeof(TRSHeader)) break; } else if(i==(int)(pch->Len+sizeof(TRSHeader)-1)) { sum=pch->CheckSum; pch->CheckSum=0; if(sum==in_chksum(packet->buf, pch->Len+sizeof(TRSHeader))) { PCommSession session; int cmd=RunCommand(packet->buf+sizeof(TRSHeader), pch->Len); if(cmd==0) return -2; if(cmd==CMD_CONNECT) { char Sender[SENDER_LEN]; PCmdHeader chdr=(PCmdHeader)(packet->buf+sizeof(TRSHeader)); memset(Sender, 0, SENDER_LEN); memcpy(Sender, (void*)&rs, sizeof(rs)); session=CreateSession(Sender); chdr->SessionID=session->SessionID; chdr->CheckSum=0; chdr->CheckSum=in_chksum((void*)chdr,sizeof(TCmdHeader)); session->Send=SendRSData; session->Speed=THEBR; SendRSData((void*)chdr, sizeof(TCmdHeader), Sender); } else if(CMD_RESTART==cmd) SetPC(0); // while(rs->poll()) ch=rs->read(); } return pch->Cmd; } i++; } while(rs->poll()) ch=rs->read(); // ExBeep(5);DelayUS(100000);ExBeep(5); return -1; }