コード例 #1
0
ファイル: sr_router.c プロジェクト: yufengli71/Mininet_Router
void sr_handleip(struct sr_instance* sr,
        uint8_t * packet/* lent */,
        unsigned int len,
        char* interface/* lent */)
{
	sr_ip_hdr_t *ip_hdr = 0;
	struct sr_if *iface = 0;
	sr_icmp_hdr_t *icmp_hdr = 0;
	uint8_t *reply_packet = 0;
	struct sr_rt *rt = 0;
	uint32_t nexthop_ip, longest_mask = 0;
	struct sr_arpentry *arp_entry = 0;
	struct sr_arpreq *arp_req = 0;
	sr_ethernet_hdr_t *ether_hdr = 0;
	int matched = 0;
	
	/* check if header has the correct size */
	if (len < sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t)) {
		fprintf(stderr, "Error: invalid IP header length\n");
		return;
	}
	
	ip_hdr = (sr_ip_hdr_t*)(packet + sizeof(sr_ethernet_hdr_t));
	
	/* perform ip header checksum */
	if (cksum(ip_hdr, ip_hdr->ip_hl) != 0xffff) {
		fprintf(stderr, "Error: IP checksum failed\n");
		return;
	}
	
	/* grab the receiving interface */
	if ((iface = sr_get_interface(sr, interface)) == 0) {
		fprintf(stderr, "Error: interface does not exist (sr_handleip)\n");
		return;
	}
	
	/* if the packet is destined to our ip */
	if (ip_hdr->ip_dst == htonl(iface->ip)) {
	
		/* if it is an ICMP */
		if (ip_hdr->ip_p == htons(ip_protocol_icmp)) {
			
			/* check if header has the correct size */
			if (len < sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t) + sizeof(sr_icmp_hdr_t)) {
				fprintf(stderr, "Error: invalid ICMP header length\n");
				return;
			}
			
			icmp_hdr = (sr_icmp_hdr_t*)(packet + sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t));
			
			/* if it is an ICMP echo request, send an ICMP echo reply */
			if (icmp_hdr->icmp_type == htons(8) && icmp_hdr->icmp_code == htons(0)) {
				
				/* perform ICMP header checksum */
				if (cksum(icmp_hdr, sizeof(icmp_hdr)) != 0xffff) {
					fprintf(stderr, "Error: ICMP checksum failed\n");
					return;
				}
				
				/* generate an echo reply packet */
				if ((reply_packet = sr_generate_icmp((sr_ethernet_hdr_t *)packet, ip_hdr, iface, 0, 0)) == 0) {
					fprintf(stderr, "Error: failed to generate ICMP echo reply packet\n");
					return;
				}
				
				/* send an ICMP echo reply */
				if (sr_send_packet(sr, reply_packet, sizeof(reply_packet), (const char*)interface) == -1) {
					fprintf(stderr, "Error: sending packet failed (sr_handleip)\n");
				}
				
				free(reply_packet);				
			}
		}
		/* if it contains a TCP or UDP payload */
		else {
		
			/* generate Destination net unreachable (type 3, code 0) reply packet */
			if ((reply_packet = sr_generate_icmp((sr_ethernet_hdr_t *)packet, ip_hdr, iface, 3, 3)) == 0) {
				fprintf(stderr, "Error: failed to generate ICMP packet\n");
				return;
			}
			
			/* send an ICMP */
			if (sr_send_packet(sr, reply_packet, sizeof(reply_packet), (const char*)interface) == -1) {
				fprintf(stderr, "Error: sending packet failed (sr_handleip)\n");
			}
			
			free(reply_packet);		
		}
	}
	/* packet not for us, forward it */
	else {
		
		/* if TTL reaches 0 */
		if (ip_hdr->ip_ttl <= htons(1)) {
		
			/* generate Time exceeded (type 11, code 0) reply packet */
			if ((reply_packet = sr_generate_icmp((sr_ethernet_hdr_t *)packet, ip_hdr, iface, 11, 0)) == 0) {
				fprintf(stderr, "Error: failed to generate ICMP packet\n");
				return;
			}
			
			/* send an ICMP */
			if (sr_send_packet(sr, reply_packet, sizeof(reply_packet), (const char*)interface) == -1) {
				fprintf(stderr, "Error: sending packet failed (sr_handleip)\n");
			}
			
			free(reply_packet);
		}
		/* if packet has enough TTL */
		else {
			
			/* decrement the TTL by 1 */
			ip_hdr->ip_ttl --;
			
			/* recompute the packet checksum */
			ip_hdr->ip_sum = htons(0);
			ip_hdr->ip_sum = cksum(ip_hdr, sizeof(sr_ip_hdr_t));
			
			/* Find entry in the routing table with the longest prefix match */
			rt = sr->routing_table;
			while (rt != NULL) {
				
				/* update the gateway ip and the longest mask so far */
				if ((rt->dest.s_addr & rt->mask.s_addr) == (ntohl(ip_hdr->ip_dst) & rt->mask.s_addr) &&
					rt->mask.s_addr > longest_mask) {
					nexthop_ip = rt->gw.s_addr;
					longest_mask = rt->mask.s_addr;
					matched = 1;
				}
				
				rt = rt->next;
			}
			
			/* if a matching routing table entry was NOT found */
			if (matched == 0) {
				
				/* generate Destination net unreachable (type 3, code 0) reply packet */
				if ((reply_packet = sr_generate_icmp((sr_ethernet_hdr_t *)packet, ip_hdr, iface, 3, 0)) == 0) {
					fprintf(stderr, "Error: failed to generate ICMP packet\n");
					return;
				}
				
				/* send an ICMP */
				if (sr_send_packet(sr, reply_packet, sizeof(reply_packet), (const char*)interface) == -1) {
					fprintf(stderr, "Error: sending packet failed (sr_handleip)\n");
				}
				
				free(reply_packet);
			}
			/* if a matching routing table entry was found */
			else {
				/* if the next hop is 0.0.0.0 */
				if(nexthop_ip == 0) {
					nexthop_ip = ip_hdr->ip_dst;
				}
				
				/* set the source MAC of ethernet header */
				ether_hdr = (sr_ethernet_hdr_t*)packet;
				memcpy(ether_hdr->ether_shost, iface->addr, ETHER_ADDR_LEN);
				
				/* if the next-hop IP CANNOT be found in ARP cache */
				if ((arp_entry = sr_arpcache_lookup(&(sr->cache), htonl(nexthop_ip))) == NULL) {
					
					/* send an ARP request */
					arp_req = sr_arpcache_queuereq(&(sr->cache), nexthop_ip, packet, len, iface);
					handle_arpreq(sr, arp_req);
				}
				/* if the next-hop IP can be found in ARP cache */
				else {
					
					/* set the destination MAC of ethernet header */
					memcpy(ether_hdr->ether_dhost, arp_entry->mac, ETHER_ADDR_LEN);
					
					/* send the packet */
					if (sr_send_packet(sr, packet, sizeof(packet), (const char*)interface) == -1) {
						fprintf(stderr, "Error: sending packet failed (sr_handlearp)\n");
					}
					
					free(arp_entry);
				}
			}
		}
	}
}
コード例 #2
0
ファイル: bsplit.c プロジェクト: kuzinann/espl
int main (int argc, char **argv) {
    FILE *originalFile;
    int numOfBytesRead=1;
    int c;

    FILE *fileToWrite;
    char * sumOfOptions = "usage: bsplit [-x] [-h] [-b SIZE] FILE";
    int maxSizeFromUser=1024;

    int numOfFile=1;
    char numOfFileStr[50];

    unsigned int originalFileCksum = 0;
    char* fileName = argv[argc-1];
    originalFile = fopen( fileName, "r"); /*opens the original file */

    unsigned int currCksum = 0;

    while ((c = getopt (argc, argv, "xhb:")) != -1) {
        switch (c)
        {
        case 'x':
            originalFileCksum = cksum(originalFile);
            printf("%d\n", originalFileCksum );

            break;

        case 'h':

            printf("%s\n", sumOfOptions );
            exit(0);

            break;

        case 'b':

            maxSizeFromUser = atoi(optarg);



            break;


        default:
            abort ();
        }

    }


    unsigned int arrayForNewFile [(maxSizeFromUser+3)/4] ;

    while(numOfBytesRead) {

        numOfBytesRead = fread(arrayForNewFile, 1, maxSizeFromUser, originalFile); /*reads maxSizeFromUser at most bytes- 1 byte each time and saves it in arrayForNewFile*/

        if(numOfBytesRead!=0) {

            if(numOfFile<10) {
                sprintf(numOfFileStr , "%s.0%d", fileName, numOfFile); /*adds the numOfFile into "FILE.0%d" and saves the resulting string in numOfFileStr */

            } else {
                sprintf(numOfFileStr , "%s.%d", fileName, numOfFile); /*adds the numOfFile into "FILE.%d" and saves the resulting string in numOfFileStr */

            }
            /* printf ("Characters: %c %d \n", 'a', 65);*/

            fileToWrite = fopen( numOfFileStr, "w+"); /*creates a new file to write&read to, called numOfFileStr*/

            fwrite ( &currCksum, sizeof(currCksum), 1, fileToWrite);/*write 4 bytes of "0" into the beggining of the new file*/

            fwrite ( arrayForNewFile, 1, numOfBytesRead, fileToWrite); /*write into the new file all the chunk data from the arrayForNewFile*/

            fseek( fileToWrite, sizeof(currCksum) , SEEK_SET ); /*Sets the position indicator associated with the stream to a new position- 4 bytes after the beggining of the file */

            currCksum = cksum(fileToWrite); /*calculates the cksum of the new file */

            rewind ( fileToWrite ); /* Set position of stream to the beginning */

            fwrite ( &currCksum, sizeof(currCksum), 1, fileToWrite); /*write the currCksum in the beggining of the fileToWrite- override the "0" that was there */

            currCksum = 0;

            ++numOfFile;

            fclose(fileToWrite);
        }
    }



    fclose (originalFile);

    return 0;
}
コード例 #3
0
/*
 * Ip input routine.  Checksum and byte swap header.  If fragmented
 * try to reassemble.  Process options.  Pass to next level.
 */
void
ip_input(struct mbuf *m)
{
	register struct ip *ip;
	int hlen;

	DEBUG_CALL("ip_input");
	DEBUG_ARG("m = %lx", (long)m);
	DEBUG_ARG("m_len = %d", m->m_len);

	STAT(ipstat.ips_total++);

	if (m->m_len < sizeof (struct ip)) {
		STAT(ipstat.ips_toosmall++);
		return;
	}

	ip = mtod(m, struct ip *);

	if (ip->ip_v != IPVERSION) {
		STAT(ipstat.ips_badvers++);
		goto bad;
	}

	hlen = ip->ip_hl << 2;
	if (hlen<sizeof(struct ip ) || hlen>m->m_len) {/* min header length */
	  STAT(ipstat.ips_badhlen++);                     /* or packet too short */
	  goto bad;
	}

        /* keep ip header intact for ICMP reply
	 * ip->ip_sum = cksum(m, hlen);
	 * if (ip->ip_sum) {
	 */
	if(cksum(m,hlen)) {
	  STAT(ipstat.ips_badsum++);
	  goto bad;
	}

	/*
	 * Convert fields to host representation.
	 */
	NTOHS(ip->ip_len);
	if (ip->ip_len < hlen) {
		STAT(ipstat.ips_badlen++);
		goto bad;
	}
	NTOHS(ip->ip_id);
	NTOHS(ip->ip_off);

	/*
	 * Check that the amount of data in the buffers
	 * is as at least much as the IP header would have us expect.
	 * Trim mbufs if longer than we expect.
	 * Drop packet if shorter than we expect.
	 */
	if (m->m_len < ip->ip_len) {
		STAT(ipstat.ips_tooshort++);
		goto bad;
	}

    if (slirp_restrict) {
        if (ip_geth(ip->ip_dst) != special_addr_ip) {
            if (ip_getn(ip->ip_dst) == 0xffffffffu && ip->ip_p != IPPROTO_UDP)
                goto bad;
        } else {
            int host = ip_geth(ip->ip_dst) & 0xff;
            struct ex_list *ex_ptr;

            if (host == 0xff)
                goto bad;

            for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next)
                if (ex_ptr->ex_addr == host)
                    break;

            if (!ex_ptr)
                goto bad;
        }
    }

	/* Should drop packet if mbuf too long? hmmm... */
	if (m->m_len > ip->ip_len)
	   m_adj(m, ip->ip_len - m->m_len);

	/* check ip_ttl for a correct ICMP reply */
	if(ip->ip_ttl==0 || ip->ip_ttl==1) {
	  icmp_error(m, ICMP_TIMXCEED,ICMP_TIMXCEED_INTRANS, 0,"ttl");
	  goto bad;
	}

	/*
	 * Process options and, if not destined for us,
	 * ship it on.  ip_dooptions returns 1 when an
	 * error was detected (causing an icmp message
	 * to be sent and the original packet to be freed).
	 */
/* We do no IP options */
/*	if (hlen > sizeof (struct ip) && ip_dooptions(m))
 *		goto next;
 */
	/*
	 * If offset or IP_MF are set, must reassemble.
	 * Otherwise, nothing need be done.
	 * (We could look in the reassembly queue to see
	 * if the packet was previously fragmented,
	 * but it's not worth the time; just let them time out.)
	 *
	 * XXX This should fail, don't fragment yet
	 */
	if (ip->ip_off &~ IP_DF) {
	  register struct ipq *fp;
      struct qlink *l;
		/*
		 * Look for queue of fragments
		 * of this datagram.
		 */
		for (l = ipq.ip_link.next; l != &ipq.ip_link; l = l->next) {
            fp = container_of(l, struct ipq, ip_link);
            if (ip->ip_id == fp->ipq_id &&
		      ip_equal(ip->ip_src, fp->ipq_src) &&
		      ip_equal(ip->ip_dst, fp->ipq_dst) &&
		      ip->ip_p == fp->ipq_p)
		    goto found;
        }
        fp = NULL;
	found:

		/*
		 * Adjust ip_len to not reflect header,
		 * set ip_mff if more fragments are expected,
		 * convert offset of this to bytes.
		 */
		ip->ip_len -= hlen;
		if (ip->ip_off & IP_MF)
		  ip->ip_tos |= 1;
		else
		  ip->ip_tos &= ~1;

		ip->ip_off <<= 3;

		/*
		 * If datagram marked as having more fragments
		 * or if this is not the first fragment,
		 * attempt reassembly; if it succeeds, proceed.
		 */
		if (ip->ip_tos & 1 || ip->ip_off) {
			STAT(ipstat.ips_fragments++);
			ip = ip_reass(ip, fp);
			if (ip == NULL)
				return;
			STAT(ipstat.ips_reassembled++);
			m = dtom(ip);
		} else
			if (fp)
		   	   ip_freef(fp);

	} else
コード例 #4
0
ファイル: sr_router.c プロジェクト: Fate9834/CorrectVersion
void ip_handlepacketforme(struct sr_instance *sr,
        sr_ip_hdr_t *ip_hdr,
        char *interface) {
 
    struct sr_arpreq *req;
    struct sr_arpentry *arp_entry;
    uint8_t *cache_packet;
    uint16_t total_len;
    uint16_t icmp_len;
    uint32_t dst;
    uint8_t icmp_type;
    uint8_t icmp_code;

    /* Check whether ICMP echo request or TCP/UDP */
    if (ip_hdr->ip_p == ip_protocol_icmp){

      dst = ip_hdr->ip_src;
      ip_hdr->ip_src = ip_hdr->ip_dst;
      ip_hdr->ip_dst = dst;

      /* Modify the ICMP reply packet */
      sr_icmp_hdr_t *icmp_hdr_ptr = icmp_header(ip_hdr);

      icmp_hdr_ptr->icmp_sum = 0;
      icmp_hdr_ptr->icmp_type = type_echo_reply;
      icmp_hdr_ptr->icmp_code = code_echo_reply;
      icmp_len = ntohs(ip_hdr->ip_len)-ip_hdr->ip_hl * 4;
              
      /* Copy the packet over */
      total_len = ip_hdr->ip_len;
      cache_packet = malloc(total_len);
      memcpy(cache_packet, ip_hdr, total_len);

      icmp_hdr_ptr = icmp_header((struct sr_ip_hdr *)cache_packet);
      icmp_hdr_ptr->icmp_sum = cksum(icmp_hdr_ptr, icmp_len);

      struct sr_ip_hdr *ip_hdr_csum = (struct sr_ip_hdr *)cache_packet;
      ip_hdr_csum->ip_sum = cksum(ip_hdr_csum, sizeof(sr_ip_hdr_t));

      /* Check if we should send immediately or wait */
      arp_entry = sr_arpcache_lookup(&sr->cache, dst);

      if (arp_entry != 0){

        /* Entry Exists, we can send it out right now */
        sr_add_ethernet_send(sr, cache_packet, total_len, dst, ethertype_ip);

        printf("** ARP entry exists, Echo reply sent\n");

      } else {
          req = sr_arpcache_queuereq(&sr->cache, dst, cache_packet, 
                                    total_len, interface);

          printf("** ARP entry doesn't exist, Echo reply queued\n");

          sr_handle_arpreq(sr, req);
        }
    } else if (ip_hdr->ip_p == ip_protocol_tcp||ip_hdr->ip_p == ip_protocol_udp) {

        /* Send ICMP port unreachable */            
        icmp_type = 3;
        icmp_code = 3;             
        sr_icmp_with_payload(sr, ip_hdr, interface, icmp_type, icmp_code);
      }
}
コード例 #5
0
ファイル: sr_router.c プロジェクト: Fate9834/CorrectVersion
void sr_handle_arpreq(struct sr_instance *sr, struct sr_arpreq *req) 
{
    if (difftime(time(0), req->sent) > 0.9) {

      /* Host is not reachable */
      if (req->times_sent >= 5) {

        printf("** Host Unreachable\n");
        
        /* Send ICMP host unreachable*/
        struct sr_packet *ip_packet, *next;
        ip_packet = req->packets;

        if(ip_packet != 0){
          next = ip_packet->next;
        }
        while(ip_packet != 0){
          sr_ip_hdr_t *ip_hdr = (sr_ip_hdr_t *)(ip_packet->buf);
          struct sr_if *s_interface = sr_get_interface(sr, ip_packet->iface);
          uint32_t dst;
          
          /* Send ICMP host unreachable */
          struct sr_ip_hdr send_ip_hdr;
          
          send_ip_hdr.ip_hl = 5;
          send_ip_hdr.ip_v = ip_hdr->ip_v;
          send_ip_hdr.ip_tos = 0;
          send_ip_hdr.ip_id = 0;
          send_ip_hdr.ip_off = htons(IP_DF);
          send_ip_hdr.ip_ttl = 100;
          send_ip_hdr.ip_p = ip_protocol_icmp;
          send_ip_hdr.ip_sum = 0;
          send_ip_hdr.ip_dst = ip_hdr->ip_src;
          send_ip_hdr.ip_src = s_interface->ip;
          dst = ip_hdr->ip_src;
            
          /* Copy the packet over */
          uint8_t *cache_packet;
          uint16_t total_len;
          uint16_t icmp_len;

          icmp_len = sizeof(struct sr_icmp_t3_hdr);
          total_len = ICMP_IP_HDR_LEN_BYTE + icmp_len;
          send_ip_hdr.ip_len = htons(total_len);
          send_ip_hdr.ip_sum = cksum(&send_ip_hdr, ICMP_IP_HDR_LEN_BYTE);

          cache_packet = malloc(total_len);
          struct sr_icmp_t3_hdr icmp_error_packet = icmp_send_error_packet(ip_hdr, code_host_unreach);

          memcpy(cache_packet, &(send_ip_hdr), ICMP_IP_HDR_LEN_BYTE);
          memcpy(cache_packet + ICMP_IP_HDR_LEN_BYTE, &(icmp_error_packet), 
                sizeof(struct sr_icmp_t3_hdr));

          print_hdr_ip(cache_packet);

          struct sr_arpreq *icmp_req;
          struct sr_arpentry *arp_entry;

          /* Check ARP cache  */
          arp_entry = sr_arpcache_lookup(&sr->cache, dst);

          if (arp_entry != 0){
                
            /* Entry exists, we can send it out right now */
            sr_add_ethernet_send(sr, cache_packet, total_len, dst, ethertype_ip);
          } else {

              /* Get the interface at which the original packet arrived */
              struct sr_rt *lpmatch;
              struct sr_if *r_iface;

              lpmatch = longest_prefix_matching(sr, dst);
              r_iface = sr_get_interface(sr, lpmatch->interface);           
              icmp_req = sr_arpcache_queuereq(&sr->cache, dst, 
                                        cache_packet, total_len, r_iface->name);
              sr_handle_arpreq(sr, icmp_req);
            }
          ip_packet = next;
          if(ip_packet != 0){
            next = ip_packet->next;
          } else {
              sr_arpreq_destroy(&sr->cache, req);
          }
        }  
      } else {
          arp_boardcast(sr, req);

	  printf("** APR boardcasted\n");

          req->sent = time(0);
          req->times_sent ++;
        }
    }
}
コード例 #6
0
ファイル: tcp_input.c プロジェクト: Leecheolhee/VSSIM
/*
 * TCP input routine, follows pages 65-76 of the
 * protocol specification dated September, 1981 very closely.
 */
