void sr_handle_arpreq(struct sr_instance *sr, struct sr_arpreq *req){
    /*Debug("\nsr_handle_arpreq called\n");*/
    time_t     now;
    now = time(NULL);
    
    struct sr_arpcache *cache = &(sr->cache);
    /*if the arp_request has never been sent before or if the last time the 
    arp_request was sent was more than 1 second ago*/

    if ((req->times_sent == 0)||(difftime(now, req->sent)> 1.0)){
        /*Debug("\nARP request not previously sent or have not been sent within the last second\n");*/
        if (req->times_sent >= 5)
		{
            /*Debug("\nARP request was sent 5 times previously; destroy ARP request\n");*/
            /*loop through all of the IP packets waiting for the request,
            call function to send ICMP msg -> host_unreachable*/
            struct sr_packet *packet;
            for(packet = req->packets; packet != NULL; packet = packet->next)
			{
				/*这里的interface是outgoing interface,有问题,send_icmp_message要的是in_interface*/
				send_icmp_message(sr, packet->buf, sizeof(struct sr_packet), sr_get_interface(sr, req->packets->iface), ICMP_DESTINATION_UNREACHABLE_TYPE, ICMP_HOST_UNREACHABLE_CODE);
            }
            sr_arpreq_destroy(cache, req);
        }
        else
		{
            /*Debug("\nSending ARP request\n");*/
			/*这里的interface是outgoing interface,有问题,send_icmp_message要的是in_interface*/
			printf("interface: %s", req->packets->iface);
			send_arp_request(sr, sr_get_interface(sr, req->packets->iface), req->ip);
			req->sent = now;
            req->times_sent++;
		}
    }
}
Beispiel #2
0
static enum ofp_return_code ofp_ip_output_add_eth(odp_packet_t pkt,
						  struct ip_out *odata)
{
	uint8_t l2_size = 0;
	void *l2_addr;

	if (!odata->gw) /* link local */
		odata->gw = odata->ip->ip_dst.s_addr;

	if (ETH_WITHOUT_VLAN(odata->vlan, odata->out_port))
		l2_size = sizeof(struct ofp_ether_header);
	else
		l2_size = sizeof(struct ofp_ether_vlan_header);

	if (odp_packet_l2_offset(pkt) + l2_size == odp_packet_l3_offset(pkt)) {
		l2_addr = odp_packet_l2_ptr(pkt, NULL);
	} else if (odp_packet_l3_offset(pkt) >= l2_size) {
		odp_packet_l2_offset_set(pkt,
					odp_packet_l3_offset(pkt) - l2_size);
		l2_addr = odp_packet_l2_ptr(pkt, NULL);
	} else {
		l2_addr = odp_packet_push_head(pkt,
					l2_size - odp_packet_l3_offset(pkt));
		odp_packet_l2_offset_set(pkt, 0);
		odp_packet_l3_offset_set(pkt, l2_size);
		odp_packet_l4_offset_set(pkt, l2_size + (odata->ip->ip_hl<<2));
	}

	if (odp_unlikely(l2_addr == NULL)) {
		OFP_DBG("l2_addr == NULL");
		return OFP_PKT_DROP;
	}

