static void arp_input(const uint8_t *pkt, int pkt_len) { struct ethhdr *eh = (struct ethhdr *)pkt; struct arphdr *ah = (struct arphdr *)(pkt + ETH_HLEN); uint8_t arp_reply[ETH_HLEN + sizeof(struct arphdr)]; struct ethhdr *reh = (struct ethhdr *)arp_reply; struct arphdr *rah = (struct arphdr *)(arp_reply + ETH_HLEN); int ar_op; struct ex_list *ex_ptr; ar_op = ntohs(ah->ar_op); switch(ar_op) { uint32_t ar_tip_ip; case ARPOP_REQUEST: ar_tip_ip = ip_read32h(ah->ar_tip); if ((ar_tip_ip & 0xffffff00) == special_addr_ip) { uint32_t ar_tip_low = ar_tip_ip & 0xff; if ( CTL_IS_DNS(ar_tip_low) || ar_tip_low == CTL_ALIAS) goto arp_ok; for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) { if (ex_ptr->ex_addr == ar_tip_low) goto arp_ok; } return; arp_ok: memcpy(client_ethaddr, eh->h_source, ETH_ALEN); memcpy(reh->h_dest, pkt + ETH_ALEN, ETH_ALEN); memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 1); reh->h_source[5] = ar_tip_low; reh->h_proto = htons(ETH_P_ARP); rah->ar_hrd = htons(1); rah->ar_pro = htons(ETH_P_IP); rah->ar_hln = ETH_ALEN; rah->ar_pln = 4; rah->ar_op = htons(ARPOP_REPLY); memcpy(rah->ar_sha, reh->h_source, ETH_ALEN); memcpy(rah->ar_sip, ah->ar_tip, 4); memcpy(rah->ar_tha, ah->ar_sha, ETH_ALEN); memcpy(rah->ar_tip, ah->ar_sip, 4); slirp_output(arp_reply, sizeof(arp_reply)); } break; case ARPOP_REPLY: if (!memcmp(client_ethaddr, zero_ethaddr, ETH_ALEN) && ip_equal( ip_read(ah->ar_sip), client_ip )) { memcpy(client_ethaddr, ah->ar_sha, ETH_ALEN); } break; default: break; } }
/* * sendto() a socket */ int sosendto(struct socket *so, struct mbuf *m) { int ret; SockAddress addr; uint32_t addr_ip; uint16_t addr_port; DEBUG_CALL("sosendto"); DEBUG_ARG("so = %lx", (long)so); DEBUG_ARG("m = %lx", (long)m); if ((so->so_faddr_ip & 0xffffff00) == special_addr_ip) { /* It's an alias */ int low = so->so_faddr_ip & 0xff; if ( CTL_IS_DNS(low) ) addr_ip = dns_addr[low - CTL_DNS]; else addr_ip = loopback_addr_ip; } else addr_ip = so->so_faddr_ip; addr_port = so->so_faddr_port; /* * test for generic forwarding; this function replaces the arguments * only on success */ unsigned long faddr = addr_ip; int fport = addr_port; if (slirp_should_net_forward(faddr, fport, &faddr, &fport)) { time_t timestamp = time(NULL); slirp_drop_log( "Redirected UDP: src: 0x%08lx:0x%04x org dst: 0x%08lx:0x%04x " "new dst: 0x%08lx:0x%04x %ld\n", so->so_laddr_ip, so->so_laddr_port, addr_ip, addr_port, faddr, fport, timestamp ); } addr_ip = faddr; addr_port = fport; sock_address_init_inet(&addr, addr_ip, addr_port); DEBUG_MISC((dfd, " sendto()ing, addr.sin_port=%d, addr.sin_addr.s_addr=%08x\n", addr_port, addr_ip)); /* Don't care what port we get */ ret = socket_sendto(so->s, m->m_data, m->m_len,&addr); if (ret < 0) return -1; /* * Kill the socket if there's no reply in 4 minutes, * but only if it's an expirable socket */ if (so->so_expire) so->so_expire = curtime + SO_EXPIRE; so->so_state = SS_ISFCONNECTED; /* So that it gets select()ed */ return 0; }