void
tcp_input(struct mbuf *m, int iphlen, struct socket *inso)
{
  	struct ip save_ip, *ip;
	register struct tcpiphdr *ti;
	caddr_t optp = NULL;
	int optlen = 0;
	int len, tlen, off;
        register struct tcpcb *tp = NULL;
	register int tiflags;
        struct socket *so = NULL;
	int todrop, acked, ourfinisacked, needoutput = 0;
	int iss = 0;
	u_long tiwin;
	int ret;
    struct ex_list *ex_ptr;
    Slirp *slirp;

	DEBUG_CALL("tcp_input");
	DEBUG_ARGS((dfd," m = %8lx  iphlen = %2d  inso = %lx\n",
		    (long )m, iphlen, (long )inso ));

	/*
	 * If called with m == 0, then we're continuing the connect
	 */
	if (m == NULL) {
		so = inso;
		slirp = so->slirp;

		/* Re-set a few variables */
		tp = sototcpcb(so);
		m = so->so_m;
                so->so_m = NULL;
		ti = so->so_ti;
		tiwin = ti->ti_win;
		tiflags = ti->ti_flags;

		goto cont_conn;
	}
	slirp = m->slirp;

	/*
	 * Get IP and TCP header together in first mbuf.
	 * Note: IP leaves IP header in first mbuf.
	 */
	ti = mtod(m, struct tcpiphdr *);
	if (iphlen > sizeof(struct ip )) {
	  ip_stripoptions(m, (struct mbuf *)0);
	  iphlen=sizeof(struct ip );
	}
	/* XXX Check if too short */


	/*
	 * Save a copy of the IP header in case we want restore it
	 * for sending an ICMP error message in response.
	 */
	ip=mtod(m, struct ip *);
	save_ip = *ip;
	save_ip.ip_len+= iphlen;

	/*
	 * Checksum extended TCP header and data.
	 */
	tlen = ((struct ip *)ti)->ip_len;
        tcpiphdr2qlink(ti)->next = tcpiphdr2qlink(ti)->prev = NULL;
        memset(&ti->ti_i.ih_mbuf, 0 , sizeof(struct mbuf_ptr));
	ti->ti_x1 = 0;
	ti->ti_len = htons((u_int16_t)tlen);
	len = sizeof(struct ip ) + tlen;
	if(cksum(m, len)) {
	  goto drop;
	}

	/*
	 * Check that TCP offset makes sense,
	 * pull out TCP options and adjust length.		XXX
	 */
	off = ti->ti_off << 2;
	if (off < sizeof (struct tcphdr) || off > tlen) {
	  goto drop;
	}
	tlen -= off;
	ti->ti_len = tlen;
	if (off > sizeof (struct tcphdr)) {
	  optlen = off - sizeof (struct tcphdr);
	  optp = mtod(m, caddr_t) + sizeof (struct tcpiphdr);
	}
	tiflags = ti->ti_flags;

	/*
	 * Convert TCP protocol specific fields to host format.
	 */
	NTOHL(ti->ti_seq);
	NTOHL(ti->ti_ack);
	NTOHS(ti->ti_win);
	NTOHS(ti->ti_urp);

	/*
	 * Drop TCP, IP headers and TCP options.
	 */
	m->m_data += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
	m->m_len  -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);

    if (slirp->restricted) {
        for (ex_ptr = slirp->exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
            if (ex_ptr->ex_fport == ti->ti_dport &&
                ti->ti_dst.s_addr == ex_ptr->ex_addr.s_addr) {
                break;
            }
        }
        if (!ex_ptr)
            goto drop;
    }
	/*
	 * Locate pcb for segment.
	 */
findso:
	so = slirp->tcp_last_so;
	if (so->so_fport != ti->ti_dport ||
	    so->so_lport != ti->ti_sport ||
	    so->so_laddr.s_addr != ti->ti_src.s_addr ||
	    so->so_faddr.s_addr != ti->ti_dst.s_addr) {
		so = solookup(&slirp->tcb, ti->ti_src, ti->ti_sport,
			       ti->ti_dst, ti->ti_dport);
		if (so)
			slirp->tcp_last_so = so;
	}

	/*
	 * If the state is CLOSED (i.e., TCB does not exist) then
	 * all data in the incoming segment is discarded.
	 * If the TCB exists but is in CLOSED state, it is embryonic,
	 * but should either do a listen or a connect soon.
	 *
	 * state == CLOSED means we've done socreate() but haven't
	 * attached it to a protocol yet...
	 *
	 * XXX If a TCB does not exist, and the TH_SYN flag is
	 * the only flag set, then create a session, mark it
	 * as if it was LISTENING, and continue...
	 */
        if (so == NULL) {
	  if ((tiflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ACK)) != TH_SYN)
	    goto dropwithreset;

	  if ((so = socreate(slirp)) == NULL)
	    goto dropwithreset;
	  if (tcp_attach(so) < 0) {
	    free(so); /* Not sofree (if it failed, it's not insqued) */
	    goto dropwithreset;
	  }

	  sbreserve(&so->so_snd, TCP_SNDSPACE);
	  sbreserve(&so->so_rcv, TCP_RCVSPACE);

	  so->so_laddr = ti->ti_src;
	  so->so_lport = ti->ti_sport;
	  so->so_faddr = ti->ti_dst;
	  so->so_fport = ti->ti_dport;

	  if ((so->so_iptos = tcp_tos(so)) == 0)
	    so->so_iptos = ((struct ip *)ti)->ip_tos;

	  tp = sototcpcb(so);
	  tp->t_state = TCPS_LISTEN;
	}

        /*
         * If this is a still-connecting socket, this probably
         * a retransmit of the SYN.  Whether it's a retransmit SYN
	 * or something else, we nuke it.
         */
        if (so->so_state & SS_ISFCONNECTING)
                goto drop;

	tp = sototcpcb(so);

	/* XXX Should never fail */
        if (tp == NULL)
		goto dropwithreset;
	if (tp->t_state == TCPS_CLOSED)
		goto drop;

	tiwin = ti->ti_win;

	/*
	 * Segment received on connection.
	 * Reset idle time and keep-alive timer.
	 */
	tp->t_idle = 0;
	if (SO_OPTIONS)
	   tp->t_timer[TCPT_KEEP] = TCPTV_KEEPINTVL;
	else
	   tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_IDLE;

	/*
	 * Process options if not in LISTEN state,
	 * else do it below (after getting remote address).
	 */
	if (optp && tp->t_state != TCPS_LISTEN)
		tcp_dooptions(tp, (u_char *)optp, optlen, ti);

	/*
	 * Header prediction: check for the two common cases
	 * of a uni-directional data xfer.  If the packet has
	 * no control flags, is in-sequence, the window didn't
	 * change and we're not retransmitting, it's a
	 * candidate.  If the length is zero and the ack moved
	 * forward, we're the sender side of the xfer.  Just
	 * free the data acked & wake any higher level process
	 * that was blocked waiting for space.  If the length
	 * is non-zero and the ack didn't move, we're the
	 * receiver side.  If we're getting packets in-order
	 * (the reassembly queue is empty), add the data to
	 * the socket buffer and note that we need a delayed ack.
	 *
	 * XXX Some of these tests are not needed
	 * eg: the tiwin == tp->snd_wnd prevents many more
	 * predictions.. with no *real* advantage..
	 */
	if (tp->t_state == TCPS_ESTABLISHED &&
	    (tiflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ACK)) == TH_ACK &&
	    ti->ti_seq == tp->rcv_nxt &&
	    tiwin && tiwin == tp->snd_wnd &&
	    tp->snd_nxt == tp->snd_max) {
		if (ti->ti_len == 0) {
			if (SEQ_GT(ti->ti_ack, tp->snd_una) &&
			    SEQ_LEQ(ti->ti_ack, tp->snd_max) &&
			    tp->snd_cwnd >= tp->snd_wnd) {
				/*
				 * this is a pure ack for outstanding data.
				 */
				if (tp->t_rtt &&
				    SEQ_GT(ti->ti_ack, tp->t_rtseq))
					tcp_xmit_timer(tp, tp->t_rtt);
				acked = ti->ti_ack - tp->snd_una;
				sbdrop(&so->so_snd, acked);
				tp->snd_una = ti->ti_ack;
				m_freem(m);

				/*
				 * If all outstanding data are acked, stop
				 * retransmit timer, otherwise restart timer
				 * using current (possibly backed-off) value.
				 * If process is waiting for space,
				 * wakeup/selwakeup/signal.  If data
				 * are ready to send, let tcp_output
				 * decide between more output or persist.
				 */
				if (tp->snd_una == tp->snd_max)
					tp->t_timer[TCPT_REXMT] = 0;
				else if (tp->t_timer[TCPT_PERSIST] == 0)
					tp->t_timer[TCPT_REXMT] = tp->t_rxtcur;

				/*
				 * This is called because sowwakeup might have
				 * put data into so_snd.  Since we don't so sowwakeup,
				 * we don't need this.. XXX???
				 */
				if (so->so_snd.sb_cc)
					(void) tcp_output(tp);

				return;
			}
		} else if (ti->ti_ack == tp->snd_una &&
		    tcpfrag_list_empty(tp) &&
		    ti->ti_len <= sbspace(&so->so_rcv)) {
			/*
			 * this is a pure, in-sequence data packet
			 * with nothing on the reassembly queue and
			 * we have enough buffer space to take it.
			 */
			tp->rcv_nxt += ti->ti_len;
			/*
			 * Add data to socket buffer.
			 */
			if (so->so_emu) {
				if (tcp_emu(so,m)) sbappend(so, m);
			} else
				sbappend(so, m);

			/*
			 * If this is a short packet, then ACK now - with Nagel
			 *	congestion avoidance sender won't send more until
			 *	he gets an ACK.
			 *
			 * It is better to not delay acks at all to maximize
			 * TCP throughput.  See RFC 2581.
			 */
			tp->t_flags |= TF_ACKNOW;
			tcp_output(tp);
			return;
		}
	} /* header prediction */
	/*
	 * Calculate 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 advertised window.
	 */
	{ int win;
          win = sbspace(&so->so_rcv);
	  if (win < 0)
	    win = 0;
	  tp->rcv_wnd = max(win, (int)(tp->rcv_adv - tp->rcv_nxt));
	}

	switch (tp->t_state) {

	/*
	 * If the state is LISTEN then ignore segment if it contains an RST.
	 * If the segment contains an ACK then it is bad and send a RST.
	 * If it does not contain a SYN then it is not interesting; drop it.
	 * Don't bother responding if the destination was a broadcast.
	 * Otherwise initialize tp->rcv_nxt, and tp->irs, select an initial
	 * tp->iss, and send a segment:
	 *     <SEQ=ISS><ACK=RCV_NXT><CTL=SYN,ACK>
	 * Also initialize tp->snd_nxt to tp->iss+1 and tp->snd_una to tp->iss.
	 * Fill in remote peer address fields if not previously specified.
	 * Enter SYN_RECEIVED state, and process any other fields of this
	 * segment in this state.
	 */
	case TCPS_LISTEN: {

	  if (tiflags & TH_RST)
	    goto drop;
	  if (tiflags & TH_ACK)
	    goto dropwithreset;
	  if ((tiflags & TH_SYN) == 0)
	    goto drop;

	  /*
	   * This has way too many gotos...
	   * But a bit of spaghetti code never hurt anybody :)
	   */

	  /*
	   * If this is destined for the control address, then flag to
	   * tcp_ctl once connected, otherwise connect
	   */
	  if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) ==
	      slirp->vnetwork_addr.s_addr) {
	    if (so->so_faddr.s_addr != slirp->vhost_addr.s_addr &&
		so->so_faddr.s_addr != slirp->vnameserver_addr.s_addr) {
		/* May be an add exec */
		for (ex_ptr = slirp->exec_list; ex_ptr;
		     ex_ptr = ex_ptr->ex_next) {
		  if(ex_ptr->ex_fport == so->so_fport &&
		     so->so_faddr.s_addr == ex_ptr->ex_addr.s_addr) {
		    so->so_state |= SS_CTL;
		    break;
		  }
		}
		if (so->so_state & SS_CTL) {
		    goto cont_input;
		}
	    }
	    /* CTL_ALIAS: Do nothing, tcp_fconnect will be called on it */
	  }

	  if (so->so_emu & EMU_NOCONNECT) {
	    so->so_emu &= ~EMU_NOCONNECT;
	    goto cont_input;
	  }

	  if((tcp_fconnect(so) == -1) && (errno != EINPROGRESS) && (errno != EWOULDBLOCK)) {
	    u_char code=ICMP_UNREACH_NET;
	    DEBUG_MISC((dfd," tcp fconnect errno = %d-%s\n",
			errno,strerror(errno)));
	    if(errno == ECONNREFUSED) {
	      /* ACK the SYN, send RST to refuse the connection */
	      tcp_respond(tp, ti, m, ti->ti_seq+1, (tcp_seq)0,
			  TH_RST|TH_ACK);
	    } else {
	      if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST;
	      HTONL(ti->ti_seq);             /* restore tcp header */
	      HTONL(ti->ti_ack);
	      HTONS(ti->ti_win);
	      HTONS(ti->ti_urp);
	      m->m_data -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
	      m->m_len  += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
	      *ip=save_ip;
	      icmp_error(m, ICMP_UNREACH,code, 0,strerror(errno));
	    }
	    tp = tcp_close(tp);
	    m_free(m);
	  } else {
	    /*
	     * Haven't connected yet, save the current mbuf
	     * and ti, and return
	     * XXX Some OS's don't tell us whether the connect()
	     * succeeded or not.  So we must time it out.
	     */
	    so->so_m = m;
	    so->so_ti = ti;
	    tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
	    tp->t_state = TCPS_SYN_RECEIVED;
	  }
	  return;

	cont_conn:
	  /* m==NULL
	   * Check if the connect succeeded
	   */
	  if (so->so_state & SS_NOFDREF) {
	    tp = tcp_close(tp);
	    goto dropwithreset;
	  }
	cont_input:
	  tcp_template(tp);

	  if (optp)
	    tcp_dooptions(tp, (u_char *)optp, optlen, ti);

	  if (iss)
	    tp->iss = iss;
	  else
	    tp->iss = slirp->tcp_iss;
	  slirp->tcp_iss += TCP_ISSINCR/2;
	  tp->irs = ti->ti_seq;
	  tcp_sendseqinit(tp);
	  tcp_rcvseqinit(tp);
	  tp->t_flags |= TF_ACKNOW;
	  tp->t_state = TCPS_SYN_RECEIVED;
	  tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
	  goto trimthenstep6;
	} /* case TCPS_LISTEN */

	/*
	 * If the state is SYN_SENT:
	 *	if seg contains an ACK, but not for our SYN, drop the input.
	 *	if seg contains a RST, then drop the connection.
	 *	if seg does not contain SYN, then drop it.
	 * Otherwise this is an acceptable SYN segment
	 *	initialize tp->rcv_nxt and tp->irs
	 *	if seg contains ack then advance tp->snd_una
	 *	if SYN has been acked change to ESTABLISHED else SYN_RCVD state
	 *	arrange for segment to be acked (eventually)
	 *	continue processing rest of data/controls, beginning with URG
	 */
	case TCPS_SYN_SENT:
		if ((tiflags & TH_ACK) &&
		    (SEQ_LEQ(ti->ti_ack, tp->iss) ||
		     SEQ_GT(ti->ti_ack, tp->snd_max)))
			goto dropwithreset;

		if (tiflags & TH_RST) {
			if (tiflags & TH_ACK)
				tp = tcp_drop(tp,0); /* XXX Check t_softerror! */
			goto drop;
		}

		if ((tiflags & TH_SYN) == 0)
			goto drop;
		if (tiflags & TH_ACK) {
			tp->snd_una = ti->ti_ack;
			if (SEQ_LT(tp->snd_nxt, tp->snd_una))
				tp->snd_nxt = tp->snd_una;
		}

		tp->t_timer[TCPT_REXMT] = 0;
		tp->irs = ti->ti_seq;
		tcp_rcvseqinit(tp);
		tp->t_flags |= TF_ACKNOW;
		if (tiflags & TH_ACK && SEQ_GT(tp->snd_una, tp->iss)) {
			soisfconnected(so);
			tp->t_state = TCPS_ESTABLISHED;

			(void) tcp_reass(tp, (struct tcpiphdr *)0,
				(struct mbuf *)0);
			/*
			 * if we didn't have to retransmit the SYN,
			 * use its rtt as our initial srtt & rtt var.
			 */
			if (tp->t_rtt)
				tcp_xmit_timer(tp, tp->t_rtt);
		} else
			tp->t_state = TCPS_SYN_RECEIVED;