	if (ETH_WITHOUT_VLAN(odata->vlan, odata->out_port)) {
		struct ofp_ether_header *eth =
				(struct ofp_ether_header *)l2_addr;
		uint32_t addr = odp_be_to_cpu_32(odata->ip->ip_dst.s_addr);

		if (OFP_IN_MULTICAST(addr)) {
			eth->ether_dhost[0] = 0x01;
			eth->ether_dhost[1] = 0x00;
			eth->ether_dhost[2] = 0x5e;
			eth->ether_dhost[3] = (addr >> 16) & 0x7f;
			eth->ether_dhost[4] = (addr >> 8) & 0xff;
			eth->ether_dhost[5] = addr & 0xff;
		} else if (odata->dev_out->ip_addr == odata->ip->ip_dst.s_addr) {
			odata->is_local_address = 1;
			ofp_copy_mac(eth->ether_dhost, &(odata->dev_out->mac[0]));
		} else if (ofp_get_mac(odata->dev_out, odata->gw, eth->ether_dhost) < 0) {
			send_arp_request(odata->dev_out, odata->gw);
			return ofp_arp_save_ipv4_pkt(pkt, odata->nh,
						     odata->gw, odata->dev_out);
		}

		ofp_copy_mac(eth->ether_shost, odata->dev_out->mac);
		eth->ether_type = odp_cpu_to_be_16(OFP_ETHERTYPE_IP);
	} else {
Beispiel #3
0
void arp_queue_add(struct sr_instance* sr, uint8_t* packet, unsigned int len, const char* out_iface_name, struct in_addr *next_hop)
{
	assert(sr);
	assert(packet);
	assert(out_iface_name);
	assert(next_hop);

	router_state *rs = get_router_state(sr);

	/* Is there an existing queue entry for this IP? */
	arp_queue_entry* aqe = get_from_arp_queue(sr, next_hop);
	if (!aqe) {
		/* create a new queue entry */
		aqe = (arp_queue_entry*)malloc(sizeof(arp_queue_entry));
		bzero(aqe, sizeof(arp_queue_entry));
		memcpy(aqe->out_iface_name, out_iface_name, IF_LEN);
		aqe->next_hop = *next_hop;

		/* send a request */
		time(&(aqe->last_req_time));
		aqe->requests = 1;
		send_arp_request(sr, next_hop->s_addr, out_iface_name);

		arp_queue_entry_add_packet(aqe, packet, len);

		/* create a node, add this entry to the node, and push it into our linked list */
		node* n = node_create();
		n->data = aqe;

		if (rs->arp_queue == NULL) {
			rs->arp_queue = n;
		} else {
			node_push_back(rs->arp_queue, n);
		}
	} else {
		/* entry exists, just add the packet */
		arp_queue_entry_add_packet(aqe, packet, len);
	}
}
Beispiel #4
0
void handle_arpreq(struct sr_instance* sr, struct sr_arpreq* req) {
    time_t curtime = time(NULL);
    
    if (difftime(curtime,req->sent) > 1.0) {
        if (req->times_sent >= 5) {
            struct sr_packet* sr_pckt = req->packets;
            
            while (sr_pckt != NULL) {
                send_icmp_destination_host_unreachable(sr, sr_pckt->buf,
                                                       sr_pckt->len);
                sr_pckt = sr_pckt->next;
            }
            sr_arpreq_destroy(&sr->cache, req);
            
            
        } else {
            send_arp_request(sr, req);
            req->sent = curtime;
            req->times_sent = req->times_sent + 1;
        }
        
    }
}
Beispiel #5
0
int zcip_main(int argc UNUSED_PARAM, char **argv)
{
	char *r_opt;
	const char *l_opt = "169.254.0.0";
	int state;
	int nsent;
	unsigned opts;

	// Ugly trick, but I want these zeroed in one go
	struct {
		const struct ether_addr null_ethaddr;
		struct ifreq ifr;
		uint32_t chosen_nip;
		int conflicts;
		int timeout_ms; // must be signed
		int verbose;
	} L;
#define null_ethaddr (L.null_ethaddr)
#define ifr          (L.ifr         )
#define chosen_nip   (L.chosen_nip  )
#define conflicts    (L.conflicts   )
#define timeout_ms   (L.timeout_ms  )
#define verbose      (L.verbose     )

	memset(&L, 0, sizeof(L));
	INIT_G();

#define FOREGROUND (opts & 1)
#define QUIT       (opts & 2)
	// Parse commandline: prog [options] ifname script
	// exactly 2 args; -v accumulates and implies -f
	opt_complementary = "=2:vv:vf";
	opts = getopt32(argv, "fqr:l:v", &r_opt, &l_opt, &verbose);
#if !BB_MMU
	// on NOMMU reexec early (or else we will rerun things twice)
	if (!FOREGROUND)
		bb_daemonize_or_rexec(0 /*was: DAEMON_CHDIR_ROOT*/, argv);
#endif
	// Open an ARP socket
	// (need to do it before openlog to prevent openlog from taking
	// fd 3 (sock_fd==3))
	xmove_fd(xsocket(AF_PACKET, SOCK_PACKET, htons(ETH_P_ARP)), sock_fd);
	if (!FOREGROUND) {
		// do it before all bb_xx_msg calls
		openlog(applet_name, 0, LOG_DAEMON);
		logmode |= LOGMODE_SYSLOG;
	}
	bb_logenv_override();

	{ // -l n.n.n.n
		struct in_addr net;
		if (inet_aton(l_opt, &net) == 0
		 || (net.s_addr & htonl(IN_CLASSB_NET)) != net.s_addr
		) {
			bb_error_msg_and_die("invalid network address");
		}
		G.localnet_ip = ntohl(net.s_addr);
	}
	if (opts & 4) { // -r n.n.n.n
		struct in_addr ip;
		if (inet_aton(r_opt, &ip) == 0
		 || (ntohl(ip.s_addr) & IN_CLASSB_NET) != G.localnet_ip
		) {
			bb_error_msg_and_die("invalid link address");
		}
		chosen_nip = ip.s_addr;
	}
	argv += optind - 1;

	/* Now: argv[0]:junk argv[1]:intf argv[2]:script argv[3]:NULL */
	/* We need to make space for script argument: */
	argv[0] = argv[1];
	argv[1] = argv[2];
	/* Now: argv[0]:intf argv[1]:script argv[2]:junk argv[3]:NULL */
#define argv_intf (argv[0])

	xsetenv("interface", argv_intf);

	// Initialize the interface (modprobe, ifup, etc)
	if (run(argv, "init", 0))
		return EXIT_FAILURE;

	// Initialize G.iface_sockaddr
	// G.iface_sockaddr is: { u16 sa_family; u8 sa_data[14]; }
	//memset(&G.iface_sockaddr, 0, sizeof(G.iface_sockaddr));
	//TODO: are we leaving sa_family == 0 (AF_UNSPEC)?!
	safe_strncpy(G.iface_sockaddr.sa_data, argv_intf, sizeof(G.iface_sockaddr.sa_data));

	// Bind to the interface's ARP socket
	xbind(sock_fd, &G.iface_sockaddr, sizeof(G.iface_sockaddr));

	// Get the interface's ethernet address
	//memset(&ifr, 0, sizeof(ifr));
	strncpy_IFNAMSIZ(ifr.ifr_name, argv_intf);
	xioctl(sock_fd, SIOCGIFHWADDR, &ifr);
	memcpy(&G.our_ethaddr, &ifr.ifr_hwaddr.sa_data, ETH_ALEN);

	// Start with some stable ip address, either a function of
	// the hardware address or else the last address we used.
	// we are taking low-order four bytes, as top-order ones
	// aren't random enough.
	// NOTE: the sequence of addresses we try changes only
	// depending on when we detect conflicts.
	{
		uint32_t t;
		move_from_unaligned32(t, ((char *)&G.our_ethaddr + 2));
		t += getpid();
		srand(t);
	}
	// FIXME cases to handle:
	//  - zcip already running!
	//  - link already has local address... just defend/update

	// Daemonize now; don't delay system startup
	if (!FOREGROUND) {
#if BB_MMU
		bb_daemonize(0 /*was: DAEMON_CHDIR_ROOT*/);
#endif
		bb_info_msg("start, interface %s", argv_intf);
	}

	// Run the dynamic address negotiation protocol,
	// restarting after address conflicts:
	//  - start with some address we want to try
	//  - short random delay
	//  - arp probes to see if another host uses it
	//    00:04:e2:64:23:c2 > ff:ff:ff:ff:ff:ff arp who-has 169.254.194.171 tell 0.0.0.0
	//  - arp announcements that we're claiming it
	//    00:04:e2:64:23:c2 > ff:ff:ff:ff:ff:ff arp who-has 169.254.194.171 (00:04:e2:64:23:c2) tell 169.254.194.171
	//  - use it
	//  - defend it, within limits
	// exit if:
	// - address is successfully obtained and -q was given:
	//   run "<script> config", then exit with exitcode 0
	// - poll error (when does this happen?)
	// - read error (when does this happen?)
	// - sendto error (in send_arp_request()) (when does this happen?)
	// - revents & POLLERR (link down). run "<script> deconfig" first
	if (chosen_nip == 0) {
 new_nip_and_PROBE:
		chosen_nip = pick_nip();
	}
	nsent = 0;
	state = PROBE;
	while (1) {
		struct pollfd fds[1];
		unsigned deadline_us;
		struct arp_packet p;
		int ip_conflict;
		int n;

		fds[0].fd = sock_fd;
		fds[0].events = POLLIN;
		fds[0].revents = 0;

		// Poll, being ready to adjust current timeout
		if (!timeout_ms) {
			timeout_ms = random_delay_ms(PROBE_WAIT);
			// FIXME setsockopt(sock_fd, SO_ATTACH_FILTER, ...) to
			// make the kernel filter out all packets except
			// ones we'd care about.
		}
		// Set deadline_us to the point in time when we timeout
		deadline_us = MONOTONIC_US() + timeout_ms * 1000;

		VDBG("...wait %d %s nsent=%u\n",
				timeout_ms, argv_intf, nsent);

		n = safe_poll(fds, 1, timeout_ms);
		if (n < 0) {
			//bb_perror_msg("poll"); - done in safe_poll
			return EXIT_FAILURE;
		}
		if (n == 0) { // timed out?
			VDBG("state:%d\n", state);
			switch (state) {
			case PROBE:
				// No conflicting ARP packets were seen:
				// we can progress through the states
				if (nsent < PROBE_NUM) {
					nsent++;
					VDBG("probe/%u %s@%s\n",
							nsent, argv_intf, nip_to_a(chosen_nip));
					timeout_ms = PROBE_MIN * 1000;
					timeout_ms += random_delay_ms(PROBE_MAX - PROBE_MIN);
					send_arp_request(0, &null_ethaddr, chosen_nip);
					continue;
				}
  				// Switch to announce state
				nsent = 0;
				state = ANNOUNCE;
				goto send_announce;
			case ANNOUNCE:
				// No conflicting ARP packets were seen:
				// we can progress through the states
				if (nsent < ANNOUNCE_NUM) {
 send_announce:
					nsent++;
					VDBG("announce/%u %s@%s\n",
							nsent, argv_intf, nip_to_a(chosen_nip));
					timeout_ms = ANNOUNCE_INTERVAL * 1000;
					send_arp_request(chosen_nip, &G.our_ethaddr, chosen_nip);
					continue;
				}
				// Switch to monitor state
				// FIXME update filters
				run(argv, "config", chosen_nip);
				// NOTE: all other exit paths should deconfig...
				if (QUIT)
					return EXIT_SUCCESS;
				// fall through: switch to MONITOR
			default:
			// case DEFEND:
			// case MONITOR: (shouldn't happen, MONITOR timeout is infinite)
				// Defend period ended with no ARP replies - we won
				timeout_ms = -1; // never timeout in monitor state
				state = MONITOR;
				continue;
			}
		}

		// Packet arrived, or link went down.
		// We need to adjust the timeout in case we didn't receive
		// a conflicting packet.
		if (timeout_ms > 0) {
			unsigned diff = deadline_us - MONOTONIC_US();
			if ((int)(diff) < 0) {
				// Current time is greater than the expected timeout time.
				diff = 0;
			}
			VDBG("adjusting timeout\n");
			timeout_ms = (diff / 1000) | 1; // never 0
		}

		if ((fds[0].revents & POLLIN) == 0) {
			if (fds[0].revents & POLLERR) {
				// FIXME: links routinely go down;
				// this shouldn't necessarily exit.
				bb_error_msg("iface %s is down", argv_intf);
				if (state >= MONITOR) {
					// Only if we are in MONITOR or DEFEND
					run(argv, "deconfig", chosen_nip);
				}
				return EXIT_FAILURE;
			}
			continue;
		}

		// Read ARP packet
		if (safe_read(sock_fd, &p, sizeof(p)) < 0) {
			bb_perror_msg_and_die(bb_msg_read_error);
		}

		if (p.eth.ether_type != htons(ETHERTYPE_ARP))
			continue;
		if (p.arp.arp_op != htons(ARPOP_REQUEST)
		 && p.arp.arp_op != htons(ARPOP_REPLY)
		) {
			continue;
		}
#ifdef DEBUG
		{
			struct ether_addr *sha = (struct ether_addr *) p.arp.arp_sha;
			struct ether_addr *tha = (struct ether_addr *) p.arp.arp_tha;
			struct in_addr *spa = (struct in_addr *) p.arp.arp_spa;
			struct in_addr *tpa = (struct in_addr *) p.arp.arp_tpa;
			VDBG("source=%s %s\n", ether_ntoa(sha),	inet_ntoa(*spa));
			VDBG("target=%s %s\n", ether_ntoa(tha),	inet_ntoa(*tpa));
		}
#endif
		ip_conflict = 0;
		if (memcmp(&p.arp.arp_sha, &G.our_ethaddr, ETH_ALEN) != 0) {
			if (memcmp(p.arp.arp_spa, &chosen_nip, 4) == 0) {
				// A probe or reply with source_ip == chosen ip
				ip_conflict = 1;
			}
			if (p.arp.arp_op == htons(ARPOP_REQUEST)
			 && memcmp(p.arp.arp_spa, &const_int_0, 4) == 0
			 && memcmp(p.arp.arp_tpa, &chosen_nip, 4) == 0
			) {
				// A probe with source_ip == 0.0.0.0, target_ip == chosen ip:
				// another host trying to claim this ip!
				ip_conflict |= 2;
			}
		}
		VDBG("state:%d ip_conflict:%d\n", state, ip_conflict);
		if (!ip_conflict)
			continue;

		// Either src or target IP conflict exists
		if (state <= ANNOUNCE) {
			// PROBE or ANNOUNCE
			conflicts++;
			timeout_ms = PROBE_MIN * 1000
				+ CONFLICT_MULTIPLIER * random_delay_ms(conflicts);
			goto new_nip_and_PROBE;
		}

		// MONITOR or DEFEND: only src IP conflict is a problem
		if (ip_conflict & 1) {
			if (state == MONITOR) {
				// Src IP conflict, defend with a single ARP probe
				VDBG("monitor conflict - defending\n");
				timeout_ms = DEFEND_INTERVAL * 1000;
				state = DEFEND;
				send_arp_request(chosen_nip, &G.our_ethaddr, chosen_nip);
				continue;
			}
			// state == DEFEND
			// Another src IP conflict, start over
			VDBG("defend conflict - starting over\n");
			run(argv, "deconfig", chosen_nip);
			conflicts = 0;
			timeout_ms = 0;
			goto new_nip_and_PROBE;
		}
		// Note: if we only have a target IP conflict here (ip_conflict & 2),
		// IOW: if we just saw this sort of ARP packet:
		//  aa:bb:cc:dd:ee:ff > xx:xx:xx:xx:xx:xx arp who-has <chosen_nip> tell 0.0.0.0
		// we expect _kernel_ to respond to that, because <chosen_nip>
		// is (expected to be) configured on this iface.
	} // while (1)
#undef argv_intf
}
void main() {

    struct hw_ip_pair *hi_pair;
    char IP_str[20], cache_hw_addr[6];
    fd_set rset;
    int cache_ifindex, cache_hatype;
    struct hw_addr HWaddr;

    hi_pair = malloc(sizeof(struct hw_ip_pair));
    get_hw_ip_pair(hi_pair);

    printf("My IP :%s,\t HW addr", hi_pair->ip_addr);
    print_mac_to_string(hi_pair->hw_addr);
    printf("\n");

    int pf_pack_sockfd = create_pf_pack_socket();
    void* buffer = (void*)malloc(ETH_FRAME_LEN);

    int listen_sockfd, conn_sockfd, clilen, n;
    struct sockaddr_un servaddr, cliaddr;
    char sendline[MAXLINE], recvline[MAXLINE];
    struct sockaddr_in *destIP = malloc(sizeof(struct sockaddr_in));
    char ip_addr[20];
    struct arp_packet *arp_req = malloc(sizeof(struct arp_packet));
    struct arp_packet *arp_rep = malloc(sizeof(struct arp_packet));
    struct arp_packet *arp_recv = malloc(sizeof(struct arp_packet));
    struct sockaddr_ll socket_address; 
    int ll_len = sizeof(struct sockaddr_ll);
    int i=0;

    listen_sockfd = Socket(AF_LOCAL, SOCK_STREAM, 0);
    unlink(SUN_PATH_ARP);
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sun_family = AF_LOCAL;
    strcpy(servaddr.sun_path, SUN_PATH_ARP);
    Bind(listen_sockfd, (SA *) &servaddr, sizeof(servaddr));
    Listen(listen_sockfd, LISTENQ);

    int lookup_flag=0;
    clilen = sizeof(struct sockaddr_un);
    while(1) {

        FD_ZERO(&rset);

        FD_SET(listen_sockfd, &rset);
        FD_SET(pf_pack_sockfd, &rset);
        FD_SET(conn_sockfd, &rset);
        int max;

        if(conn_sockfd != 0)
            max = max(max(listen_sockfd, conn_sockfd),pf_pack_sockfd);
        else	
            max = max(listen_sockfd,pf_pack_sockfd);
        int ret = select(max+1, &rset, NULL, NULL, NULL);

        if(FD_ISSET(listen_sockfd, &rset)) {
            conn_sockfd = Accept(listen_sockfd, (SA *) &cliaddr, &clilen);
            /*			n = read(conn_sockfd, destIP, sizeof(struct sockaddr_in));
                        Inet_ntop(AF_INET, &(destIP->sin_addr), ip_addr, 20);

            // Lookup for the <HW,IP> pair in the ARP cache
            lookup_arp_cache(ip_addr, cache_hw_addr, &cache_ifindex, &cache_hatype,&lookup_flag);


            if(lookup_flag == 0) {
            printf("Entry not found from cache\n");
            create_arp_request_packet(arp_req, ip_addr, hi_pair);
            send_arp_request(pf_pack_sockfd, arp_req, hi_pair, conn_sockfd);
            }
            else{
            printf("Entry found from cache\n");
            // Send from cache
            HWaddr.sll_ifindex = cache_ifindex;
            HWaddr.sll_hatype = cache_hatype;
            HWaddr.sll_halen = sizeof(cache_hatype);

            memcpy(HWaddr.mac_addr, cache_hw_addr,6); 

            print_mac_to_string(HWaddr.mac_addr);
            Write(conn_sockfd, (void *)&HWaddr, sizeof(HWaddr));
            close(conn_sockfd);

            }
            printf("Sent ARP request\n");
             */		}

        else if(ret!= -1 && FD_ISSET(conn_sockfd, &rset)) {
            n = read(conn_sockfd, destIP, sizeof(struct sockaddr_in));
            Inet_ntop(AF_INET, &(destIP->sin_addr), ip_addr, 20);

            // Lookup for the <HW,IP> pair in the ARP cache
            lookup_arp_cache(ip_addr, cache_hw_addr, &cache_ifindex, &cache_hatype,&lookup_flag);


            if(lookup_flag == 0) {
                create_arp_request_packet(arp_req, ip_addr, hi_pair);
                printf("send 1\n");
                send_arp_request(pf_pack_sockfd, arp_req, hi_pair, conn_sockfd);
            }   
            else{
                // Send from cache
                HWaddr.sll_ifindex = cache_ifindex;
                HWaddr.sll_hatype = cache_hatype;
                HWaddr.sll_halen = sizeof(cache_hatype);

                memcpy(HWaddr.mac_addr, cache_hw_addr,6);

                //				print_mac_to_string(HWaddr.mac_addr);
                Write(conn_sockfd, (void *)&HWaddr, sizeof(HWaddr));
                close(conn_sockfd);
                conn_sockfd = 0;
            }
        }

        else if(FD_ISSET(pf_pack_sockfd, &rset)) {

            Recvfrom(pf_pack_sockfd, buffer, ETH_FRAME_LEN, 0, (SA *)&socket_address, &ll_len);
            void *data = buffer + 14;
            arp_rep = (struct arp_packet *)data;
            if (arp_rep->id == ARP_ID){
                if(arp_rep->op == ARP_REQ) {
                    if(strcmp(arp_rep->dest_IP, hi_pair->ip_addr) == 0) {

                        printf("Printing Ethernet Header and ARP Request Packet Received\n");
                        print_ethernet_and_arp(arp_rep->src_mac, arp_rep->dest_mac, arp_rep);
                        add_to_arp_cache_list(arp_rep->src_IP, arp_rep->src_mac, socket_address.sll_ifindex, socket_address.sll_hatype, conn_sockfd, 1);
                        //						print_arp_cache_list();
                        create_arp_reply_packet(arp_recv, arp_rep->src_IP, hi_pair, arp_rep->src_mac, arp_rep->id);
                        send_arp_reply(pf_pack_sockfd, arp_recv, hi_pair, socket_address.sll_ifindex);
                    }
                    else {
                        update_arp_cache(arp_rep->src_IP, arp_rep->src_mac, socket_address.sll_ifindex, 0, conn_sockfd);
                    }
                    continue;
                }
                else if(arp_rep->op == ARP_REP) {
                    if(ret == -1) {
                        delete_from_arp_cache(arp_rep->src_IP);
                        //						print_arp_cache_list();
                        continue;
                    }

                    printf("Printing Ethernet Header and ARP Reply Packet Received\n");
                    print_ethernet_and_arp(arp_rep->src_mac, arp_rep->dest_mac, arp_rep);

                    update_arp_cache(arp_rep->src_IP, arp_rep->src_mac, socket_address.sll_ifindex, 0, conn_sockfd);
                    //					print_arp_cache_list();
                    HWaddr.sll_ifindex = socket_address.sll_ifindex;
                    HWaddr.sll_hatype = socket_address.sll_hatype;
                    HWaddr.sll_halen = socket_address.sll_halen;

                    memcpy(HWaddr.mac_addr, arp_rep->src_mac,6); 

                    //					print_mac_to_string(HWaddr.mac_addr);
                    Write(conn_sockfd, (void *)&HWaddr, sizeof(HWaddr));
                    close(conn_sockfd);
                    conn_sockfd = 0;
                    update_arp_cache(arp_rep->src_IP, arp_rep->src_mac, socket_address.sll_ifindex, 0, -1);
                    //					print_arp_cache_list();
                }
            }

        }
    }
}
Beispiel #7
0
static void route_ip_packet(struct sr_instance *sr, uint8_t *packet, size_t len, char *interface) {
    // Copy the IP header
    struct ip *ip_header = calloc(1, sizeof(struct ip));
    memcpy(ip_header, packet + sizeof(struct sr_ethernet_hdr), sizeof(struct ip));

    // The IP header is a dirty liar
    int actual_header_length = ip_header->ip_hl * 4;
    int ip_packet_len = len - sizeof(struct sr_ethernet_hdr);

    // Decrement the TTL and check if it's 0
    ip_header->ip_ttl -= 1;
    if(ip_header->ip_ttl <= 0) {
        return;
    }

    // Zero out the old checksum
    ip_header->ip_sum = 0;

    // Create a buffer to calculate the checksum
    uint16_t *header_buffer;

    // Create a chunk of memory aligned to 16 bits
    posix_memalign((void **) &header_buffer, CHECKSUM_ALIGNMENT, actual_header_length);
    bzero(header_buffer, actual_header_length);

    // Copy required IP header fields
    memcpy(header_buffer, ip_header, sizeof(struct ip));

    // Copy the original IP header flags
    memcpy(header_buffer, packet + sizeof(struct sr_ethernet_hdr) + sizeof(struct ip),
            actual_header_length - sizeof(struct ip));

    // Calculate the new checksum
    ip_header->ip_sum = header_checksum(header_buffer, actual_header_length / 2);

    free(header_buffer);

    // Get the IP packet's destination
    struct in_addr destination_addr = ip_header->ip_dst;
    uint32_t destination_ip = destination_addr.s_addr;

    // Check if we're the destination
    struct sr_if *iface = sr_get_interface(sr, interface);
    if(destination_ip == iface->ip) {
        printf("Dropping packet bound for router on %s\n", interface);
        return;
    }

    // Check the routing table for the correct gateway to forward the packet through
    struct sr_rt *table_entry = search_routing_table(sr, destination_ip);

    printf("\tThe nexthop is %s\n", inet_ntoa(table_entry->gw));

    if(table_entry) {
        // Get the interface for the gateway
        struct sr_if *gw_iface = sr_get_interface(sr, table_entry->interface);

        // Determine the IP to forward to
        struct in_addr nexthop;

        // Determine if the IP to forward to is in our network
        if(table_entry->gw.s_addr == 0) {
            nexthop = destination_addr;
        } else {
            nexthop = table_entry->gw;
        }

        // Create an updated IP packet with the correct headers/data
        uint8_t *updated_packet = calloc(ip_packet_len, sizeof(uint8_t));
        memcpy(updated_packet, ip_header, actual_header_length);
        memcpy(updated_packet + actual_header_length,
                packet + sizeof(struct sr_ethernet_hdr ) + actual_header_length,
                len - sizeof(struct sr_ethernet_hdr ) - actual_header_length);

        // Search the ARP cache for the nexthop
        uint8_t *gw_addr = search_arp_cache(cache, nexthop.s_addr);

        if(gw_addr) {
            printf("\tForwarding packet bound for %s through next hop @ ",
                    inet_ntoa(destination_addr));
            printf("%s (", inet_ntoa(table_entry->gw));
            print_ethernet_addr(gw_addr, stdout);
            printf(")\n");

            uint8_t *buffer = pack_ethernet_packet(gw_addr, gw_iface->addr, ETHERTYPE_IP,
                    updated_packet, ip_packet_len);

            sr_send_packet(sr, buffer, len, gw_iface->name);
        } else {
            // Otherwise we cache the IP packet and make an ARP request
            printf("\tSending ARP request to %s (%s), to forward packet bound for ",
                    inet_ntoa(nexthop), gw_iface->name);
            printf("%s\n", inet_ntoa(destination_addr));

            add_ip_cache_entry(ip_cache, updated_packet, nexthop, ip_packet_len);
            send_arp_request(sr, gw_iface, nexthop);
        }

    } else {
        // TODO: What do we do here?
    }
}
/**
 * \brief detect and resolve IP conflict
 * \param the ethernet interface entry in the MIB for which we change the IP
 * \param interface the name of this interface (eth0/enp2s0/lo...)
 * \return TRUE if conflict could be resolved, FALSE otherwise
 */
gboolean ip_conflict_detection(  struct ethernetIfTableEntry *if_entry, gchar *interface ){

	g_debug ("ip_conflict_detection()" );

	/* select a random time to wait between 0 en PROBE_WAIT */
	srand(time(NULL));
	/* PROBE_WAIT is given in second, if we want a integer value for microsecond , we should multiply it by 1000000 */
	gdouble probe_wait =  ((gdouble) rand()/ (gdouble)(RAND_MAX)) * PROBE_WAIT;
	/* send PROB_NUM ARP PROBE messages between space randomly between PROBE_MIN and PROBE_MAX number*/
	gdouble space = (((gdouble) rand()/ (gdouble)(RAND_MAX)) /  (gdouble) ((PROBE_MAX - PROBE_MIN) * PROBE_NUM));
	gdouble time_passed = 0 ;
	gboolean conflict = TRUE ;
	in_addr_t max_ip_value = inet_addr ( DEFAULT_STATIC_IP ) ;

	GTimer *timer = g_timer_new();

	/* wait probe_wait */
	g_debug ("waiting %G second(s)", probe_wait);
	g_timer_start( timer );
	while(time_passed < probe_wait){
		time_passed = g_timer_elapsed ( timer, NULL );
	}

	int sending_socket_fd;
	struct sockaddr_ll sa;
	if ( !prepare_arp_request_socket (if_entry , &sending_socket_fd , &sa )){
		g_critical("cannot prepare socket for ARP request");
		return FALSE;
	}

	/* variable for the ethernet frame to build */
	struct arp_packet pkt;
	int ethernet_frame_length;
	uint8_t *ethernet_frame;

	while ( conflict ){

		/* build the ethernet frame */
		ethernet_frame = init_ethernet_frame (if_entry , &pkt, &ethernet_frame_length, TRUE );
		if ( !ethernet_frame  ){
			g_critical("cannot build ethernet frame for ARP request");
			return FALSE;
		}

		/* wait PROBE_MIN */
		g_debug ("waiting %d second(s)", PROBE_MIN);
		g_timer_reset( timer );
		time_passed = g_timer_elapsed ( timer, NULL );
		while( time_passed  <  (PROBE_MIN) ){
			time_passed = g_timer_elapsed ( timer, NULL );
		}

		/* send ARP PROBE message PROBE_NUM times with an interval probe_wait */
		g_debug("send ARP Probe message %d times every %G second(s)", PROBE_NUM, space);
		for( int i = 1 ; i <= PROBE_NUM ; i ++){

			g_timer_reset( timer );
			time_passed = g_timer_elapsed ( timer, NULL );
			while( time_passed  <  space ){
				time_passed = g_timer_elapsed ( timer, NULL );
			}

			send_arp_request( sending_socket_fd , ethernet_frame, ethernet_frame_length, sa );

		}

		conflict = receive_arp_reply( ) ;

		/* if receive_arp_reply return FALSE there is a conflict, else, we are fine with this IP  */
		if ( conflict ){
			struct in_addr device_ip;
			device_ip.s_addr = if_entry->ethernetIfIpAddress ;
			g_debug("IP address %s already in use", inet_ntoa ( device_ip ));
			/* pick up a new random IP */
			if_entry->ethernetIfIpAddressConflict 	= if_entry->ethernetIfIpAddress ;
			if_entry->ethernetIfIpAddress 			= random_ip_for_conflict(interface);
			if ( if_entry->ethernetIfIpAddress == max_ip_value )
			   return TRUE;
			/* send trap */
			send_ipAddressConflict_trap();
		}
	}

	/* build and send probe message */
	ethernet_frame = init_ethernet_frame (if_entry , &pkt, &ethernet_frame_length, FALSE );
	send_arp_request( sending_socket_fd , ethernet_frame, ethernet_frame_length, sa );

	/* close sockets */
	close ( sending_socket_fd );

	/* free the ethernet frame build */
	free(ethernet_frame);

	return FALSE;

}
Beispiel #9
0
/*
 * HELPER function called from arp_thread
 */
void process_arp_queue(struct sr_instance* sr) {
	router_state* rs = get_router_state(sr);
	node* n = get_router_state(sr)->arp_queue;
	node* next = NULL;
	time_t now;
	double diff;

	while (n) {
		next = n->next;

		arp_queue_entry* aqe = (arp_queue_entry*)n->data;

		/* has it been over a second since the last arp request was sent? */
		time(&now);
		diff = difftime(now, aqe->last_req_time);
		if (diff > 1) {
			/* have we sent less than 5 arp requests? */
			if (aqe->requests < 5) {
				/* send another */
				time(&(aqe->last_req_time));
				++(aqe->requests);
				send_arp_request(sr, aqe->next_hop.s_addr, aqe->out_iface_name);
			} else {
				/* we have exceeded the max arp requests, return packets to sender */
				node* cur_packet_node = aqe->head;
				node* next_packet_node = NULL;

				while (cur_packet_node) {
					/* send icmp for the packet, free it, and its encasing entry */
					arp_queue_packet_entry* aqpe = (arp_queue_packet_entry*)cur_packet_node->data;

					/* only send an icmp error if the packet is not icmp, or if it is, its an echo request or reply
					 * also ensure we don't send an icmp error back to one of our interfaces
					 */
					if ((get_ip_hdr(aqpe->packet, aqpe->len)->ip_p != IP_PROTO_ICMP) ||
							(get_icmp_hdr(aqpe->packet, aqpe->len)->icmp_type == ICMP_TYPE_ECHO_REPLY) ||
							(get_icmp_hdr(aqpe->packet, aqpe->len)->icmp_type == ICMP_TYPE_ECHO_REQUEST)) {

					 	/* also ensure we don't send an icmp error back to one of our interfaces */
						if (!iface_match_ip(rs, get_ip_hdr(aqpe->packet, aqpe->len)->ip_src.s_addr)) {
							/* Total hack here to increment the TTL since we already decremented it earlier in the pipeline
							 * and the ICMP error should return the original packet.
							 * TODO: Don't decrement the TTL until the packet is ready to be put on the wire
							 * and we have the next hop ARP address, although checking should be done
							 * where it is currently being decremented to minimize effort on a doomed packet */
							ip_hdr *ip = get_ip_hdr(aqpe->packet, aqpe->len);
							if (ip->ip_ttl < 255) {
								ip->ip_ttl++;

								/* recalculate checksum */
								bzero(&ip->ip_sum, sizeof(uint16_t));
								uint16_t checksum = htons(compute_ip_checksum(ip));
								ip->ip_sum = checksum;
							}

							send_icmp_packet(sr, aqpe->packet, aqpe->len, ICMP_TYPE_DESTINATION_UNREACHABLE, ICMP_CODE_HOST_UNREACHABLE);
						}
					}

					free(aqpe->packet);
					next_packet_node = cur_packet_node->next;
					//free(cur_packet_node);   /* IS THIS CORRECT TO FREE IT ? */
					node_remove(&(aqe->head), cur_packet_node);
					cur_packet_node = next_packet_node;
				}

				/* free the arp queue entry for this destination ip, and patch the list */
				node_remove(&(get_router_state(sr)->arp_queue), n);
			}
		}

		n = next;
	}
}