trimthenstep6:
		/*
		 * Advance ti->ti_seq to correspond to first data byte.
		 * If data, trim to stay within window,
		 * dropping FIN if necessary.
		 */
		ti->ti_seq++;
		if (ti->ti_len > tp->rcv_wnd) {
			todrop = ti->ti_len - tp->rcv_wnd;
			m_adj(m, -todrop);
			ti->ti_len = tp->rcv_wnd;
			tiflags &= ~TH_FIN;
		}
		tp->snd_wl1 = ti->ti_seq - 1;
		tp->rcv_up = ti->ti_seq;
		goto step6;
	} /* switch tp->t_state */
	/*
	 * States other than LISTEN or SYN_SENT.
	 * 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 ack.
	 */
	todrop = tp->rcv_nxt - ti->ti_seq;
	if (todrop > 0) {
		if (tiflags & TH_SYN) {
			tiflags &= ~TH_SYN;
			ti->ti_seq++;
			if (ti->ti_urp > 1)
				ti->ti_urp--;
			else
				tiflags &= ~TH_URG;
			todrop--;
		}
		/*
		 * Following if statement from Stevens, vol. 2, p. 960.
		 */
		if (todrop > ti->ti_len
		    || (todrop == ti->ti_len && (tiflags & TH_FIN) == 0)) {
			/*
			 * Any valid FIN must be to the left of the window.
			 * At this point the FIN must be a duplicate or out
			 * of sequence; drop it.
			 */
			tiflags &= ~TH_FIN;

			/*
			 * Send an ACK to resynchronize and drop any data.
			 * But keep on processing for RST or ACK.
			 */
			tp->t_flags |= TF_ACKNOW;
			todrop = ti->ti_len;
		}
		m_adj(m, todrop);
		ti->ti_seq += todrop;
		ti->ti_len -= todrop;
		if (ti->ti_urp > todrop)
			ti->ti_urp -= todrop;
		else {
			tiflags &= ~TH_URG;
			ti->ti_urp = 0;
		}
	}
	/*
	 * If new data are received on a connection after the
	 * user processes are gone, then RST the other end.
	 */
	if ((so->so_state & SS_NOFDREF) &&
	    tp->t_state > TCPS_CLOSE_WAIT && ti->ti_len) {
		tp = tcp_close(tp);
		goto dropwithreset;
	}

	/*
	 * If segment ends after window, drop trailing data
	 * (and PUSH and FIN); if nothing left, just ACK.
	 */
	todrop = (ti->ti_seq+ti->ti_len) - (tp->rcv_nxt+tp->rcv_wnd);
	if (todrop > 0) {
		if (todrop >= ti->ti_len) {
			/*
			 * If a new connection request is received
			 * while in TIME_WAIT, drop the old connection
			 * and start over if the sequence numbers
			 * are above the previous ones.
			 */
			if (tiflags & TH_SYN &&
			    tp->t_state == TCPS_TIME_WAIT &&
			    SEQ_GT(ti->ti_seq, tp->rcv_nxt)) {
				iss = tp->rcv_nxt + TCP_ISSINCR;
				tp = tcp_close(tp);
				goto findso;
			}
			/*
			 * If window is closed can only take segments at
			 * window edge, and have to drop data and PUSH from
			 * incoming segments.  Continue processing, but
			 * remember to ack.  Otherwise, drop segment
			 * and ack.
			 */
			if (tp->rcv_wnd == 0 && ti->ti_seq == tp->rcv_nxt) {
				tp->t_flags |= TF_ACKNOW;
			} else {
				goto dropafterack;
			}
		}
		m_adj(m, -todrop);
		ti->ti_len -= todrop;
		tiflags &= ~(TH_PUSH|TH_FIN);
	}

	/*
	 * If the RST bit is set examine the state:
	 *    SYN_RECEIVED STATE:
	 *	If passive open, return to LISTEN state.
	 *	If active open, inform user that connection was refused.
	 *    ESTABLISHED, FIN_WAIT_1, FIN_WAIT2, CLOSE_WAIT STATES:
	 *	Inform user that connection was reset, and close tcb.
	 *    CLOSING, LAST_ACK, TIME_WAIT STATES
	 *	Close the tcb.
	 */
	if (tiflags&TH_RST) switch (tp->t_state) {

	case TCPS_SYN_RECEIVED:
	case TCPS_ESTABLISHED:
	case TCPS_FIN_WAIT_1:
	case TCPS_FIN_WAIT_2:
	case TCPS_CLOSE_WAIT:
		tp->t_state = TCPS_CLOSED;
		tp = tcp_close(tp);
		goto drop;

	case TCPS_CLOSING:
	case TCPS_LAST_ACK:
	case TCPS_TIME_WAIT:
		tp = tcp_close(tp);
		goto drop;
	}

	/*
	 * If a SYN is in the window, then this is an
	 * error and we send an RST and drop the connection.
	 */
	if (tiflags & TH_SYN) {
		tp = tcp_drop(tp,0);
		goto dropwithreset;
	}

	/*
	 * If the ACK bit is off we drop the segment and return.
	 */
	if ((tiflags & TH_ACK) == 0) goto drop;

	/*
	 * Ack processing.
	 */
	switch (tp->t_state) {
	/*
	 * In SYN_RECEIVED state if the ack ACKs our SYN then enter
	 * ESTABLISHED state and continue processing, otherwise
	 * send an RST.  una<=ack<=max
	 */
	case TCPS_SYN_RECEIVED:

		if (SEQ_GT(tp->snd_una, ti->ti_ack) ||
		    SEQ_GT(ti->ti_ack, tp->snd_max))
			goto dropwithreset;
		tp->t_state = TCPS_ESTABLISHED;
		/*
		 * The sent SYN is ack'ed with our sequence number +1
		 * The first data byte already in the buffer will get
		 * lost if no correction is made.  This is only needed for
		 * SS_CTL since the buffer is empty otherwise.
		 * tp->snd_una++; or:
		 */
		tp->snd_una=ti->ti_ack;
		if (so->so_state & SS_CTL) {
		  /* So tcp_ctl reports the right state */
		  ret = tcp_ctl(so);
		  if (ret == 1) {
		    soisfconnected(so);
		    so->so_state &= ~SS_CTL;   /* success XXX */
		  } else if (ret == 2) {
		    so->so_state &= SS_PERSISTENT_MASK;
		    so->so_state |= SS_NOFDREF; /* CTL_CMD */
		  } else {
		    needoutput = 1;
		    tp->t_state = TCPS_FIN_WAIT_1;
		  }
		} else {
		  soisfconnected(so);
		}

		(void) tcp_reass(tp, (struct tcpiphdr *)0, (struct mbuf *)0);
		tp->snd_wl1 = ti->ti_seq - 1;
		/* Avoid ack processing; snd_una==ti_ack  =>  dup ack */
		goto synrx_to_est;
		/* fall into ... */

	/*
	 * In ESTABLISHED state: drop duplicate ACKs; ACK out of range
	 * ACKs.  If the ack is in the range
	 *	tp->snd_una < ti->ti_ack <= tp->snd_max
	 * then advance tp->snd_una to ti->ti_ack and drop
	 * data from the retransmission queue.  If this ACK reflects
	 * more up to date window information we update our window information.
	 */
	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:

		if (SEQ_LEQ(ti->ti_ack, tp->snd_una)) {
			if (ti->ti_len == 0 && tiwin == tp->snd_wnd) {
			  DEBUG_MISC((dfd," dup ack  m = %lx  so = %lx \n",
				      (long )m, (long )so));
				/*
				 * If we have outstanding data (other than
				 * a window probe), this is a completely
				 * duplicate ack (ie, window info didn't
				 * change), the ack is the biggest we've
				 * seen and we've seen exactly our rexmt
				 * threshold of them, assume a packet
				 * has been dropped and retransmit it.
				 * Kludge snd_nxt & the congestion
				 * window so we send only this one
				 * packet.
				 *
				 * We know we're losing at the current
				 * window size so do congestion avoidance
				 * (set ssthresh to half the current window
				 * and pull our congestion window back to
				 * the new ssthresh).
				 *
				 * Dup acks mean that packets have left the
				 * network (they're now cached at the receiver)
				 * so bump cwnd by the amount in the receiver
				 * to keep a constant cwnd packets in the
				 * network.
				 */
				if (tp->t_timer[TCPT_REXMT] == 0 ||
				    ti->ti_ack != tp->snd_una)
					tp->t_dupacks = 0;
				else if (++tp->t_dupacks == TCPREXMTTHRESH) {
					tcp_seq onxt = tp->snd_nxt;
					u_int win =
					    min(tp->snd_wnd, tp->snd_cwnd) / 2 /
						tp->t_maxseg;

					if (win < 2)
						win = 2;
					tp->snd_ssthresh = win * tp->t_maxseg;
					tp->t_timer[TCPT_REXMT] = 0;
					tp->t_rtt = 0;
					tp->snd_nxt = ti->ti_ack;
					tp->snd_cwnd = tp->t_maxseg;
					(void) tcp_output(tp);
					tp->snd_cwnd = tp->snd_ssthresh +
					       tp->t_maxseg * tp->t_dupacks;
					if (SEQ_GT(onxt, tp->snd_nxt))
						tp->snd_nxt = onxt;
					goto drop;
				} else if (tp->t_dupacks > TCPREXMTTHRESH) {
					tp->snd_cwnd += tp->t_maxseg;
					(void) tcp_output(tp);
					goto drop;
				}
			} else
				tp->t_dupacks = 0;
			break;
		}
	synrx_to_est:
		/*
		 * If the congestion window was inflated to account
		 * for the other side's cached packets, retract it.
		 */
		if (tp->t_dupacks > TCPREXMTTHRESH &&
		    tp->snd_cwnd > tp->snd_ssthresh)
			tp->snd_cwnd = tp->snd_ssthresh;
		tp->t_dupacks = 0;
		if (SEQ_GT(ti->ti_ack, tp->snd_max)) {
			goto dropafterack;
		}
		acked = ti->ti_ack - tp->snd_una;

		/*
		 * If transmit timer is running and timed sequence
		 * number was acked, update smoothed round trip time.
		 * Since we now have an rtt measurement, cancel the
		 * timer backoff (cf., Phil Karn's retransmit alg.).
		 * Recompute the initial retransmit timer.
		 */
		if (tp->t_rtt && SEQ_GT(ti->ti_ack, tp->t_rtseq))
			tcp_xmit_timer(tp,tp->t_rtt);

		/*
		 * If all outstanding data is acked, stop retransmit
		 * timer and remember to restart (more output or persist).
		 * If there is more data to be acked, restart retransmit
		 * timer, using current (possibly backed-off) value.
		 */
		if (ti->ti_ack == tp->snd_max) {
			tp->t_timer[TCPT_REXMT] = 0;
			needoutput = 1;
		} else if (tp->t_timer[TCPT_PERSIST] == 0)
			tp->t_timer[TCPT_REXMT] = tp->t_rxtcur;
		/*
		 * When new data is acked, open the congestion window.
		 * If the window gives us less than ssthresh packets
		 * in flight, open exponentially (maxseg per packet).
		 * Otherwise open linearly: maxseg per window
		 * (maxseg^2 / cwnd per packet).
		 */
		{
		  register u_int cw = tp->snd_cwnd;
		  register u_int incr = tp->t_maxseg;

		  if (cw > tp->snd_ssthresh)
		    incr = incr * incr / cw;
		  tp->snd_cwnd = min(cw + incr, TCP_MAXWIN<<tp->snd_scale);
		}
		if (acked > so->so_snd.sb_cc) {
			tp->snd_wnd -= so->so_snd.sb_cc;
			sbdrop(&so->so_snd, (int )so->so_snd.sb_cc);
			ourfinisacked = 1;
		} else {
			sbdrop(&so->so_snd, acked);
			tp->snd_wnd -= acked;
			ourfinisacked = 0;
		}
		tp->snd_una = ti->ti_ack;
		if (SEQ_LT(tp->snd_nxt, tp->snd_una))
			tp->snd_nxt = tp->snd_una;

		switch (tp->t_state) {

		/*
		 * In FIN_WAIT_1 STATE in addition to the processing
		 * for the ESTABLISHED state if our FIN is now acknowledged
		 * then enter FIN_WAIT_2.
		 */
		case TCPS_FIN_WAIT_1:
			if (ourfinisacked) {
				/*
				 * If we can't receive any more
				 * data, then closing user can proceed.
				 * Starting the timer is contrary to the
				 * specification, but if we don't get a FIN
				 * we'll hang forever.
				 */
				if (so->so_state & SS_FCANTRCVMORE) {
					tp->t_timer[TCPT_2MSL] = TCP_MAXIDLE;
				}
				tp->t_state = TCPS_FIN_WAIT_2;
			}
			break;

	 	/*
		 * In CLOSING STATE in addition to the processing for
		 * the ESTABLISHED state if the ACK acknowledges our FIN
		 * then enter the TIME-WAIT state, otherwise ignore
		 * the segment.
		 */
		case TCPS_CLOSING:
			if (ourfinisacked) {
				tp->t_state = TCPS_TIME_WAIT;
				tcp_canceltimers(tp);
				tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;
			}
			break;

		/*
		 * In LAST_ACK, we may still be waiting for data to drain
		 * and/or to be acked, as well as for the ack of our FIN.
		 * If our FIN is now acknowledged, delete the TCB,
		 * enter the closed state and return.
		 */
		case TCPS_LAST_ACK:
			if (ourfinisacked) {
				tp = tcp_close(tp);
				goto drop;
			}
			break;

		/*
		 * In TIME_WAIT state the only thing that should arrive
		 * is a retransmission of the remote FIN.  Acknowledge
		 * it and restart the finack timer.
		 */
		case TCPS_TIME_WAIT:
			tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;
			goto dropafterack;
		}
	} /* switch(tp->t_state) */

step6:
	/*
	 * Update window information.
	 * Don't look at window if no ACK: TAC's send garbage on first SYN.
	 */
	if ((tiflags & TH_ACK) &&
	    (SEQ_LT(tp->snd_wl1, ti->ti_seq) ||
	    (tp->snd_wl1 == ti->ti_seq && (SEQ_LT(tp->snd_wl2, ti->ti_ack) ||
	    (tp->snd_wl2 == ti->ti_ack && tiwin > tp->snd_wnd))))) {
		tp->snd_wnd = tiwin;
		tp->snd_wl1 = ti->ti_seq;
		tp->snd_wl2 = ti->ti_ack;
		if (tp->snd_wnd > tp->max_sndwnd)
			tp->max_sndwnd = tp->snd_wnd;
		needoutput = 1;
	}

	/*
	 * Process segments with URG.
	 */
	if ((tiflags & TH_URG) && ti->ti_urp &&
	    TCPS_HAVERCVDFIN(tp->t_state) == 0) {
		/*
		 * This is a kludge, but if we receive and accept
		 * random urgent pointers, we'll crash in
		 * soreceive.  It's hard to imagine someone
		 * actually wanting to send this much urgent data.
		 */
		if (ti->ti_urp + so->so_rcv.sb_cc > so->so_rcv.sb_datalen) {
			ti->ti_urp = 0;
			tiflags &= ~TH_URG;
			goto dodata;
		}
		/*
		 * If this segment advances the known urgent pointer,
		 * then mark the data stream.  This should not happen
		 * in CLOSE_WAIT, CLOSING, LAST_ACK or TIME_WAIT STATES since
		 * a FIN has been received from the remote side.
		 * In these states we ignore the URG.
		 *
		 * According to RFC961 (Assigned Protocols),
		 * the urgent pointer points to the last octet
		 * of urgent data.  We continue, however,
		 * to consider it to indicate the first octet
		 * of data past the urgent section as the original
		 * spec states (in one of two places).
		 */
		if (SEQ_GT(ti->ti_seq+ti->ti_urp, tp->rcv_up)) {
			tp->rcv_up = ti->ti_seq + ti->ti_urp;
			so->so_urgc =  so->so_rcv.sb_cc +
				(tp->rcv_up - tp->rcv_nxt); /* -1; */
			tp->rcv_up = ti->ti_seq + ti->ti_urp;

		}
	} else
		/*
		 * If no out of band data is expected,
		 * pull receive urgent pointer along
		 * with the receive window.
		 */
		if (SEQ_GT(tp->rcv_nxt, tp->rcv_up))
			tp->rcv_up = tp->rcv_nxt;
dodata:

	/*
	 * Process the segment text, merging it into the TCP sequencing queue,
	 * and arranging for acknowledgment of receipt if necessary.
	 * This process logically involves adjusting tp->rcv_wnd as data
	 * is presented to the user (this happens in tcp_usrreq.c,
	 * case PRU_RCVD).  If a FIN has already been received on this
	 * connection then we just ignore the text.
	 */
	if ((ti->ti_len || (tiflags&TH_FIN)) &&
	    TCPS_HAVERCVDFIN(tp->t_state) == 0) {
		TCP_REASS(tp, ti, m, so, tiflags);
		/*
		 * Note the amount of data that peer has sent into
		 * our window, in order to estimate the sender's
		 * buffer size.
		 */
		len = so->so_rcv.sb_datalen - (tp->rcv_adv - tp->rcv_nxt);
	} else {
		m_free(m);
		tiflags &= ~TH_FIN;
	}

	/*
	 * If FIN is received ACK the FIN and let the user know
	 * that the connection is closing.
	 */
	if (tiflags & TH_FIN) {
		if (TCPS_HAVERCVDFIN(tp->t_state) == 0) {
			/*
			 * If we receive a FIN we can't send more data,
			 * set it SS_FDRAIN
                         * Shutdown the socket if there is no rx data in the
			 * buffer.
			 * soread() is called on completion of shutdown() and
			 * will got to TCPS_LAST_ACK, and use tcp_output()
			 * to send the FIN.
			 */
			sofwdrain(so);

			tp->t_flags |= TF_ACKNOW;
			tp->rcv_nxt++;
		}
		switch (tp->t_state) {

	 	/*
		 * In SYN_RECEIVED and ESTABLISHED STATES
		 * enter the CLOSE_WAIT state.
		 */
		case TCPS_SYN_RECEIVED:
		case TCPS_ESTABLISHED:
		  if(so->so_emu == EMU_CTL)        /* no shutdown on socket */
		    tp->t_state = TCPS_LAST_ACK;
		  else
		    tp->t_state = TCPS_CLOSE_WAIT;
		  break;

	 	/*
		 * If still in FIN_WAIT_1 STATE FIN has not been acked so
		 * enter the CLOSING state.
		 */
		case TCPS_FIN_WAIT_1:
			tp->t_state = TCPS_CLOSING;
			break;

	 	/*
		 * In FIN_WAIT_2 state enter the TIME_WAIT state,
		 * starting the time-wait timer, turning off the other
		 * standard timers.
		 */
		case TCPS_FIN_WAIT_2:
			tp->t_state = TCPS_TIME_WAIT;
			tcp_canceltimers(tp);
			tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;
			break;

		/*
		 * In TIME_WAIT state restart the 2 MSL time_wait timer.
		 */
		case TCPS_TIME_WAIT:
			tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;
			break;
		}
	}

	/*
	 * If this is a small packet, then ACK now - with Nagel
	 *      congestion avoidance sender won't send more until
	 *      he gets an ACK.
	 *
	 * See above.
	 */
	if (ti->ti_len && (unsigned)ti->ti_len <= 5 &&
	    ((struct tcpiphdr_2 *)ti)->first_char == (char)27) {
		tp->t_flags |= TF_ACKNOW;
	}

	/*
	 * Return any desired output.
	 */
	if (needoutput || (tp->t_flags & TF_ACKNOW)) {
		(void) tcp_output(tp);
	}
	return;

dropafterack:
	/*
	 * Generate an ACK dropping incoming segment if it occupies
	 * sequence space, where the ACK reflects our state.
	 */
	if (tiflags & TH_RST)
		goto drop;
	m_freem(m);
	tp->t_flags |= TF_ACKNOW;
	(void) tcp_output(tp);
	return;

dropwithreset:
	/* reuses m if m!=NULL, m_free() unnecessary */
	if (tiflags & TH_ACK)
		tcp_respond(tp, ti, m, (tcp_seq)0, ti->ti_ack, TH_RST);
	else {
		if (tiflags & TH_SYN) ti->ti_len++;
		tcp_respond(tp, ti, m, ti->ti_seq+ti->ti_len, (tcp_seq)0,
		    TH_RST|TH_ACK);
	}

	return;

drop:
	/*
	 * Drop space held by incoming segment and return.
	 */
	m_free(m);

	return;
}
コード例 #7
0
ファイル: ip_icmp.c プロジェクト: 0day-ci/qemu
void
icmp_send_error(struct mbuf *msrc, u_char type, u_char code, int minsize,
           const char *message)
{
  unsigned hlen, shlen, s_ip_len;
  register struct ip *ip;
  register struct icmp *icp;
  register struct mbuf *m;

  DEBUG_CALL("icmp_send_error");
  DEBUG_ARG("msrc = %p", msrc);
  DEBUG_ARG("msrc_len = %d", msrc->m_len);

  if(type!=ICMP_UNREACH && type!=ICMP_TIMXCEED) goto end_error;

  /* check msrc */
  if(!msrc) goto end_error;
  ip = mtod(msrc, struct ip *);
#ifdef DEBUG
  { char bufa[20], bufb[20];
    strcpy(bufa, inet_ntoa(ip->ip_src));
    strcpy(bufb, inet_ntoa(ip->ip_dst));
    DEBUG_MISC((dfd, " %.16s to %.16s\n", bufa, bufb));
  }
#endif
  if(ip->ip_off & IP_OFFMASK) goto end_error;    /* Only reply to fragment 0 */

  /* Do not reply to source-only IPs */
  if ((ip->ip_src.s_addr & htonl(~(0xf << 28))) == 0) {
      goto end_error;
  }

  shlen=ip->ip_hl << 2;
  s_ip_len=ip->ip_len;
  if(ip->ip_p == IPPROTO_ICMP) {
    icp = (struct icmp *)((char *)ip + shlen);
    /*
     *	Assume any unknown ICMP type is an error. This isn't
     *	specified by the RFC, but think about it..
     */
    if(icp->icmp_type>18 || icmp_flush[icp->icmp_type]) goto end_error;
  }

  /* make a copy */
  m = m_get(msrc->slirp);
  if (!m) {
      goto end_error;
  }

  { int new_m_size;
    new_m_size=sizeof(struct ip )+ICMP_MINLEN+msrc->m_len+ICMP_MAXDATALEN;
    if(new_m_size>m->m_size) m_inc(m, new_m_size);
  }
  memcpy(m->m_data, msrc->m_data, msrc->m_len);
  m->m_len = msrc->m_len;                        /* copy msrc to m */

  /* make the header of the reply packet */
  ip  = mtod(m, struct ip *);
  hlen= sizeof(struct ip );     /* no options in reply */

  /* fill in icmp */
  m->m_data += hlen;
  m->m_len -= hlen;

  icp = mtod(m, struct icmp *);

  if(minsize) s_ip_len=shlen+ICMP_MINLEN;   /* return header+8b only */
  else if(s_ip_len>ICMP_MAXDATALEN)         /* maximum size */
    s_ip_len=ICMP_MAXDATALEN;

  m->m_len=ICMP_MINLEN+s_ip_len;        /* 8 bytes ICMP header */

  /* min. size = 8+sizeof(struct ip)+8 */

  icp->icmp_type = type;
  icp->icmp_code = code;
  icp->icmp_id = 0;
  icp->icmp_seq = 0;

  memcpy(&icp->icmp_ip, msrc->m_data, s_ip_len);   /* report the ip packet */
  HTONS(icp->icmp_ip.ip_len);
  HTONS(icp->icmp_ip.ip_id);
  HTONS(icp->icmp_ip.ip_off);

#ifdef DEBUG
  if(message) {           /* DEBUG : append message to ICMP packet */
    int message_len;
    char *cpnt;
    message_len=strlen(message);
    if(message_len>ICMP_MAXDATALEN) message_len=ICMP_MAXDATALEN;
    cpnt=(char *)m->m_data+m->m_len;
    memcpy(cpnt, message, message_len);
    m->m_len+=message_len;
  }
#endif

  icp->icmp_cksum = 0;
  icp->icmp_cksum = cksum(m, m->m_len);

  m->m_data -= hlen;
  m->m_len += hlen;

  /* fill in ip */
  ip->ip_hl = hlen >> 2;
  ip->ip_len = m->m_len;

  ip->ip_tos=((ip->ip_tos & 0x1E) | 0xC0);  /* high priority for errors */

  ip->ip_ttl = MAXTTL;
  ip->ip_p = IPPROTO_ICMP;
  ip->ip_dst = ip->ip_src;    /* ip addresses */
  ip->ip_src = m->slirp->vhost_addr;

  (void ) ip_output((struct socket *)NULL, m);

end_error:
  return;
}
コード例 #8
0
ファイル: sr_handler.c プロジェクト: tmonca/router
int handle_ip_pkt(struct sr_instance* sr, uint8_t* Pkt, char* interface, unsigned int len, uint8_t srcMAC[]) {

    //actually I have to pass in a uint8_t* packet not an sr_ip_pkt...

    /*
     Extract the IP header
     Header actions:
     1) check the IP checksum
     -> discard if wrong
     2) check if TTL expired
     -> send ICMP type 11 (0)
     3) check if it is our message
     -> if yes jump to "OURS:"
     Not Ours:
     1) Find the next hop in rtable
     2) Decrement TTL, recalculate Checksum
     3) Assemble new packet
     4) Send on correct interface

     OURS:
     1) Check type of packet
     -> ICMP
     -> UDP/TCP

     ICMP:
     1) Check type
     2) respond as appropriate

     UDP/TCP
     1) Pass up the stack

     */
    assert(Pkt);
    assert(sr);
    assert(interface);

    //struct sr_router* subsystem = (struct sr_router*)sr_get_subsystem(sr);
    struct sr_vns_if* myIntf = sr_get_interface(sr, interface);
    uint32_t myIP = myIntf->ip;

    struct ip* pktHdr = (struct ip*)Pkt;
    uint8_t* payload = (uint8_t*)malloc_or_die(len - 20);
    uint8_t* ptr = Pkt + 20;
    memcpy(payload, ptr, len-20);

    uint32_t originIP = pktHdr->ip_src.s_addr;

    //first thing is to update ARP - no point wasiting useful information is there!
    time_t now = time(NULL);
    int checkArp;
    checkArp = find_and_update(sr, originIP, srcMAC, now);

    if(pktHdr->ip_hl != 5) {
        //means there were IP options so unerachable (host or network?)
        printf("@@@@@@@@@@@@@@@@@@@@@@@@@@      IP hdr length was %u. Should have been 5 (e.g. 20 bytes)\n", pktHdr->ip_hl);
        uint8_t* data = (uint8_t*)malloc_or_die(28);
        memcpy(data, Pkt, 28);
        int tmp;
        tmp = create_ICMP_pkt(sr, interface, originIP, 3, 1, 0, 0, data, 28);
        return -3;
    }

    if(cksum((uint8_t*)pktHdr, 20)) {
        printf("@@@@@@@@@@@@@@@@@@@@@@    CHECKSUM 0x%hx WAS INVALID SO WE WILL DROP THE PACKET\n", pktHdr->ip_sum);
        return -2;
    }

    if(pktHdr->ip_ttl < 2) {
        printf("@@@@@@@@@@@@@@@@@@@@@@    TTL has expired so we will send back an ICMP\n");
        //get the data (IP hdr + 8 bytes of packet)
        uint8_t* data = (uint8_t*)malloc_or_die(28);
        memcpy(data, Pkt, 28);
        int tmp;
        tmp = create_ICMP_pkt(sr, interface, originIP, 11, 0, 0, 0, data, 28);
        return -1;
    }

    if(check_my_interface(sr, (uint32_t)pktHdr->ip_dst.s_addr)) {

        // printf("This is my packet so I will process it\n");

        switch(pktHdr->ip_p) {
        case IPPROTO_ICMP:
            ;
            //printf("\nThis is an IP ICMP packet of length %d\n", len);
            // printf("After removing the IP header we are left with %d bytes\n", datalen);
            int datalen = len - sizeof(struct ip);
            uint8_t* ICMP = (uint8_t*) malloc_or_die(datalen);
            //ICMP = array_cpy(Pkt->payload, datalen);
            memcpy(ICMP, payload, datalen);
            int tmp;
            tmp = process_ICMP_pkt(sr, interface, originIP, ICMP, datalen);
            return tmp;

        case IPPROTO_TCP:
            printf("TCP packet sent up the stack\n");
            sr_transport_input(Pkt);
            return 1;
        default:
            return 0;
        }
    }
    else {
        //printf("**********  Not my packet, so I will forward it\n");
        return 3;
    }
    return 0;
}
コード例 #9
0
ファイル: udp.c プロジェクト: AbnerChang/RiscVQemuPcat
/* m->m_data  points at ip packet header
 * m->m_len   length ip packet
 * ip->ip_len length data (IPDU)
 */
void
udp_input(register struct mbuf *m, int iphlen)
{
	Slirp *slirp = m->slirp;
	register struct ip *ip;
	register struct udphdr *uh;
	int len;
	struct ip save_ip;
	struct socket *so;

	DEBUG_CALL("udp_input");
	DEBUG_ARG("m = %lx", (long)m);
	DEBUG_ARG("iphlen = %d", iphlen);

	/*
	 * Strip IP options, if any; should skip this,
	 * make available to user, and use on returned packets,
	 * but we don't yet have a way to check the checksum
	 * with options still present.
	 */
	if(iphlen > sizeof(struct ip)) {
		ip_stripoptions(m, (struct mbuf *)0);
		iphlen = sizeof(struct ip);
	}

	/*
	 * Get IP and UDP header together in first mbuf.
	 */
	ip = mtod(m, struct ip *);
	uh = (struct udphdr *)((caddr_t)ip + iphlen);

	/*
	 * Make mbuf data length reflect UDP length.
	 * If not enough data to reflect UDP length, drop.
	 */
	len = ntohs((uint16_t)uh->uh_ulen);

	if (ip->ip_len != len) {
		if (len > ip->ip_len) {
			goto bad;
		}
		m_adj(m, len - ip->ip_len);
		ip->ip_len = len;
	}

	/*
	 * Save a copy of the IP header in case we want restore it
	 * for sending an ICMP error message in response.
	 */
	save_ip = *ip;
	save_ip.ip_len+= iphlen;         /* tcp_input subtracts this */

	/*
	 * Checksum extended UDP header and data.
	 */
	if (uh->uh_sum) {
      memset(&((struct ipovly *)ip)->ih_mbuf, 0, sizeof(struct mbuf_ptr));
	  ((struct ipovly *)ip)->ih_x1 = 0;
	  ((struct ipovly *)ip)->ih_len = uh->uh_ulen;
	  if(cksum(m, len + sizeof(struct ip))) {
	    goto bad;
	  }
	}

        /*
         *  handle DHCP/BOOTP
         */
        if (ntohs(uh->uh_dport) == BOOTP_SERVER &&
            (ip->ip_dst.s_addr == slirp->vhost_addr.s_addr ||
             ip->ip_dst.s_addr == 0xffffffff)) {
                bootp_input(m);
                goto bad;
            }

        /*
         *  handle TFTP
         */
        if (ntohs(uh->uh_dport) == TFTP_SERVER &&
            ip->ip_dst.s_addr == slirp->vhost_addr.s_addr) {
            tftp_input(m);
            goto bad;
        }

        if (slirp->restricted) {
            goto bad;
        }

	/*
	 * Locate pcb for datagram.
	 */
	so = slirp->udp_last_so;
	if (so->so_lport != uh->uh_sport ||
	    so->so_laddr.s_addr != ip->ip_src.s_addr) {
		struct socket *tmp;

		for (tmp = slirp->udb.so_next; tmp != &slirp->udb;
		     tmp = tmp->so_next) {
			if (tmp->so_lport == uh->uh_sport &&
			    tmp->so_laddr.s_addr == ip->ip_src.s_addr) {
				so = tmp;
				break;
			}
		}
		if (tmp == &slirp->udb) {
		  so = NULL;
		} else {
		  slirp->udp_last_so = so;
		}
	}

	if (so == NULL) {
	  /*
	   * If there's no socket for this packet,
	   * create one
	   */
	  so = socreate(slirp);
	  if (!so) {
	      goto bad;
	  }
	  if(udp_attach(so) == -1) {
	    DEBUG_MISC((dfd," udp_attach errno = %d-%s\n",
			errno,strerror(errno)));
	    sofree(so);
	    goto bad;
	  }

	  /*
	   * Setup fields
	   */
	  so->so_laddr = ip->ip_src;
	  so->so_lport = uh->uh_sport;

	  if ((so->so_iptos = udp_tos(so)) == 0)
	    so->so_iptos = ip->ip_tos;

	  /*
	   * XXXXX Here, check if it's in udpexec_list,
	   * and if it is, do the fork_exec() etc.
	   */
	}

        so->so_faddr = ip->ip_dst; /* XXX */
        so->so_fport = uh->uh_dport; /* XXX */

	iphlen += sizeof(struct udphdr);
	m->m_len -= iphlen;
	m->m_data += iphlen;

	/*
	 * Now we sendto() the packet.
	 */
	if(sosendto(so,m) == -1) {
	  m->m_len += iphlen;
	  m->m_data -= iphlen;
	  *ip=save_ip;
	  DEBUG_MISC((dfd,"udp tx errno = %d-%s\n",errno,strerror(errno)));
	  icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno));
	}

	m_free(so->so_m);   /* used for ICMP if error on sorecvfrom */

	/* restore the orig mbuf packet */
	m->m_len += iphlen;
	m->m_data -= iphlen;
	*ip=save_ip;
	so->so_m=m;         /* ICMP backup */

	return;
bad:
	m_free(m);
}
コード例 #10
0
ファイル: sr_handler.c プロジェクト: tmonca/router
int create_ICMP_pkt(struct sr_instance* sr, char* interface, uint32_t dstIP, uint8_t type, uint8_t code, uint16_t field1, uint16_t field2, uint8_t* data, unsigned int datalen) {

    assert(data);
    assert(sr);
    assert(interface);
#if 0
    printf("********* at %s    Payload is 0x ", __func__);
    int i;
    for(i = 0; i < datalen; i++) {
        printf("%x", data[i]);
    }
    printf("\n");
#endif
    int len, rtn;
    switch (type) {

    case 3:
    case 11:
        len = 8 + sizeof(struct ip) + 8; //8byte ICMP hdr, 20byte IP hdr, 8byte IP data
        break; //for now to keep it easy to follow code
    case 0:
        len = sizeof(struct sr_icmp_hdr) + datalen; // 8byte ICMP hdr, data as in echo rqst allowing for ID and sequence in data
        break;
    default:
        len = 8; //this might not be helpful...

    }
    //printf("********   We're assigning %d bytes of memory\n", len);
    struct sr_icmp_hdr* packet = (struct sr_icmp_hdr*) malloc_or_die(sizeof(struct sr_icmp_hdr));

    // now they all get some std entries

    packet->type = type;
    packet->code = code;
    packet->checksum = 0x0; // needs to be 0'ed before calculation
    packet->field1 = field1;
    packet->field2 = field2;

    //and now we fill the other entries as appropriate

    // printf("********* at %s    After conversion to packet \n ", __func__);
    // print_icmp_pkt(packet);

    //finally we can add a checksum
    //uint16_t check = cksum((uint8_t*)packet, len);   // The problem is I can't do this cast apparently

    //printf("\n\n********* at %s    transferring  0x \n", __func__);
    //print_icmp_pkt(packet);

    uint8_t* Pkt = array_join(packet, data, sizeof(struct sr_icmp_hdr), datalen);

    //memcpy(Pkt, packet, len);
    uint16_t check = cksum(Pkt, len);
    // printf("\n\n &&&&&&&&&&   the checksum is calculated as %hu\n", check);

    ((struct sr_icmp_hdr*)Pkt)->checksum = check;

    // Pkt = icmp_to_raw(packet, len);

    //so we still have the issue of how to insert the checksum


    rtn = make_and_send(sr, interface, dstIP, Pkt, len, IPPROTO_ICMP);

    if(rtn == 2) {
        printf("*************    ICMP pkt, ARP request sent\n");
        return 2;
    }
    else if (rtn == 1) {
        printf("**************    ICMP packet, we had an ARP entry\n");
        return 2;
    }
    else {
        return 0;
    }
    return 0;
}
コード例 #11
0
ファイル: sr_handler.c プロジェクト: tmonca/router
int make_and_send(struct sr_instance* sr, char * interface, uint32_t dstIP, uint8_t* payld, unsigned int len, uint8_t proto) {
    assert(payld);
    assert(sr);
    assert(interface);
#if 0
    printf("********* at %s    Payload is 0x ", __func__);
    int i ;
    for(i = 0; i < len; i++) {
        printf("%hhx ", payld[i]);
    }
    printf("\n");
#endif

    /* doing some testing

     */


    printf("\n*************************\n\n");

    print_ip(dstIP);

    printf("\n\n**************************\n\n");
    char* test;
    test = longest_prefix(sr, ntohl(dstIP));

    printf("\n\n**************************\n");

    struct sr_vns_if* myIntf = sr_get_interface(sr, interface);

    struct ip* ipHdr = (struct ip*) malloc_or_die(20);

    int rtn;

    struct in_addr src;
    struct in_addr dst;
    src.s_addr = myIntf->ip;
    dst.s_addr = dstIP;

    //fill in ip hdr

    //How do we set version and hl?
    ipHdr->ip_hl = 5;
    ipHdr->ip_v = 4;

    ipHdr->ip_tos = 0x0;
    ipHdr->ip_len = htons(len + 20);
    ipHdr->ip_id = htons(1638);
    ipHdr->ip_off = 0x0;
    ipHdr->ip_ttl = 64;
    ipHdr->ip_p = proto;   // probably always IPPROTO_ICMP for the router
    ipHdr->ip_sum = 0x0;
    ipHdr->ip_src = src;
    ipHdr->ip_dst = dst;

    uint16_t check = cksum((uint8_t*)ipHdr, 20);
    ipHdr->ip_sum = check;

    //Then we make an ethernet payload

    //   Tracking back from sr_arp.c:298
    //  we don't have the valid ICMP here even so go back further

    uint8_t* packet = (uint8_t*) malloc_or_die(len + 20);
    packet = array_join(ipHdr, payld, 20, len);

#if 0
    printf("\n");

    for(i = 0; i < len + 20; i++) {
        printf("%hhx ", packet[i]);
    }
    //printf("\n*************      %s     ******************\n", __func__);

#endif
    rtn = arp_lookup(sr, interface, packet, dstIP, (len + 20));

    return rtn;

}
コード例 #12
0
ファイル: egp.c プロジェクト: gisti/t50
        sizeof(struct egp_hdr)  +
        sizeof(struct egp_acq_hdr));

  /*
   * @nbrito -- Tue Jan 18 11:09:34 BRST 2011
   * XXX Have to work a little bit more deeply in packet building.
   * XXX Checking EGP Type and building appropriate header.
   */
  /* EGP Header structure making a pointer to Packet. */
  egp           = (struct egp_hdr *)((void *)ip + sizeof(struct iphdr) + greoptlen);
  egp->version  = EGPVERSION;
  egp->type     = co->egp.type;
  egp->code     = co->egp.code;
  egp->status   = co->egp.status;
  egp->as       = __RND(co->egp.as);
  egp->sequence = __RND(co->egp.sequence);
  egp->check    = 0;

  /* EGP Acquire Header structure. */
  egp_acq        = (struct egp_acq_hdr *)((void *)egp + sizeof(struct egp_hdr));
  egp_acq->hello = __RND(co->egp.hello);
  egp_acq->poll  = __RND(co->egp.poll);

  /* Computing the checksum. */
  egp->check    = co->bogus_csum ? random() : 
    cksum(egp, sizeof(struct egp_hdr) + sizeof(struct egp_acq_hdr));

  /* GRE Encapsulation takes place. */
  gre_checksum(packet, co, *size);
}
コード例 #13
0
ファイル: udp.c プロジェクト: 0x0mar/t50
  gre_ip = gre_encapsulation(packet, co,
    sizeof(struct iphdr) + sizeof(struct udphdr));

  /* UDP Header structure making a pointer to  IP Header structure. */
  udp         = (struct udphdr *)((void *)ip + sizeof(struct iphdr) + greoptlen);
  udp->source = htons(IPPORT_RND(co->source));
  udp->dest   = htons(IPPORT_RND(co->dest));
  udp->len    = htons(sizeof(struct udphdr));
  udp->check  = 0;    /* needed 'cause of cksum(), below! */

  /* Fill PSEUDO Header structure. */
  pseudo           = (struct psdhdr *)((void *)udp + sizeof(struct udphdr));
  pseudo->saddr    = co->encapsulated ? gre_ip->saddr : ip->saddr;
  pseudo->daddr    = co->encapsulated ? gre_ip->daddr : ip->daddr;
  pseudo->zero     = 0;
  pseudo->protocol = co->ip.protocol;
  pseudo->len      = htons(sizeof(struct udphdr));

  /* Computing the checksum. */
  udp->check  = co->bogus_csum ? RANDOM() :
    cksum(udp, sizeof(struct udphdr) + sizeof(struct psdhdr));

#ifdef DUMP_DATA
  dump_udp(fdebug, udp);
  dump_psdhdr(fdebug, pseudo);
#endif

  gre_checksum(packet, co, *size);
}
コード例 #14
0
ファイル: ip_output.c プロジェクト: 0-14N/NDroid
/*
 * IP output.  The packet in mbuf chain m contains a skeletal IP
 * header (with len, off, ttl, proto, tos, src, dst).
 * The mbuf chain containing the packet will be freed.
 * The mbuf opt, if present, will not be freed.
 */
int
ip_output(struct socket *so, struct mbuf *m0)
{
	register struct ip *ip;
	register struct mbuf *m = m0;
	register int hlen = sizeof(struct ip );
	int len, off, error = 0;

	DEBUG_CALL("ip_output");
	DEBUG_ARG("so = %lx", (long)so);
	DEBUG_ARG("m0 = %lx", (long)m0);

	/* We do no options */
/*	if (opt) {
 *		m = ip_insertoptions(m, opt, &len);
 *		hlen = len;
 *	}
 */
	ip = mtod(m, struct ip *);
	/*
	 * Fill in IP header.
	 */
	ip->ip_v = IPVERSION;
	ip->ip_off &= IP_DF;
	ip->ip_id = htons(ip_id++);
	ip->ip_hl = hlen >> 2;
	STAT(ipstat.ips_localout++);

	/*
	 * Verify that we have any chance at all of being able to queue
	 *      the packet or packet fragments
	 */
	/* XXX Hmmm... */
/*	if (if_queued > IF_THRESH && towrite <= 0) {
 *		error = ENOBUFS;
 *		goto bad;
 *	}
 */

	/*
	 * If small enough for interface, can just send directly.
	 */
	if ((u_int16_t)ip->ip_len <= IF_MTU) {
		ip->ip_len = htons((u_int16_t)ip->ip_len);
		ip->ip_off = htons((u_int16_t)ip->ip_off);
		ip->ip_sum = 0;
		ip->ip_sum = cksum(m, hlen);

		if_output(so, m);
		goto done;
	}

	/*
	 * Too large for interface; fragment if possible.
	 * Must be able to put at least 8 bytes per fragment.
	 */
	if (ip->ip_off & IP_DF) {
		error = -1;
		STAT(ipstat.ips_cantfrag++);
		goto bad;
	}

	len = (IF_MTU - hlen) &~ 7;       /* ip databytes per packet */
	if (len < 8) {
		error = -1;
		goto bad;
	}

    {
	int mhlen, firstlen = len;
	struct mbuf **mnext = &m->m_nextpkt;

	/*
	 * Loop through length of segment after first fragment,
	 * make new header and copy data of each part and link onto chain.
	 */
	m0 = m;
	mhlen = sizeof (struct ip);
	for (off = hlen + len; off < (u_int16_t)ip->ip_len; off += len) {
	  register struct ip *mhip;
	  m = m_get();
          if (m == NULL) {
	    error = -1;
	    STAT(ipstat.ips_odropped++);
	    goto sendorfree;
	  }
	  m->m_data += IF_MAXLINKHDR;
	  mhip = mtod(m, struct ip *);
	  *mhip = *ip;

		/* No options */
/*		if (hlen > sizeof (struct ip)) {
 *			mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip);
 *			mhip->ip_hl = mhlen >> 2;
 *		}
 */
	  m->m_len = mhlen;
	  mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF);
	  if (ip->ip_off & IP_MF)
	    mhip->ip_off |= IP_MF;
	  if (off + len >= (u_int16_t)ip->ip_len)
	    len = (u_int16_t)ip->ip_len - off;
	  else
	    mhip->ip_off |= IP_MF;
	  mhip->ip_len = htons((u_int16_t)(len + mhlen));

	  if (m_copy(m, m0, off, len) < 0) {
	    error = -1;
	    goto sendorfree;
	  }

	  mhip->ip_off = htons((u_int16_t)mhip->ip_off);
	  mhip->ip_sum = 0;
	  mhip->ip_sum = cksum(m, mhlen);
	  *mnext = m;
	  mnext = &m->m_nextpkt;
	  STAT(ipstat.ips_ofragments++);
	}
	/*
	 * Update first fragment by trimming what's been copied out
	 * and updating header, then send each fragment (in order).
	 */
	m = m0;
	m_adj(m, hlen + firstlen - (u_int16_t)ip->ip_len);
	ip->ip_len = htons((u_int16_t)m->m_len);
	ip->ip_off = htons((u_int16_t)(ip->ip_off | IP_MF));
	ip->ip_sum = 0;
	ip->ip_sum = cksum(m, hlen);
sendorfree:
	for (m = m0; m; m = m0) {
		m0 = m->m_nextpkt;
                m->m_nextpkt = NULL;
		if (error == 0)
			if_output(so, m);
		else
			m_freem(m);
	}

	if (error == 0)
		STAT(ipstat.ips_fragmented++);
    }

done:
	return (error);

bad:
	m_freem(m0);
	goto done;
}
コード例 #15
0
ファイル: sr_helper.c プロジェクト: petergrabowski/networks
int handle_ip_packet(struct sr_instance * sr, uint8_t * packet, unsigned int len ) {


      sr_ip_hdr_t *iphdr = (sr_ip_hdr_t *)(packet + sizeof(sr_ethernet_hdr_t));

      /* validate checksum. */
      uint16_t checksum;

      checksum = cksum(iphdr, sizeof(*iphdr));
      if (checksum != 0xffff) {

            return -1;
      } 


      
      uint8_t * newpacket_for_ip = (uint8_t *) malloc(len);
      memcpy(newpacket_for_ip, packet, len);
      sr_ip_hdr_t *new_iphdr = (sr_ip_hdr_t *)(newpacket_for_ip + sizeof(sr_ethernet_hdr_t));

      /* Decrement the TTL by 1, and recompute the packet 
      checksum over the modified header. */

      /* decrement ttl */
      new_iphdr->ip_ttl--;

      if (new_iphdr->ip_ttl <= 0) {
          /* check ttl, less than zero */
            send_icmp_message(sr,packet, 11, 0);
            return -1;
      }

      /* update checksum. */
      new_iphdr->ip_sum = 0;
      checksum = cksum(new_iphdr, sizeof(*new_iphdr));
      new_iphdr->ip_sum = checksum;
      checksum = cksum(new_iphdr, sizeof(*new_iphdr));

      struct sr_if* assoc_iface = validate_ip(sr->if_list, iphdr->ip_dst);
      if (assoc_iface) {
            /*it's destined to one of our IPs */
            /* ICMP */
            uint8_t ip_proto = ip_protocol(packet + sizeof(sr_ethernet_hdr_t));
            if (ip_proto == ip_protocol_icmp) { 

                
                  int minlength = sizeof(sr_icmp_hdr_t) + sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t);
                  if (len < minlength){
                  
                        return -1;
                  }

                  struct sr_icmp_hdr * icmp_hdr =  (struct sr_icmp_hdr *) (packet + sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t));

                  if(icmp_hdr->icmp_type == 8){
                        /* is an echo request */

                        int res;
                        res = make_echo_request(&newpacket_for_ip, len);

                        if (res == -1){
                              
                              return -1;
                        }
                  }
                  /* end ICMP */
            } else {
                  /* got a udp payload to a rounter interface */
                  int res;
                  res = send_icmp_message(sr, packet, 3,  3);
                  if (res == -1){
                        
                        return -1;
                  }
            }
      }


      /* Find out which entry in the routing table has 
      the longest prefix match with the 
      destination IP address. */
      struct sr_rt* best_rt = find_best_rt(sr->routing_table,  ntohl(new_iphdr->ip_dst));         
      if (!best_rt) {
            /* didn't find an interface, send an ICMP message type 3 
            code 0, also if there are any errors above */
            int res = send_icmp_message(sr, packet, 3,  0);
            if (res == -1){
                 
                  return -1;
            }
            
            return 0;
      }

      /* found an interface */

      struct sr_if * best_iface = sr_get_interface(sr, best_rt->interface);
      if (!best_iface){
           
            return -1;
      }
      struct sr_arpentry * forward_arp_entry = sr_arpcache_lookup(&(sr->cache), best_rt->gw.s_addr);
      
      struct sr_ethernet_hdr * new_ether_hdr = (struct sr_ethernet_hdr * ) newpacket_for_ip; 

      /* ethernet -- update the source address */
      memcpy(new_ether_hdr->ether_shost, best_iface->addr,  ETHER_ADDR_LEN);

      if (forward_arp_entry) {
            /* we have a MAC address */
           

            /* update packet */
            /* ethernet -- set the dest address */
            memcpy(new_ether_hdr->ether_dhost, forward_arp_entry->mac, ETHER_ADDR_LEN);

            /* send packet using correct interface */
            int res = 0; 

            
            res = sr_send_packet(sr, newpacket_for_ip, len, best_rt->interface);

            if (res != 0) {
                 
                  return -1;
            }

            free(forward_arp_entry);
      } else {
            /* we dont have a MAC address, add to arp queue */
            
            struct sr_arpreq * arpreq;
            arpreq = sr_arpcache_queuereq(&(sr->cache), best_rt->gw.s_addr, newpacket_for_ip, 
                  len, best_rt->interface );
            if (!arpreq){
                 
                  return -1;
            }
            uint32_t ip, dest;
           
            ip = ntohl(best_iface->ip);

            dest = ntohl(best_rt->dest.s_addr);
            sr_handle_arp_req(sr, arpreq); 
      } 
      return 0;      
}
コード例 #16
0
ファイル: mkboot.c プロジェクト: ajinkya93/OpenBSD
int
putfile(char *from_file, int to)
{
	struct exec ex;
	register int n, total;
	char buf[2048];
	int from, check_sum = 0;
	struct lif_load load;

	if ((from = open(from_file, O_RDONLY)) < 0)
		err(1, "%s", from_file);

	n = read(from, &ex, sizeof(ex));
	if (n != sizeof(ex))
		err(1, "%s: reading file header", from_file);

	entry = ex.a_entry;
	if (N_GETMAGIC(ex) == OMAGIC || N_GETMAGIC(ex) == NMAGIC)
		entry += sizeof(ex);
	else if (IS_ELF(*(Elf32_Ehdr *)&ex)) {
		Elf32_Ehdr elf_header;
		Elf32_Phdr *elf_segments;
		int i, header_count, memory_needed, elf_load_image_segment;

		(void) lseek(from, 0, SEEK_SET);
		n = read(from, &elf_header, sizeof(elf_header));
		if (n != sizeof (elf_header))
			err(1, "%s: reading ELF header", from_file);
		header_count = ntohs(elf_header.e_phnum);
		elf_segments = reallocarray(NULL, header_count,
		    sizeof(*elf_segments));
		if (elf_segments == NULL)
			err(1, "malloc");
		memory_needed = header_count * sizeof(*elf_segments);
		(void) lseek(from, ntohl(elf_header.e_phoff), SEEK_SET);
		n = read(from, elf_segments, memory_needed);
		if (n != memory_needed)
			err(1, "%s: reading ELF segments", from_file);
		elf_load_image_segment = -1;
		for (i = 0; i < header_count; i++) {
			if (elf_segments[i].p_filesz &&
			    ntohl(elf_segments[i].p_flags) & PF_X) {
				if (elf_load_image_segment != -1)
					errx(1, "%s: more than one ELF program segment", from_file);
				elf_load_image_segment = i;
			}
		}
		if (elf_load_image_segment == -1)
			errx(1, "%s: no suitable ELF program segment", from_file);
		entry = ntohl(elf_header.e_entry) +
			ntohl(elf_segments[elf_load_image_segment].p_offset) -
			ntohl(elf_segments[elf_load_image_segment].p_vaddr);
		free(elf_segments);
	} else if (*(u_char *)&ex == 0x1f && ((u_char *)&ex)[1] == 0x8b) {
		entry = 0;
	} else
		errx(1, "%s: bad magic number", from_file);

	entry += sizeof(load);
	lseek(to, sizeof(load), SEEK_CUR);
	total = 0;
	n = sizeof(buf) - sizeof(load);
	/* copy the whole file */
	for (lseek(from, 0, 0); ; n = sizeof(buf)) {
		bzero(buf, sizeof(buf));
		if ((n = read(from, buf, n)) < 0)
			err(1, "%s", from_file);
		else if (n == 0)
			break;

		if (write(to, buf, n) != n)
			err(1, "%s", to_file);

		total += n;
		check_sum = cksum(check_sum, (int *)buf, n);
	}

	/* load header */
	load.address = htobe32(loadpoint + sizeof(load));
	load.count = htobe32(4 + total);
	check_sum = cksum(check_sum, (int *)&load, sizeof(load));

	if (verbose)
		warnx("wrote %d bytes of file \'%s\'", total, from_file);

	total += sizeof(load);
	/* insert the header */
	lseek(to, -total, SEEK_CUR);
	if (write(to, &load, sizeof(load)) != sizeof(load))
		err(1, "%s", to_file);
	lseek(to, total - sizeof(load), SEEK_CUR);

	bzero(buf, sizeof(buf));
	/* pad to int */
	n = sizeof(int) - total % sizeof(int);
	if (total % sizeof(int)) {
		if (write(to, buf, n) != n)
			err(1, "%s", to_file);
		else
			total += n;
	}

	/* pad to the blocksize */
	n = sizeof(buf) - total % sizeof(buf);

	if (n < sizeof(int)) {
		n += sizeof(buf);
		total += sizeof(buf);
	} else
		total += n;

	/* TODO should pad here to the 65k boundary for tape boot */

	if (verbose)
		warnx("checksum is 0x%08x", -check_sum);

	check_sum = htobe32(-check_sum);
	if (write(to, &check_sum, sizeof(int)) != sizeof(int))
		err(1, "%s", to_file);

	n -= sizeof(int);

	if (write(to, buf, n) != n)
		err(1, "%s", to_file);

	if (close(from) < 0 )
		err(1, "%s", from_file);

	return total;
}
コード例 #17
0
ファイル: sr_helper.c プロジェクト: petergrabowski/networks
int send_icmp_message(struct sr_instance * sr, uint8_t * packet, 
      uint8_t icmp_type,  uint8_t icmp_code) {

      int res, size, icmp_len;

      if (icmp_type == 3){
            size = sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t) + sizeof(sr_icmp_hdr_t);
      } else if (icmp_type == 11) {
            size = sizeof(sr_ethernet_hdr_t) + 2 * sizeof(sr_ip_hdr_t) + sizeof(sr_icmp_t3_hdr_t) + 8;
      } else {
           
            return -1;

      }
      uint8_t  temp[ETHER_ADDR_LEN]; 
      uint8_t icmp_message[size];
      memcpy(icmp_message, packet, size);

      icmp_len = size - ( sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t));

      struct sr_ethernet_hdr * ether_hdr = (struct sr_ethernet_hdr * ) icmp_message; 
      struct sr_ip_hdr *ip_hdr = (struct sr_ip_hdr *)(icmp_message + sizeof(sr_ethernet_hdr_t));
      struct sr_ip_hdr *old_ip_hdr = (struct sr_ip_hdr *)(packet + sizeof(sr_ethernet_hdr_t));
      struct sr_icmp_hdr * icmp_hdr = (struct sr_icmp_hdr *) (icmp_message + sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t));

      /* swap source and host MAC address */
      memcpy(temp, ether_hdr->ether_dhost, ETHER_ADDR_LEN);
      memcpy(ether_hdr->ether_dhost, ether_hdr->ether_shost, ETHER_ADDR_LEN);
      memcpy(ether_hdr->ether_shost, temp, ETHER_ADDR_LEN);

      if (icmp_type == 11) {
            struct sr_icmp_t3_hdr * t3_hdr = (struct sr_icmp_t3_hdr *) icmp_hdr;
            memcpy(t3_hdr->data, old_ip_hdr, ICMP_DATA_SIZE);
            t3_hdr->next_mtu = 1500;
      }


      /* updte icmp info */
      uint32_t checksum;
      icmp_hdr->icmp_type = icmp_type;
      icmp_hdr->icmp_code = icmp_code;
      icmp_hdr->icmp_sum = 0;
      checksum = cksum(icmp_hdr, icmp_len);
      icmp_hdr->icmp_sum = checksum;

      /* update IP info */
      ip_hdr->ip_tos = 0;
      ip_hdr->ip_ttl = 64;
      uint32_t iptemp;
      iptemp = ip_hdr->ip_src;

      ip_hdr->ip_src = ip_hdr->ip_dst;
      ip_hdr->ip_dst = iptemp;

      /* update ip checksum. */
      ip_hdr->ip_sum = 0;
      checksum = cksum(ip_hdr, sizeof(*ip_hdr));
      ip_hdr->ip_sum = checksum;
      checksum = cksum(ip_hdr, sizeof(*ip_hdr));
      if (checksum != 0xffff){
           
            return -1;
      }

      struct sr_rt* best_rt = find_best_rt(sr->routing_table,  ntohl(ip_hdr->ip_dst));         
      if (!best_rt) {
            
            return -1;
      }

      res = sr_send_packet(sr, icmp_message, size, best_rt->interface);

      if (res != 0) {
            
            return -1;
      }
      return 0;
}
コード例 #18
0
ファイル: ip_input.cpp プロジェクト: sunfirefox/WinUAE
/*
 * Ip input routine.  Checksum and byte swap header.  If fragmented
 * try to reassemble.  Process options.  Pass to next level.
 */
void ip_input(struct mbuf *m)
{
	struct ip *ip;
	int hlen;
	
	DEBUG_CALL("ip_input");
	DEBUG_ARG("m = %lx", (long)m);
	DEBUG_ARG("m_len = %d", m->m_len);

	ipstat.ips_total++;
	
	if (m->m_len < sizeof (struct ip)) {
		ipstat.ips_toosmall++;
		return;
	}
	
	ip = mtod(m, struct ip *);
	
	if (ip->ip_v != IPVERSION) {
		ipstat.ips_badvers++;
		goto bad;
	}

	hlen = ip->ip_hl << 2;
	if (hlen<sizeof(struct ip ) || hlen>m->m_len) {/* min header length */
	  ipstat.ips_badhlen++;                     /* or packet too short */
	  goto bad;
	}

        /* keep ip header intact for ICMP reply
	 * ip->ip_sum = cksum(m, hlen); 
	 * if (ip->ip_sum) { 
	 */
	if(cksum(m,hlen)) {
	  ipstat.ips_badsum++;
	  goto bad;
	}

	/*
	 * Convert fields to host representation.
	 */
	NTOHS(ip->ip_len);
	if (ip->ip_len < hlen) {
		ipstat.ips_badlen++;
		goto bad;
	}
	NTOHS(ip->ip_id);
	NTOHS(ip->ip_off);

	/*
	 * Check that the amount of data in the buffers
	 * is as at least much as the IP header would have us expect.
	 * Trim mbufs if longer than we expect.
	 * Drop packet if shorter than we expect.
	 */
	if (m->m_len < ip->ip_len) {
		ipstat.ips_tooshort++;
		goto bad;
	}
	/* Should drop packet if mbuf too long? hmmm... */
	if (m->m_len > ip->ip_len)
	   m_adj(m, ip->ip_len - m->m_len);

	/* check ip_ttl for a correct ICMP reply */
	if(ip->ip_ttl==0 || ip->ip_ttl==1) {
	  icmp_error(m, ICMP_TIMXCEED,ICMP_TIMXCEED_INTRANS, 0,"ttl");
	  goto bad;
	}

	/*
	 * Process options and, if not destined for us,
	 * ship it on.  ip_dooptions returns 1 when an
	 * error was detected (causing an icmp message
	 * to be sent and the original packet to be freed).
	 */
/* We do no IP options */
/*	if (hlen > sizeof (struct ip) && ip_dooptions(m))
 *		goto next;
 */
	/*
	 * If offset or IP_MF are set, must reassemble.
	 * Otherwise, nothing need be done.
	 * (We could look in the reassembly queue to see
	 * if the packet was previously fragmented,
	 * but it's not worth the time; just let them time out.)
	 * 
	 * XXX This should fail, don't fragment yet
	 */
	if (ip->ip_off &~ IP_DF) {
	  register struct ipq *fp;
		/*
		 * Look for queue of fragments
		 * of this datagram.
		 */
		for (fp = (struct ipq *) ipq.next; fp != &ipq;
		     fp = (struct ipq *) fp->next)
		  if (ip->ip_id == fp->ipq_id &&
		      ip->ip_src.s_addr == fp->ipq_src.s_addr &&
		      ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&
		      ip->ip_p == fp->ipq_p)
		    goto found;
		fp = 0;
	found:

		/*
		 * Adjust ip_len to not reflect header,
		 * set ip_mff if more fragments are expected,
		 * convert offset of this to bytes.
		 */
		ip->ip_len -= hlen;
		if (ip->ip_off & IP_MF)
		  ((struct ipasfrag *)ip)->ipf_mff |= 1;
		else 
		  ((struct ipasfrag *)ip)->ipf_mff &= ~1;

		ip->ip_off <<= 3;

		/*
		 * If datagram marked as having more fragments
		 * or if this is not the first fragment,
		 * attempt reassembly; if it succeeds, proceed.
		 */
		if (((struct ipasfrag *)ip)->ipf_mff & 1 || ip->ip_off) {
			ipstat.ips_fragments++;
			ip = ip_reass((struct ipasfrag *)ip, fp);
			if (ip == 0)
				return;
			ipstat.ips_reassembled++;
			m = dtom(ip);
		} else
			if (fp)
		   	   ip_freef(fp);

	} else
		ip->ip_len -= hlen;

	/*
	 * Switch out to protocol's input routine.
	 */
	ipstat.ips_delivered++;
	switch (ip->ip_p) {
	 case IPPROTO_TCP:
		tcp_input(m, hlen, (struct socket *)NULL);
		break;
	 case IPPROTO_UDP:
		udp_input(m, hlen);
		break;
	 case IPPROTO_ICMP:
		icmp_input(m, hlen);
		break;
	 default:
		ipstat.ips_noproto++;
		m_free(m);
	}
	return;
bad:
	m_freem(m);
	return;
}
コード例 #19
0
ファイル: ip_icmp.c プロジェクト: 0day-ci/qemu
/*
 * Process a received ICMP message.
 */
void
icmp_input(struct mbuf *m, int hlen)
{
  register struct icmp *icp;
  register struct ip *ip=mtod(m, struct ip *);
  int icmplen=ip->ip_len;
  Slirp *slirp = m->slirp;

  DEBUG_CALL("icmp_input");
  DEBUG_ARG("m = %p", m);
  DEBUG_ARG("m_len = %d", m->m_len);

  /*
   * Locate icmp structure in mbuf, and check
   * that its not corrupted and of at least minimum length.
   */
  if (icmplen < ICMP_MINLEN) {          /* min 8 bytes payload */
  freeit:
    m_free(m);
    goto end_error;
  }

  m->m_len -= hlen;
  m->m_data += hlen;
  icp = mtod(m, struct icmp *);
  if (cksum(m, icmplen)) {
    goto freeit;
  }
  m->m_len += hlen;
  m->m_data -= hlen;

  DEBUG_ARG("icmp_type = %d", icp->icmp_type);
  switch (icp->icmp_type) {
  case ICMP_ECHO:
    ip->ip_len += hlen;	             /* since ip_input subtracts this */
    if (ip->ip_dst.s_addr == slirp->vhost_addr.s_addr) {
      icmp_reflect(m);
    } else if (slirp->restricted) {
        goto freeit;
    } else {
      struct socket *so;
      struct sockaddr_storage addr;
      if ((so = socreate(slirp)) == NULL) goto freeit;
      if (icmp_send(so, m, hlen) == 0) {
        return;
      }
      if (udp_attach(so, AF_INET) == -1) {
	DEBUG_MISC((dfd,"icmp_input udp_attach errno = %d-%s\n",
		    errno,strerror(errno)));
	sofree(so);
	m_free(m);
	goto end_error;
      }
      so->so_m = m;
      so->so_ffamily = AF_INET;
      so->so_faddr = ip->ip_dst;
      so->so_fport = htons(7);
      so->so_lfamily = AF_INET;
      so->so_laddr = ip->ip_src;
      so->so_lport = htons(9);
      so->so_iptos = ip->ip_tos;
      so->so_type = IPPROTO_ICMP;
      so->so_state = SS_ISFCONNECTED;

      /* Send the packet */
      addr = so->fhost.ss;
      sotranslate_out(so, &addr);

      if(sendto(so->s, icmp_ping_msg, strlen(icmp_ping_msg), 0,
		(struct sockaddr *)&addr, sizeof(addr)) == -1) {
	DEBUG_MISC((dfd,"icmp_input udp sendto tx errno = %d-%s\n",
		    errno,strerror(errno)));
	icmp_send_error(m, ICMP_UNREACH, ICMP_UNREACH_NET, 0, strerror(errno));
	udp_detach(so);
      }
    } /* if ip->ip_dst.s_addr == alias_addr.s_addr */
    break;
  case ICMP_UNREACH:
    /* XXX? report error? close socket? */
  case ICMP_TIMXCEED:
  case ICMP_PARAMPROB:
  case ICMP_SOURCEQUENCH:
  case ICMP_TSTAMP:
  case ICMP_MASKREQ:
  case ICMP_REDIRECT:
    m_free(m);
    break;

  default:
    m_free(m);
  } /* swith */

end_error:
  /* m is m_free()'d xor put in a socket xor or given to ip_send */
  return;
}
コード例 #20
0
ファイル: ip_output.c プロジェクト: aissat/vde2
/*
 * IP output.  The packet in mbuf chain m contains a skeletal IP
 * header (with len, off, ttl, proto, tos, src, dst).
 * The mbuf chain containing the packet will be freed.
 * The mbuf opt, if present, will not be freed.
 */
int
ip_output(struct socket *so, struct mbuf *m0)
{
	Slirp *slirp = m0->slirp;
	struct ip *ip;
	struct mbuf *m = m0;
	int hlen = sizeof(struct ip );
	int len, off, error = 0;

	DEBUG_CALL("ip_output");
	DEBUG_ARG("so = %lx", (long)so);
	DEBUG_ARG("m0 = %lx", (long)m0);

	ip = mtod(m, struct ip *);
	/*
	 * Fill in IP header.
	 */
	ip->ip_v = IPVERSION;
	ip->ip_off &= IP_DF;
	ip->ip_id = htons(slirp->ip_id++);
	ip->ip_hl = hlen >> 2;

	/*
	 * If small enough for interface, can just send directly.
	 */
	if ((u_int16_t)ip->ip_len <= IF_MTU) {
		ip->ip_len = htons((u_int16_t)ip->ip_len);
		ip->ip_off = htons((u_int16_t)ip->ip_off);
		ip->ip_sum = 0;
		ip->ip_sum = cksum(m, hlen);

		if_output(so, m);
		goto done;
	}

	/*
	 * Too large for interface; fragment if possible.
	 * Must be able to put at least 8 bytes per fragment.
	 */
	if (ip->ip_off & IP_DF) {
		error = -1;
		goto bad;
	}

	len = (IF_MTU - hlen) &~ 7;       /* ip databytes per packet */
	if (len < 8) {
		error = -1;
		goto bad;
	}

    {
	int mhlen, firstlen = len;
	struct mbuf **mnext = &m->m_nextpkt;

	/*
	 * Loop through length of segment after first fragment,
	 * make new header and copy data of each part and link onto chain.
	 */
	m0 = m;
	mhlen = sizeof (struct ip);
	for (off = hlen + len; off < (u_int16_t)ip->ip_len; off += len) {
	  struct ip *mhip;
	  m = m_get(slirp);
          if (m == NULL) {
	    error = -1;
	    goto sendorfree;
	  }
	  m->m_data += IF_MAXLINKHDR;
	  mhip = mtod(m, struct ip *);
	  *mhip = *ip;

	  m->m_len = mhlen;
	  mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF);
	  if (ip->ip_off & IP_MF)
	    mhip->ip_off |= IP_MF;
	  if (off + len >= (u_int16_t)ip->ip_len)
	    len = (u_int16_t)ip->ip_len - off;
	  else
	    mhip->ip_off |= IP_MF;
	  mhip->ip_len = htons((u_int16_t)(len + mhlen));

	  if (m_copy(m, m0, off, len) < 0) {
	    error = -1;
	    goto sendorfree;
	  }

	  mhip->ip_off = htons((u_int16_t)mhip->ip_off);
	  mhip->ip_sum = 0;
	  mhip->ip_sum = cksum(m, mhlen);
	  *mnext = m;
	  mnext = &m->m_nextpkt;
	}
	/*
	 * Update first fragment by trimming what's been copied out
	 * and updating header, then send each fragment (in order).
	 */
	m = m0;
	m_adj(m, hlen + firstlen - (u_int16_t)ip->ip_len);
	ip->ip_len = htons((u_int16_t)m->m_len);
	ip->ip_off = htons((u_int16_t)(ip->ip_off | IP_MF));
	ip->ip_sum = 0;
	ip->ip_sum = cksum(m, hlen);
sendorfree:
	for (m = m0; m; m = m0) {
		m0 = m->m_nextpkt;
                m->m_nextpkt = NULL;
		if (error == 0)
			if_output(so, m);
		else
			m_freem(m);
	}
    }

done:
	return (error);

bad:
	m_freem(m0);
	goto done;
}
コード例 #21
0
ファイル: sr_router.c プロジェクト: Cam1337/cs144_lab3
/*---------------------------------------------------------------------
 * Method: sr_send_icmp(struct sr_instance* sr, uint8_t *packet, unsigned int len, 
 *										  uint8_t type, uint8_t code)
 * Scope: Global
 *
 * This function sends an icmp of the supplied type and code, using the
 * supplied packet, which is an ip datagram. 
 *
 *---------------------------------------------------------------------*/
void sr_send_icmp(struct sr_instance* sr, uint8_t *packet, unsigned int len, 
									uint8_t type, uint8_t code)
{
	uint16_t icmp_len;
	uint32_t dst;
	struct sr_ip_hdr *error_ip_hdr;
	struct sr_icmp_hdr icmp_hdr;
	struct sr_icmp_hdr *icmp_hdr_ptr;
	struct sr_if *interface;
	struct sr_ip_hdr ip_hdr;
	uint8_t *new_pkt;
	struct sr_rt *rt;
	uint16_t total_len;
	
	/* Destination unreachable message or TTL exceeded. */
	if (type == ICMP_UNREACHABLE_TYPE || type == ICMP_TIME_EXCEEDED_TYPE) {
	
		/* Update icmp header fields. */
		icmp_hdr.icmp_type = type;
		icmp_hdr.icmp_code = code;
		icmp_hdr.unused = 0;
		icmp_hdr.icmp_sum = 0;
		
		/* Update the IP header fields. */
		error_ip_hdr = (struct sr_ip_hdr *)packet;
		ip_hdr.ip_hl = ICMP_IP_HDR_LEN;
		ip_hdr.ip_v = ip_version_4;
		ip_hdr.ip_tos = 0;
		ip_hdr.ip_id = error_ip_hdr->ip_id;
		ip_hdr.ip_off = htons(IP_DF);
		ip_hdr.ip_ttl = DEFAULT_TTL;
		ip_hdr.ip_p = ip_protocol_icmp;
		ip_hdr.ip_sum = 0;
		ip_hdr.ip_dst = error_ip_hdr->ip_src;
		dst = error_ip_hdr->ip_src;
	
		/* Look up longest prefix match in your routing table. If it doesn't exist, just
		 * give up. No use in sending an error message for an error message. */
		rt = sr_longest_prefix_match(sr, ip_in_addr(ip_hdr.ip_dst));
		if (rt == 0)
			return;
		
		/* Update the source IP to be the outgoing interface's ip address. */
		interface = sr_get_interface(sr, (const char*)rt->interface);
		ip_hdr.ip_src = interface->ip;
		
		/* Update length: first 8 bytes of original message, original ip header, icmp header
		 * and new ip header. */
		icmp_len = ip_ihl(error_ip_hdr) + ICMP_COPIED_DATAGRAM_DATA_LEN + sizeof(struct sr_icmp_hdr);
		total_len = icmp_len + ICMP_IP_HDR_LEN_BYTES;
		ip_hdr.ip_len = htons(total_len);
		
		/* Update the ip checksum. */
		ip_hdr.ip_sum = cksum(&ip_hdr, ICMP_IP_HDR_LEN_BYTES);
	
		/* Allocate a packet, copy everything in. */
		new_pkt = malloc(total_len);
		memcpy(new_pkt, &ip_hdr, ICMP_IP_HDR_LEN_BYTES);
		memcpy(new_pkt + ICMP_IP_HDR_LEN_BYTES, &icmp_hdr, sizeof(struct sr_icmp_hdr));
		memcpy(new_pkt + ICMP_IP_HDR_LEN_BYTES + sizeof(struct sr_icmp_hdr), 
					 error_ip_hdr, 
					 ip_ihl(error_ip_hdr) + ICMP_COPIED_DATAGRAM_DATA_LEN);
		
	/* Echo reply. */
	} else if (type == ICMP_ECHO_REPLY_CODE) {
	
		/* Update the IP header fields. */
		error_ip_hdr = (struct sr_ip_hdr *)packet;
		dst = error_ip_hdr->ip_src;
		error_ip_hdr->ip_src = error_ip_hdr->ip_dst;
		error_ip_hdr->ip_dst = dst;
		
		/* Update the type of icmp from request to reply. */
		icmp_hdr_ptr = icmp_header(error_ip_hdr);
		icmp_hdr_ptr->icmp_sum = 0;
		icmp_hdr_ptr->icmp_code = code;
		icmp_hdr_ptr->icmp_type = type;
		
		/* Allocate a copy of this packet. */
		total_len = ip_len(error_ip_hdr);
		new_pkt = malloc(total_len);
		memcpy(new_pkt, error_ip_hdr, total_len);
		
		/* Calculate the length of the icmp message for computing checksum. */
		icmp_len = total_len - ICMP_IP_HDR_LEN;
	}
	
	/* Update the checksum of the icmp message starting at 'type' field. */
	icmp_hdr_ptr = icmp_header((struct sr_ip_hdr *)new_pkt);
	icmp_hdr_ptr->icmp_sum = cksum(icmp_hdr_ptr, icmp_len); 
	
	/* Encapsulate and send */
	sr_encap_and_send_pkt(sr, new_pkt, total_len, dst, 0, ethertype_ip);
	free(new_pkt);
}
コード例 #22
0
ファイル: sr_router.c プロジェクト: allendaicool/router
void sr_handlepacket_ip(struct sr_instance* sr,
        sr_ethernet_hdr_t* eth_hdr,
        uint8_t* packet/* not even a malloc pointer, don't free this */,
        unsigned int len,
        char* interface/* lent */) 
{
    /* puts("handling IP header"); */
    sr_ip_hdr_t *ip_hdr;
    struct sr_if* if_dst;

    /* REQUIRES */
    assert(packet);

    if (len < sizeof(sr_ip_hdr_t)) {
        /* puts("Ethernet payload (claiming to contain IP) is smaller than IP header. Discarding."); */
        return;
    }

    /* If we're using a NAT, then the rewrite of IP packets is
     * absolutely the first thing we do. That way the rest of
     * the router still feels like everything is the same. This
     * is the only change to the router to get a NAT working. */
    if (sr->use_nat) {
        int drop_requested = sr_nat_rewrite_ip_packet(sr, packet, len);
        if (drop_requested) {
            /* puts("DROP requested by the NAT. Dropping packet."); */
            return;
        }
    }

    ip_hdr = (sr_ip_hdr_t*)packet;

    /* Endianness */
    uint32_t ip_dst = ntohl(ip_hdr->ip_dst);

    /* Check for a corrupt packet */

    uint16_t cksum_buffer = ip_hdr->ip_sum;
    ip_hdr->ip_sum = 0;

    if (cksum((const void*)ip_hdr, sizeof(sr_ip_hdr_t)) != cksum_buffer) {
        /* puts("Checksum is corrupted. Bailing"); */
        return;
    }

    /* Decrement time to live */

    /* printf("TTL: %i\n", ip_hdr->ip_ttl); */

    /* Recalculate the cksum after changing the TTL */

    ip_hdr->ip_ttl--;
    ip_hdr->ip_sum = cksum((const void*)ip_hdr, sizeof(sr_ip_hdr_t));

    if (ip_hdr->ip_ttl <= 0) {
        /* puts("Packet TTL expired"); */

        /* Send out a ICMP TTL expired response */

        sr_try_send_ip_packet(sr, ip_hdr->ip_src, 0,
            sr_build_icmp_t3_packet(
                ICMP_TYPE_TTL_EXCEEDED,
                ICMP_CODE_TTL_EXCEEDED,
                (uint8_t*)ip_hdr
            ),
            NULL
        );

        return;
    }

    /* Check for any IP packets destined for our interfaces */

    if_dst = sr_get_interface_ip (sr, ntohl(ip_dst));
    if (if_dst != 0) {

        /* puts("IP packet is destined for our interfaces."); */

        /* If this IP packet is destined for us */

        switch (ip_hdr->ip_p) {

            /*
             * ICMP handling.
             */

            case ip_protocol_icmp:
                sr_handlepacket_icmp(sr, eth_hdr, ip_hdr, packet + sizeof(sr_ip_hdr_t), len - sizeof(sr_ip_hdr_t), interface);
                return;

            /*
             * TCP and UDP handling, which are both the same
             */

            case ip_protocol_tcp:
            case ip_protocol_udp:
                /* puts("Received a TCP/UDP request."); */

                /* Undo changes to the TTL */

                ip_hdr->ip_ttl++;
                ip_hdr->ip_sum = cksum((const void*)ip_hdr, sizeof(sr_ip_hdr_t));
    
                /* Send out a ICMP port unreachable response */

                sr_try_send_ip_packet(sr, ip_hdr->ip_src, ip_hdr->ip_dst,
                    sr_build_icmp_t3_packet(
                        ICMP_TYPE_PORT_UNREACHABLE,
                        ICMP_CODE_PORT_UNREACHABLE,
                        (uint8_t*)ip_hdr
                    ),
                    NULL
                );

                return;
        }

        /* puts("IP packet protocol unsupported. Dropping packet."); */
        return;
    }

    /* Build a packet struct to pass in the contents of the IP we're forwarding */

    uint8_t* payload_buf = ((uint8_t*)packet) + sizeof(sr_ip_hdr_t);
    int payload_len = len - sizeof(sr_ip_hdr_t);

    sr_constructed_packet_t *payload = sr_grow_or_create_payload(NULL, payload_len);
    memcpy(payload->buf, payload_buf, payload_len);

    /* Handles checking the routing table, and making any ARP requests we need to make */

    sr_try_send_ip_packet(sr, ip_hdr->ip_dst, 0, payload, ip_hdr);
}
コード例 #23
0
ファイル: sr_router.c プロジェクト: Fate9834/CorrectVersion
void ip_forwardpacket(struct sr_instance *sr,
        sr_ip_hdr_t *ip_hdr,
        unsigned int len,
        char *interface) {

        printf("** FORWARDING\n");

        struct sr_arpreq *req;
        struct sr_arpentry *arp_entry;
        uint8_t icmp_type;
        uint8_t icmp_code;

        ip_hdr->ip_ttl --;
 	
        /* Update checksum */
        ip_hdr->ip_sum = 0;
        ip_hdr->ip_sum = cksum(ip_hdr, ip_hdr->ip_hl * 4);

        uint8_t *ip_pkt;

        ip_pkt = malloc(len);
        memcpy(ip_pkt, ip_hdr, len);

        /* Find longest prefix match in routing table */
        struct sr_rt* lpmatch = longest_prefix_matching(sr, ip_hdr->ip_dst);
        
        /* If cannot find destination IP in routing table, send ICMP net unreachable */
        /* OR TTL = 0 */
        if (lpmatch == 0) {
          icmp_type = 3;
          icmp_code = 0;
          sr_icmp_with_payload(sr, ip_hdr, interface, icmp_type, icmp_code);
          return;
        } else if (ip_hdr->ip_ttl == 0){
          icmp_type = 11;
          icmp_code = 0;
          sr_icmp_with_payload(sr, (sr_ip_hdr_t *)(ip_pkt), interface, icmp_type, icmp_code);
          return;
        }

        /* Ready to forward packet */  
        /* Get the corresponding interface of the destination IP. */
        struct sr_if* s_interface = sr_get_interface(sr, lpmatch->interface);
      
        /* Check ARP cache */
        arp_entry = sr_arpcache_lookup(&sr->cache, lpmatch->gw.s_addr);

        if (arp_entry == 0){

            /* If miss APR cache, add the packet to ARP request queue */
            req = sr_arpcache_queuereq(&sr->cache, lpmatch->gw.s_addr, ip_pkt, 
                                      len, s_interface->name);
            sr_handle_arpreq(sr, req);
        } else {

            /* Hit ARP cache, send out the packet right away using next-hop */
            /* Encap the ARP request into ethernet frame and then send it */
            sr_ethernet_hdr_t sr_ether_pkt;

            memcpy(sr_ether_pkt.ether_dhost, arp_entry->mac, ETHER_ADDR_LEN); /* Address from routing table */
            memcpy(sr_ether_pkt.ether_shost, s_interface->addr, ETHER_ADDR_LEN); /* Hardware address of the outgoing interface */
            sr_ether_pkt.ether_type = htons(ethertype_ip);

            uint8_t *packet_rqt;
            unsigned int total_len = len + sizeof(struct sr_ethernet_hdr);
            packet_rqt = malloc(total_len);
            memcpy(packet_rqt, &(sr_ether_pkt), sizeof(sr_ether_pkt));
            memcpy(packet_rqt + sizeof(sr_ether_pkt), ip_pkt, len);

            /* Forward the IP packet*/
            sr_send_packet(sr, packet_rqt, total_len, s_interface->name);
            free(packet_rqt);
          }
}
コード例 #24
0
ファイル: buffer.c プロジェクト: dcrankshaw/vrouter
/*******************************************************************
*   Every time handle_packet() is called, update_buffer() is called. The function walks through
*   the packet buffer and checks if the necessary mac address is now in the arp cache. If it is,
*   then the MAC address is added to the ethernet header and the packet is send and removed 
*   from the buffer. If the address is not in the cache and less than 5 arp requests have already
*   been sent, then another arp request is sent. Otherwise the packet is deleted from the buffer 
*   and an ICMP port unreachable is sent.
*******************************************************************/
void update_buffer(struct packet_state* ps,struct packet_buffer* queue)
{
	struct packet_buffer* buf_walker=0;
	buf_walker=queue;
	
	while(buf_walker)
	{
		uint32_t search_ip=buf_walker->gw_IP;
		struct arp_cache_entry* ent=search_cache(ps, search_ip);
		if(ent!=NULL)                   /*MAC Address is in ARP Cache. Send packet. */
		{
			struct sr_ethernet_hdr *eth = (struct sr_ethernet_hdr *)(buf_walker->packet);
			memmove(eth->ether_dhost, ent->mac, ETHER_ADDR_LEN);
			struct sr_if *iface=sr_get_interface(ps->sr, buf_walker->interface);
			memmove(eth->ether_shost, iface->addr, ETHER_ADDR_LEN);
			eth->ether_type = htons(ETHERTYPE_IP);
			
		    sr_send_packet(ps->sr, buf_walker->packet, buf_walker->pack_len, buf_walker->interface);
			buf_walker=delete_from_buffer(ps,buf_walker);
		}
		else if(buf_walker->num_arp_reqs < 5)   /*Send another arp request. */
		{
			buf_walker->num_arp_reqs++;
			sr_send_packet(ps->sr, buf_walker->arp_req, buf_walker->arp_len, buf_walker->interface);
			buf_walker=buf_walker->next;
		}
		else    /* 5 ARP Request already sent, send ICMP Port Unreachable and Delete from Buffer.*/
		{
			int off = sizeof(struct sr_ethernet_hdr) + sizeof(struct ip);
			ps->res_len=off;
			
			ps->response += sizeof(struct sr_ethernet_hdr);
			
			struct ip *res_ip = (struct ip*) ps->response; /*IP Header for ICMP Port Unreachable*/
			ps->response += sizeof(struct ip);
			
			ps->packet = buf_walker->packet;
			ps->packet += sizeof(struct sr_ethernet_hdr);
			
			struct ip *ip_hdr = (struct ip*) (ps->packet);  /*IP Header from original packet. */
			ps->packet += sizeof(struct ip);
			
			icmp_response(ps, ip_hdr, ICMPT_DESTUN, ICMPC_HOSTUN); /*Construct ICMP */
			memmove(res_ip, ip_hdr, sizeof(struct ip));
			res_ip->ip_len = htons(ps->res_len - sizeof(struct sr_ethernet_hdr));
			res_ip->ip_ttl = INIT_TTL;
			res_ip->ip_tos = ip_hdr->ip_tos;
			res_ip->ip_p = IPPROTO_ICMP;
			
			/* Finding interface to send ICMP out of*/
			struct sr_rt* iface_rt_entry=get_routing_if(ps, ip_hdr->ip_src);
			struct sr_if* iface=sr_get_interface(ps->sr, iface_rt_entry->interface);
			
			res_ip->ip_src.s_addr = iface->ip;
			res_ip->ip_dst = ip_hdr->ip_src;
			res_ip->ip_sum = 0;
			res_ip->ip_sum = cksum((uint8_t *)res_ip, sizeof(struct ip));
			res_ip->ip_sum = htons(res_ip->ip_sum);
			
			ps->response = (uint8_t *) res_ip - sizeof(struct sr_ethernet_hdr);
			struct sr_ethernet_hdr* eth_resp=(struct sr_ethernet_hdr*)ps->response;
			memmove(eth_resp->ether_dhost,buf_walker->old_eth->ether_shost,ETHER_ADDR_LEN);
			
			memmove(eth_resp->ether_shost,iface->addr, ETHER_ADDR_LEN);
			eth_resp->ether_type=htons(ETHERTYPE_IP);
			
			sr_send_packet(ps->sr, ps->response, ps->res_len, iface_rt_entry->interface);

			buf_walker=delete_from_buffer(ps,buf_walker);	
		}
	}
}
コード例 #25
0
ファイル: sr_router.c プロジェクト: Fate9834/CorrectVersion
void sr_icmp_with_payload(struct sr_instance *sr,
        sr_ip_hdr_t *ip_hdr, char *interface,
        uint8_t icmp_type, uint8_t icmp_code) {

    struct sr_if *r_interface = sr_get_interface(sr, interface);
    struct sr_arpreq *req;
    struct sr_arpentry *arp_entry;
    uint8_t *cache_packet;
    uint16_t total_len;
    uint16_t icmp_len;
    uint32_t dst;

    if (icmp_type == 11 && icmp_code == 0){
      if (natEnabled(sr)){
        sr_nat_undo_mapping(sr, ip_hdr, ip_hdr->ip_len, r_interface);
      }
    }

    /* Create a new IP packet for ICMP message */
    struct sr_ip_hdr send_ip_hdr;

    send_ip_hdr.ip_hl = 5;
    send_ip_hdr.ip_v = ip_hdr->ip_v;
    send_ip_hdr.ip_tos = 0;
    send_ip_hdr.ip_id = 0;
    send_ip_hdr.ip_off = htons(IP_DF);
    send_ip_hdr.ip_ttl = DEFAULT_TTL;
    send_ip_hdr.ip_p = ip_protocol_icmp;
    send_ip_hdr.ip_sum = 0;
    send_ip_hdr.ip_dst = ip_hdr->ip_src;

    if (icmp_type == 3 && icmp_code == 3){
      ip_hdr->ip_sum = cksum(ip_hdr, ip_hdr->ip_hl * 4);
      send_ip_hdr.ip_src = ip_hdr->ip_dst;
    } else {
        send_ip_hdr.ip_src = r_interface->ip;
    }
    dst = ip_hdr->ip_src;

    struct sr_icmp_t3_hdr error_packet;

    error_packet.icmp_type = icmp_type;
    error_packet.icmp_code = icmp_code;
    error_packet.icmp_sum = 0;
    error_packet.unused = 0;
    error_packet.next_mtu = htons(MTU);

    icmp_len = sizeof(struct sr_icmp_t3_hdr);
    total_len = ICMP_IP_HDR_LEN_BYTE + icmp_len;
    send_ip_hdr.ip_len = htons(total_len);
    send_ip_hdr.ip_sum = cksum(&send_ip_hdr, ICMP_IP_HDR_LEN_BYTE);

    cache_packet = malloc(total_len);

    memcpy(error_packet.data, ip_hdr, ICMP_DATA_SIZE);
    memcpy(cache_packet, &(send_ip_hdr), ICMP_IP_HDR_LEN_BYTE);
    memcpy(cache_packet + ICMP_IP_HDR_LEN_BYTE, &(error_packet), 
          sizeof(struct sr_icmp_t3_hdr));

    struct sr_icmp_hdr *icmp_hdr_ptr = icmp_header((struct sr_ip_hdr *)cache_packet);

    icmp_hdr_ptr->icmp_sum = cksum(icmp_hdr_ptr, icmp_len);

    /*Check if we should send immediately or wait */
    arp_entry = sr_arpcache_lookup(&sr->cache, dst);
    
    if (arp_entry != 0){

    /* Entry exists, we can send it out right now */
    sr_add_ethernet_send(sr, cache_packet, total_len, dst, ethertype_ip);
    } else {
        req = sr_arpcache_queuereq(&sr->cache, dst, 
                                  cache_packet, total_len, interface);
        sr_handle_arpreq(sr, req);
      }  
}
コード例 #26
0
ファイル: ip_output.c プロジェクト: greg100795/virtualbox
/* This function will free m0! */
int
ip_output0(PNATState pData, struct socket *so, struct mbuf *m0, int urg)
{
    register struct ip *ip;
    register struct mbuf *m = m0;
    register int hlen = sizeof(struct ip);
    int len, off, error = 0;
    struct ethhdr *eh = NULL;
    uint8_t eth_dst[ETH_ALEN];
    int rc = 1;

    STAM_PROFILE_START(&pData->StatIP_output, a);

#ifdef LOG_ENABLED
    LogFlowFunc(("ip_output: so = %R[natsock], m0 = %lx\n", so, (long)m0));
#else
    NOREF(so);
#endif

    M_ASSERTPKTHDR(m);
    Assert(m->m_pkthdr.header);

#if 0 /* We do no options */
    if (opt)
    {
        m = ip_insertoptions(m, opt, &len);
        hlen = len;
    }
#endif
    ip = mtod(m, struct ip *);
    LogFunc(("ip(src:%RTnaipv4, dst:%RTnaipv4)\n", ip->ip_src, ip->ip_dst));
    /*
     * Fill in IP header.
     */
    ip->ip_v = IPVERSION;
    ip->ip_off &= IP_DF;
    ip->ip_id = RT_H2N_U16(ip_currid++);
    ip->ip_hl = hlen >> 2;
    ipstat.ips_localout++;

    /* Current TCP/IP stack hasn't routing information at
     * all so we need to calculate destination ethernet address
     */
    rc = rt_lookup_in_cache(pData, ip->ip_dst.s_addr, eth_dst);
    if (RT_FAILURE(rc))
        goto exit_drop_package;

    eh = (struct ethhdr *)(m->m_data - ETH_HLEN);
    /*
     * If small enough for interface, can just send directly.
     */
    if ((u_int16_t)ip->ip_len <= if_mtu)
    {
        ip->ip_len = RT_H2N_U16((u_int16_t)ip->ip_len);
        ip->ip_off = RT_H2N_U16((u_int16_t)ip->ip_off);
        ip->ip_sum = 0;
        ip->ip_sum = cksum(m, hlen);

        if (!(m->m_flags & M_SKIP_FIREWALL)){
            struct m_tag *t;
            STAM_PROFILE_START(&pData->StatALIAS_output, b);
            if ((t = m_tag_find(m, PACKET_TAG_ALIAS, NULL)) != 0)
                rc = LibAliasOut((struct libalias *)&t[1], mtod(m, char *),
                                 m_length(m, NULL));
            else
                rc = LibAliasOut(pData->proxy_alias, mtod(m, char *),
                                 m_length(m, NULL));

            if (rc == PKT_ALIAS_IGNORED)
            {
                Log(("NAT: packet was droppped\n"));
                goto exit_drop_package;
            }
            STAM_PROFILE_STOP(&pData->StatALIAS_output, b);
        }
コード例 #27
0
ファイル: igmpv1.c プロジェクト: theralfbrown/t50
  /* Packet size. */
  *size = sizeof(struct iphdr) +
          greoptlen            +
          sizeof(struct igmphdr);

  /* Try to reallocate packet, if necessary */
  alloc_packet(*size);

  /* IP Header structure making a pointer to Packet. */
  ip = ip_header(packet, *size, co);

  /* GRE Encapsulation takes place. */
  gre_encapsulation(packet, co,
        sizeof(struct iphdr) +
        sizeof(struct igmphdr));

  /* IGMPv1 Header structure making a pointer to Packet. */
  igmpv1        = (struct igmphdr *)((void *)(ip + 1) + greoptlen);
  igmpv1->type  = co->igmp.type;
  igmpv1->code  = co->igmp.code;
  igmpv1->group = htonl(INADDR_RND(co->igmp.group));
  igmpv1->csum  = 0;  /* Needed 'cause cksum() call, below! */

  /* Computing the checksum. */
  igmpv1->csum  = co->bogus_csum ? RANDOM() : cksum(igmpv1, sizeof(struct igmphdr));

  /* GRE Encapsulation takes place. */
  gre_checksum(packet, co, *size);
}
コード例 #28
0
ファイル: ip_input.c プロジェクト: 8tab/qemu
/*
 * Ip input routine.  Checksum and byte swap header.  If fragmented
 * try to reassemble.  Process options.  Pass to next level.
 */
void
ip_input(struct mbuf *m)
{
	Slirp *slirp = m->slirp;
	register struct ip *ip;
	int hlen;

	if (!slirp->in_enabled) {
		goto bad;
	}

	DEBUG_CALL("ip_input");
	DEBUG_ARG("m = %p", m);
	DEBUG_ARG("m_len = %d", m->m_len);

	if (m->m_len < sizeof (struct ip)) {
		goto bad;
	}

	ip = mtod(m, struct ip *);

	if (ip->ip_v != IPVERSION) {
		goto bad;
	}

	hlen = ip->ip_hl << 2;
	if (hlen<sizeof(struct ip ) || hlen>m->m_len) {/* min header length */
	  goto bad;                                  /* or packet too short */
	}

        /* keep ip header intact for ICMP reply
	 * ip->ip_sum = cksum(m, hlen);
	 * if (ip->ip_sum) {
	 */
	if(cksum(m,hlen)) {
	  goto bad;
	}

	/*
	 * Convert fields to host representation.
	 */
	NTOHS(ip->ip_len);
	if (ip->ip_len < hlen) {
		goto bad;
	}
	NTOHS(ip->ip_id);
	NTOHS(ip->ip_off);

	/*
	 * Check that the amount of data in the buffers
	 * is as at least much as the IP header would have us expect.
	 * Trim mbufs if longer than we expect.
	 * Drop packet if shorter than we expect.
	 */
	if (m->m_len < ip->ip_len) {
		goto bad;
	}

	/* Should drop packet if mbuf too long? hmmm... */
	if (m->m_len > ip->ip_len)
	   m_adj(m, ip->ip_len - m->m_len);

	/* check ip_ttl for a correct ICMP reply */
	if (ip->ip_ttl == 0) {
	    icmp_send_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, 0, "ttl");
	    goto bad;
	}

	/*
	 * If offset or IP_MF are set, must reassemble.
	 * Otherwise, nothing need be done.
	 * (We could look in the reassembly queue to see
	 * if the packet was previously fragmented,
	 * but it's not worth the time; just let them time out.)
	 *
	 * XXX This should fail, don't fragment yet
	 */
	if (ip->ip_off &~ IP_DF) {
	  register struct ipq *fp;
      struct qlink *l;
		/*
		 * Look for queue of fragments
		 * of this datagram.
		 */
		for (l = slirp->ipq.ip_link.next; l != &slirp->ipq.ip_link;
		     l = l->next) {
            fp = container_of(l, struct ipq, ip_link);
            if (ip->ip_id == fp->ipq_id &&
                    ip->ip_src.s_addr == fp->ipq_src.s_addr &&
                    ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&
                    ip->ip_p == fp->ipq_p)
		    goto found;
        }
        fp = NULL;
	found:

		/*
		 * Adjust ip_len to not reflect header,
		 * set ip_mff if more fragments are expected,
		 * convert offset of this to bytes.
		 */
		ip->ip_len -= hlen;
		if (ip->ip_off & IP_MF)
		  ip->ip_tos |= 1;
		else
		  ip->ip_tos &= ~1;

		ip->ip_off <<= 3;

		/*
		 * If datagram marked as having more fragments
		 * or if this is not the first fragment,
		 * attempt reassembly; if it succeeds, proceed.
		 */
		if (ip->ip_tos & 1 || ip->ip_off) {
			ip = ip_reass(slirp, ip, fp);
                        if (ip == NULL)
				return;
			m = dtom(slirp, ip);
		} else
			if (fp)
		   	   ip_freef(slirp, fp);

	} else
コード例 #29
0
ファイル: main.c プロジェクト: korczis/skull-c
int main(int argc, char** argv)
{
    const char* hostname = argc > 1 ? argv[1] : "google.com";

    fprintf(stdout, "Sending ICMP request to '%s'\n", hostname);

    struct hostent* h = gethostbyname(hostname);
    if(0 == h || h->h_addr_list[0] == 0)
    {
        fprintf(stderr, "Unable to resolve host '%s'\n", hostname);
        return EXIT_FAILURE;
    }

    int s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);

    if (s < 0)
    {
        fprintf(stderr, "Unable to create socket, reason: %s\n", strerror(errno));
        return EXIT_FAILURE;
    }

    struct ifreq ifr;
    memset(&ifr, 0, sizeof(ifr));

    /* I want to get an IPv4 IP address */
    ifr.ifr_addr.sa_family = AF_INET;

    /* I want IP address attached to "eth0" */
    strncpy(ifr.ifr_name, "en3", IFNAMSIZ-1);

    ioctl(s, SIOCGIFADDR, &ifr);

    /* display result */
    fprintf(stdout, "%s\n", inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr));

    const int on = 1;

    // We shall provide IP headers
    if (setsockopt (s, IPPROTO_IP, IP_HDRINCL, (const char*)&on, sizeof (on)) == -1)
    {
        fprintf(stderr, "Unable to setsockopt IPPROTO_IP IP_HDRINCL, reason: %s\n", strerror(errno));
        return EXIT_FAILURE;
    }

    // Allow socket to send datagrams to broadcast addresses
    if (setsockopt (s, SOL_SOCKET, SO_BROADCAST, (const char*)&on, sizeof (on)) == -1)
    {
        fprintf(stderr, "Unable to setsockopt SOL_SOCKET SO_BROADCAST, reason: %s\n", strerror(errno));
        return EXIT_FAILURE;
    }

    int payload_size = 128;

    //Calculate total packet size
    int packet_size = sizeof (struct ip) + sizeof (struct icmp) + payload_size;
    char *packet = (char *) malloc (packet_size);

    //ip header
    struct ip *ip = (struct ip *) packet;
    struct icmp *icmp = (struct icmp *) (packet + sizeof (struct ip));

    //zero out the packet buffer
    memset (packet, 0, packet_size);

    // See - http://www.kernelthread.com/projects/hanoi/src/hanoimania/hanoi-icmp.c

    ip->ip_v = 4;
    ip->ip_hl = 5;
    ip->ip_tos = 0;
    ip->ip_len = sizeof(struct ip) + sizeof(struct icmp); // htons (packet_size);
    ip->ip_id = rand ();
    ip->ip_off = 0;
    ip->ip_ttl = 255;
    ip->ip_p = IPPROTO_ICMP;
    ip->ip_src.s_addr = inet_addr("10.0.0.17"); // *(in_addr_t*)&((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr;
    ip->ip_dst.s_addr = *(in_addr_t*)h->h_addr_list[0];
    //ip->check = in_cksum ((u16 *) ip, sizeof (struct iphdr));

    icmp->icmp_type = ICMP_ECHO;
    icmp->icmp_code = 0;
    icmp->icmp_hun.ih_idseq.icd_seq = rand();
    icmp->icmp_hun.ih_idseq.icd_id = rand();
    //checksum
    icmp->icmp_cksum = 0;

    struct sockaddr_in servaddr;
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = *(in_addr_t*)h->h_addr_list[0]; // *(in_addr_t*)h->h_addr_list[0];
    memset(&servaddr.sin_zero, 0, sizeof (servaddr.sin_zero));

    struct sockaddr_in connection;
    socklen_t addrlen;
    char buffer[MAX_MTU];

    int sent = 0, sent_size = 0;
    while (1)
    {
        // icmp->icmp_hun.ih_idseq.icd_seq = rand();
        // icmp->icmp_hun.ih_idseq.icd_id = rand();

        memset(packet + sizeof(struct ip) + sizeof(struct icmp), rand() % 255, payload_size);

        //recalculate the icmp header checksum since we are filling the payload with random characters everytime
        icmp->icmp_cksum = 0;
        icmp->icmp_cksum = cksum((unsigned short *)icmp, sizeof(struct icmp));

        ip->ip_sum = cksum((unsigned short*)ip, sizeof(struct ip));
        if (sendto(s, packet, packet_size, 0, (struct sockaddr*) &servaddr, sizeof (servaddr)) != packet_size)
        {
            fprintf(stderr, "Unable to send packet, reason: %s\n", strerror(errno));
            break;
        }

        ++sent;
        printf("%d packets sent\r", sent);
        fflush(stdout);

        usleep(1e6);  //microseconds
    }

    free(packet);

    close(s);

    return EXIT_SUCCESS;
}
コード例 #30
0
ファイル: sr_router.c プロジェクト: yufengli71/Mininet_Router
uint8_t* sr_generate_icmp(sr_ethernet_hdr_t *received_ether_hdr, 
						  sr_ip_hdr_t *received_ip_hdr, 
						  struct sr_if *iface, 
						  uint8_t type, uint8_t code)
{
	uint8_t *reply_packet = 0;
	sr_icmp_hdr_t *icmp_hdr = 0;
	sr_ip_hdr_t *ip_hdr = 0;
	sr_ethernet_hdr_t *ether_hdr = 0;
	size_t icmp_size = 0;
	
	/* type 0 echo reply */
	if (type == 0) {
	
		/* create new reply packet */
		if ((reply_packet = malloc(sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t) + sizeof(sr_icmp_hdr_t))) == NULL) {
			fprintf(stderr,"Error: out of memory (sr_generate_icmp)\n");
			return 0;
		}
		
		/* construct ICMP header */
		icmp_hdr = (sr_icmp_hdr_t *)(reply_packet + sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t));
		icmp_hdr->icmp_type = htons(type);
		icmp_hdr->icmp_code = htons(code);
		icmp_hdr->icmp_sum = htons(0);
		icmp_hdr->icmp_sum = cksum(icmp_hdr, sizeof(sr_icmp_hdr_t));
		
		/* grab the size of ICMP header */
		icmp_size = sizeof(sr_icmp_hdr_t);
	}
	/* Destination net unreachable (type 3, code 0) OR Time exceeded (type 11, code 0),
	   since the two types use the exact same struct, except the next_mtu field which is unused for type 11 */
	else if (type == 3 || type == 11) {
		sr_icmp_t3_hdr_t* icmp_hdr;
		/* create new reply packet */
		if ((reply_packet = malloc(sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t) + sizeof(sr_icmp_t3_hdr_t))) == NULL) {
			fprintf(stderr,"Error: out of memory (sr_generate_icmp)\n");
			return 0;
		}
		
		/* construct ICMP header */
		icmp_hdr = (sr_icmp_t3_hdr_t *)(reply_packet + sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t));
		icmp_hdr->icmp_type = htons(type);
		icmp_hdr->icmp_code = htons(code);
		icmp_hdr->unused = htons(0);
		icmp_hdr->next_mtu = htons(0);		
		if (type == 3) {	/* only set next_mtu if ICMP type is 3*/
			icmp_hdr->next_mtu = htons(1500);
		}
		memcpy(icmp_hdr->data, received_ip_hdr, ICMP_DATA_SIZE);
		icmp_hdr->icmp_sum = htons(0);
		icmp_hdr->icmp_sum = cksum(icmp_hdr, sizeof(sr_icmp_t3_hdr_t));
		
		/* grab the size of ICMP header */
		icmp_size = sizeof(sr_icmp_t3_hdr_t);
	}
	/* An ICMP type that we can't handle */
	else {
		fprintf(stderr,"Error: unsupported ICMP type (sr_generate_icmp)\n");
		return 0;
	}
	
	/* construct IP header */
	ip_hdr = (sr_ip_hdr_t *)(reply_packet + sizeof(sr_ethernet_hdr_t));
	ip_hdr->ip_hl = htons(5);									/* header length */
	ip_hdr->ip_v = htons(4);									/* version */
	ip_hdr->ip_tos = htons(0);									/* type of service */
	ip_hdr->ip_len = htons(20 + icmp_size);						/* total length */
	ip_hdr->ip_id = htons(0);									/* identification */
	ip_hdr->ip_off = htons(IP_DF);								/* fragment offset field */
	ip_hdr->ip_ttl = htons(INIT_TTL);							/* time to live */
	ip_hdr->ip_p = htons(ip_protocol_icmp);						/* protocol */
	ip_hdr->ip_src = htonl(iface->ip);							/* source ip address */
	ip_hdr->ip_dst = received_ip_hdr->ip_src;					/* dest ip address */
	ip_hdr->ip_sum = htons(0);
	ip_hdr->ip_sum = cksum(ip_hdr, sizeof(sr_ip_hdr_t));		/* checksum */
	
	/* construct ethernet header */
	ether_hdr = (sr_ethernet_hdr_t*)reply_packet;
	memcpy(ether_hdr->ether_dhost, received_ether_hdr->ether_shost, ETHER_ADDR_LEN);
	memcpy(ether_hdr->ether_shost, iface->addr, sizeof(iface->addr));
	ether_hdr->ether_type = htons(ethertype_ip);
			
	return reply_packet;
}