/* * Reset algorithm is not stated directly in RFC 793, * but we can conclude it according to all reset generation. * NOTE: maybe @tsk is NULL */ void tcp_send_reset(struct tcp_sock *tsk, struct tcp_segment *seg) { struct tcp *otcp, *tcphdr = seg->tcphdr; struct pkbuf *opkb; if (tcphdr->rst) return; opkb = alloc_pkb(ETH_HRD_SZ + IP_HRD_SZ + TCP_HRD_SZ); /* fill tcp head */ otcp = (struct tcp *)pkb2ip(opkb)->ip_data; otcp->src = tcphdr->dst; otcp->dst = tcphdr->src; if (tcphdr->ack) { /* * Should we set ack? * -Yes for xinu, it always set ack to seq+len * +No for Linux * +No for tapip */ otcp->seq = tcphdr->ackn; } else { otcp->ackn = _htonl(seg->seq + seg->len); otcp->ack = 1; } otcp->doff = TCP_HRD_DOFF; otcp->rst = 1; tcpdbg("send RESET from "IPFMT":%d to "IPFMT":%d", ipfmt(seg->iphdr->ip_dst), _ntohs(otcp->src), ipfmt(seg->iphdr->ip_src), _ntohs(otcp->dst)); tcp_send_out(NULL, opkb, seg); }
static int udp_init_pkb(struct sock *sk, struct pkbuf *pkb, void *buf, int size, struct sock_addr *skaddr) { struct ip *iphdr = pkb2ip(pkb); struct udp *udphdr = (struct udp *)iphdr->ip_data; /* fill ip head */ iphdr->ip_hlen = IP_HRD_SZ >> 2; iphdr->ip_ver = IP_VERSION_4; iphdr->ip_tos = 0; iphdr->ip_len = _htons(pkb->pk_len - ETH_HRD_SZ); iphdr->ip_id = _htons(udp_id); iphdr->ip_fragoff = 0; iphdr->ip_ttl = UDP_DEFAULT_TTL; iphdr->ip_pro = sk->protocol; /* IP_P_UDP */ iphdr->ip_dst = skaddr->dst_addr; /* FIXME:use the sk->rt_dst */ if (rt_output(pkb) < 0) /* fill ip src */ return -1; /* fill udp */ udphdr->src = sk->sk_sport; /* bound local address */ udphdr->dst = skaddr->dst_port; udphdr->length = _htons(size + UDP_HRD_SZ); memcpy(udphdr->data, buf, size); udpdbg(IPFMT":%d" "->" IPFMT":%d(proto %d)", ipfmt(iphdr->ip_src), _ntohs(udphdr->src), ipfmt(iphdr->ip_dst), _ntohs(udphdr->dst), iphdr->ip_pro); udp_set_checksum(iphdr, udphdr); return 0; }
static void icmp_redirect(struct icmp_desc *icmp_desc, struct pkbuf *pkb) { struct ip *iphdr = pkb2ip(pkb); struct icmp *icmphdr = ip2icmp(iphdr); if (icmphdr->icmp_code > 4) icmpdbg("Redirect code %d is error", icmphdr->icmp_code); else icmpdbg("from " IPFMT " %s(new nexthop "IPFMT")", ipfmt(iphdr->ip_src), redirectstr[icmphdr->icmp_code], ipfmt(icmphdr->icmp_gw)); free_pkb(pkb); }
void tcp_send_synack(struct tcp_sock *tsk, struct tcp_segment *seg) { /* * LISTEN : * SYN-SENT: * SEG: SYN, no ACK, no RST * <SEQ=ISS><ACK=RCV.NXT><CTL=SYN,ACK> * (ISS == SND.NXT) */ struct tcp *otcp, *tcphdr = seg->tcphdr; struct pkbuf *opkb; if (tcphdr->rst) return; opkb = alloc_pkb(ETH_HRD_SZ + IP_HRD_SZ + TCP_HRD_SZ); /* fill tcp head */ otcp = (struct tcp *)pkb2ip(opkb)->ip_data; otcp->src = tcphdr->dst; otcp->dst = tcphdr->src; otcp->doff = TCP_HRD_DOFF; otcp->seq = _htonl(tsk->iss); otcp->ackn = _htonl(tsk->rcv_nxt); otcp->syn = 1; otcp->ack = 1; otcp->window = _htons(tsk->rcv_wnd); tcpdbg("send SYN(%u)/ACK(%u) [WIN %d] to "IPFMT":%d", _ntohl(otcp->seq), _ntohs(otcp->window), _ntohl(otcp->ackn), ipfmt(seg->iphdr->ip_dst), _ntohs(otcp->dst)); tcp_send_out(tsk, opkb, seg); }
void tcp_send_fin(struct tcp_sock *tsk) { struct tcp *otcp; struct pkbuf *opkb; opkb = alloc_pkb(ETH_HRD_SZ + IP_HRD_SZ + TCP_HRD_SZ); /* fill tcp head */ otcp = (struct tcp *)pkb2ip(opkb)->ip_data; otcp->src = tsk->sk.sk_sport; otcp->dst = tsk->sk.sk_dport; otcp->doff = TCP_HRD_DOFF; otcp->seq = _htonl(tsk->snd_nxt); otcp->window = _htons(tsk->rcv_wnd); otcp->fin = 1; /* * Should we send an ACK? * Yes, tcp stack will drop packet if it has no ACK bit * according to RFC 793 #SEGMENT RECEIVE */ otcp->ackn = _htonl(tsk->rcv_nxt); otcp->ack = 1; tcpdbg("send FIN(%u)/ACK(%u) [WIN %d] to "IPFMT":%d", _ntohl(otcp->seq), _ntohl(otcp->ackn), _ntohs(otcp->window), ipfmt(tsk->sk.sk_daddr), _ntohs(otcp->dst)); tcp_send_out(tsk, opkb, NULL); }
static void send_packet(void) { if (!buf) buf = xmalloc(size + ICMP_HRD_SZ); struct icmp *icmphdr = (struct icmp *)buf; static int first = 1; if (first) { printf("PING "IPFMT" %d(%d) bytes of data\n", ipfmt(ipaddr), size, size + ICMP_HRD_SZ + IP_HRD_SZ); first = 0; } /* fill icmp data */ memset(icmphdr->icmp_data, 'x', size); icmphdr->icmp_type = ICMP_T_ECHOREQ; icmphdr->icmp_code = 0; icmphdr->icmp_id = _htons(id); icmphdr->icmp_seq = _htons(seq); icmphdr->icmp_cksum = 0; icmphdr->icmp_cksum = icmp_chksum((unsigned short *)icmphdr, ICMP_HRD_SZ + size); seq++; /* socket apis */ _send(sock, buf, ICMP_HRD_SZ + size, &skaddr); psend++; }
static void ping_stat(void) { printf( "\n" "--- " IPFMT " ping statistics ---\n" "%d packets transmitted, %d received, %d%% packet loss\n", ipfmt(ipaddr), psend, precv, (psend - precv) * 100 / psend); }
static void icmp_echo_reply(struct icmp_desc *icmp_desc, struct pkbuf *pkb) { struct ip *iphdr = pkb2ip(pkb); struct icmp *icmphdr = ip2icmp(iphdr); icmpdbg("from "IPFMT" id %d seq %d ttl %d", ipfmt(iphdr->ip_src), _ntohs(icmphdr->icmp_id), _ntohs(icmphdr->icmp_seq), iphdr->ip_ttl); free_pkb(pkb); }
void getipaddr_tap(unsigned char *name, unsigned int *ipaddr) { struct ifreq ifr = {}; struct sockaddr_in *saddr; strcpy(ifr.ifr_name, (char *)name); if (ioctl(skfd, SIOCGIFADDR, (void *)&ifr) < 0) { close(skfd); perrx("socket SIOCGIFADDR"); } saddr = (struct sockaddr_in *)&ifr.ifr_addr; *ipaddr = saddr->sin_addr.s_addr; dbg("get IPaddr: "IPFMT, ipfmt(*ipaddr)); }
/* NOTE: icmp dont drop @ipkb */ void icmp_send(unsigned char type, unsigned char code, unsigned int data, struct pkbuf *pkb_in) { struct pkbuf *pkb; struct ip *iphdr = pkb2ip(pkb_in); struct icmp *icmphdr; int paylen = _ntohs(iphdr->ip_len); /* icmp payload length */ if (paylen < iphlen(iphdr) + 8) return; /* * RFC 1812 Section 4.3.2.7 for sanity check * An ICMP error message MUST NOT be sent as the result of receiving: * 1. A packet sent as a Link Layer broadcast or multicast * 2. A packet destined to an IP broadcast or IP multicast address *[3] A packet whose source address has a network prefix of zero or is an * invalid source address (as defined in Section [5.3.7]) * 4. Any fragment of a datagram other then the first fragment (i.e., a * packet for which the fragment offset in the IP header is nonzero). * 5. An ICMP error message */ if (pkb_in->pk_type != PKT_LOCALHOST) return; if (MULTICAST(iphdr->ip_dst) || BROADCAST(iphdr->ip_dst)) return; if (iphdr->ip_fragoff & _htons(IP_FRAG_OFF)) return; if (icmp_type_error(type) && iphdr->ip_pro == IP_P_ICMP) { icmphdr = ip2icmp(iphdr); if (icmphdr->icmp_type > ICMP_T_MAXNUM || icmp_error(icmphdr)) return; } /* build icmp packet and send */ /* ip packet size must be smaller than 576 bytes */ if (IP_HRD_SZ + ICMP_HRD_SZ + paylen > 576) paylen = 576 - IP_HRD_SZ - ICMP_HRD_SZ; pkb = alloc_pkb(ETH_HRD_SZ + IP_HRD_SZ + ICMP_HRD_SZ + paylen); icmphdr = (struct icmp *)(pkb2ip(pkb)->ip_data); icmphdr->icmp_type = type; icmphdr->icmp_code = code; icmphdr->icmp_cksum = 0; icmphdr->icmp_undata = data; memcpy(icmphdr->icmp_data, (unsigned char *)iphdr, paylen); icmphdr->icmp_cksum = icmp_chksum((unsigned short *)icmphdr, ICMP_HRD_SZ + paylen); icmpdbg("to "IPFMT"(payload %d) [type %d code %d]\n", ipfmt(iphdr->ip_src), paylen, type, code); ip_send_info(pkb, 0, IP_HRD_SZ + ICMP_HRD_SZ + paylen, 0, IP_P_ICMP, iphdr->ip_src); }
void setipaddr_tap(unsigned char *name, unsigned int ipaddr) { struct ifreq ifr = {}; struct sockaddr_in *saddr; strcpy(ifr.ifr_name, (char *)name); saddr = (struct sockaddr_in *)&ifr.ifr_addr; saddr->sin_family = AF_INET; saddr->sin_addr.s_addr = ipaddr; if (ioctl(skfd, SIOCSIFADDR, (void *)&ifr) < 0) { close(skfd); perrx("socket SIOCSIFADDR"); } dbg("set IPaddr: "IPFMT, ipfmt(ipaddr)); }
void setnetmask_tap(unsigned char *name, unsigned int netmask) { struct ifreq ifr = {}; struct sockaddr_in *saddr; strcpy(ifr.ifr_name, (char *)name); saddr = (struct sockaddr_in *)&ifr.ifr_netmask; saddr->sin_family = AF_INET; saddr->sin_addr.s_addr = netmask; if (ioctl(skfd, SIOCSIFNETMASK, (void *)&ifr) < 0) { close(skfd); perrx("socket SIOCSIFNETMASK"); } dbg("set Netmask: "IPFMT, ipfmt(netmask)); }
struct arpentry *arp_lookup(unsigned short pro, unsigned int ipaddr) { struct arpentry *ae, *ret = NULL; arp_cache_lock(); arpdbg("pro:%d "IPFMT, pro, ipfmt(ipaddr)); for (ae = arp_cache_head; ae < arp_cache_end; ae++) { if (ae->ae_state == ARP_FREE) continue; if (ae->ae_pro == pro && ae->ae_ipaddr == ipaddr) { ret = ae; break; } } arp_cache_unlock(); return ret; }
static int veth_dev_init(struct netdev *dev) { /* init tap: out network nic */ if (tap_dev_init() < 0) perrx("Cannot init tap device"); /* init veth: information for our netstack */ dev->net_mtu = tap->dev.net_mtu; dev->net_ipaddr = FAKE_IPADDR; dev->net_mask = FAKE_NETMASK; hwacpy(dev->net_hwaddr, FAKE_HWADDR); dbg("%s ip address: " IPFMT, dev->net_name, ipfmt(dev->net_ipaddr)); dbg("%s hw address: " MACFMT, dev->net_name, macfmt(dev->net_hwaddr)); /* net stats have been zero */ return 0; }
static void tcp_init_text(struct tcp_sock *tsk, struct pkbuf *pkb, void *buf, int size) { struct tcp *tcphdr = pkb2tcp(pkb); tcphdr->src = tsk->sk.sk_sport; tcphdr->dst = tsk->sk.sk_dport; tcphdr->doff = TCP_HRD_DOFF; tcphdr->seq = _htonl(tsk->snd_nxt); tcphdr->ackn = _htonl(tsk->rcv_nxt); tcphdr->ack = 1; tcphdr->window = _htons(tsk->rcv_wnd); memcpy(tcphdr->data, buf, size); tsk->snd_nxt += size; tsk->snd_wnd -= size; tcpsdbg("send TEXT(%u:%d) [WIN %d] to "IPFMT":%d", _ntohl(tcphdr->seq), size, _ntohs(tcphdr->window), ipfmt(tsk->sk.sk_daddr), _ntohs(tcphdr->dst)); }
void ifinfo(struct netdev *dev) { printf("%-10sHWaddr "MACFMT"\n" " IPaddr "IPFMT"\n" " mtu %d\n" " RX packet:%u bytes:%u errors:%u\n" " TX packet:%u bytes:%u errors:%u\n", dev->net_name, macfmt(dev->net_hwaddr), ipfmt(dev->net_ipaddr), dev->net_mtu, dev->net_stats.rx_packets, dev->net_stats.rx_bytes, dev->net_stats.rx_errors, dev->net_stats.tx_packets, dev->net_stats.tx_bytes, dev->net_stats.tx_errors); }
void tcp_send_syn(struct tcp_sock *tsk, struct tcp_segment *seg) { /* * SYN-SENT: */ struct tcp *otcp; struct pkbuf *opkb; opkb = alloc_pkb(ETH_HRD_SZ + IP_HRD_SZ + TCP_HRD_SZ); /* fill tcp head */ otcp = (struct tcp *)pkb2ip(opkb)->ip_data; otcp->src = tsk->sk.sk_sport; otcp->dst = tsk->sk.sk_dport; otcp->doff = TCP_HRD_DOFF; otcp->seq = _htonl(tsk->iss); otcp->syn = 1; otcp->window = _htons(tsk->rcv_wnd); tcpdbg("send SYN(%u) [WIN %d] to "IPFMT":%d", _ntohl(otcp->seq), _ntohs(otcp->window), ipfmt(tsk->sk.sk_daddr), _ntohs(otcp->dst)); tcp_send_out(tsk, opkb, seg); }
static void recv_packet(void) { struct pkbuf *pkb; struct ip *iphdr; struct icmp *icmphdr; while (!finite || recv > 0) { pkb = _recv(sock); if (!pkb) break; iphdr = pkb2ip(pkb); icmphdr = ip2icmp(iphdr); if (iphdr->ip_pro == IP_P_ICMP && _ntohs(icmphdr->icmp_id) == id && icmphdr->icmp_type == ICMP_T_ECHORLY) { recv--; printf("%d bytes from " IPFMT ": icmp_seq=%d ttl=%d\n", ipdlen(iphdr), ipfmt(iphdr->ip_src), _ntohs(icmphdr->icmp_seq), iphdr->ip_ttl); precv++; } free_pkb(pkb); } }
/* * Acknowledgment algorithm is not stated directly in RFC 793, * but we can conclude it from all acknowledgment situation. */ void tcp_send_ack(struct tcp_sock *tsk, struct tcp_segment *seg) { /* * SYN-SENT : * SEG: SYN, acceptable ACK, no RST (SND.NXT = SEG.SEQ+1) * <SEQ=SND.NXT><ACK=RCV.NXT><CTL=ACK> * SYN-RECEIVED / ESTABLISHED / FIN-WAIT-1 / FIN-WAIT-2 / * CLOSE-WAIT / CLOSING / LAST-ACK / TIME-WAIT : * SEG: no RST, ??ACK, ??SYN (segment is not acceptable) * <SEQ=SND.NXT><ACK=RCV.NXT><CTL=ACK> * ESTABLISHED / FIN-WAIT-1 / FIN-WAIT-2 / process the segment text: * SEG: ACK, no RST * <SEQ=SND.NXT><ACK=RCV.NXT><CTL=ACK> * (This acknowledgment should be piggybacked on a segment being * transmitted if possible without incurring undue delay.) */ struct tcp *otcp, *tcphdr = seg->tcphdr; struct pkbuf *opkb; if (tcphdr->rst) return; opkb = alloc_pkb(ETH_HRD_SZ + IP_HRD_SZ + TCP_HRD_SZ); /* fill tcp head */ otcp = (struct tcp *)pkb2ip(opkb)->ip_data; otcp->src = tcphdr->dst; otcp->dst = tcphdr->src; otcp->doff = TCP_HRD_DOFF; otcp->seq = _htonl(tsk->snd_nxt); otcp->ackn = _htonl(tsk->rcv_nxt); otcp->ack = 1; otcp->window = _htons(tsk->rcv_wnd); tcpdbg("send ACK(%u) [WIN %d] to "IPFMT":%d", _ntohl(otcp->ackn), _ntohs(otcp->window), ipfmt(seg->iphdr->ip_src), _ntohs(otcp->dst)); tcp_send_out(tsk, opkb, seg); }
char *ipnfmt(unsigned int ipaddr) { static char ipbuf[16]; snprintf(ipbuf, 16, IPFMT, ipfmt(ipaddr)); return ipbuf; }
int cl_setup_promisc(struct netdev *nd) { char buf[1024]={0}; struct ifconf ifc; struct ifreq *ifr; int if_cnt; int yes; struct sockaddr_ll sll; /* set netlink socket */ nd->nd_fd = socket(PF_PACKET,SOCK_RAW,htons(ETH_P_ALL)); if(nd->nd_fd == -1) { perrx("socket:PF_PACKET"); return -1; } memset(&ifc,0,sizeof(ifc)); memset(&ifr,0,sizeof(ifr)); ifc.ifc_len = sizeof(buf); ifc.ifc_buf = buf; if(ioctl(nd->nd_fd,SIOCGIFCONF,&ifc) < 0) { perrx("ioctl:SIOCGIFCONF"); return -1; } /* list all network interfaces then look for the desired one */ ifr = ifc.ifc_req; if_cnt =ifc.ifc_len / sizeof(struct ifreq); ifr = lookup_dev(ifr,&if_cnt,nd); if(ifr == NULL) { perrx("Couldn't get device name \n"); return -1; } #ifdef IFCONF printfd(2,"interface index : %d\n",ifr->ifr_ifindex); printfd(2,"interface address : "IPFMT"\n", ipfmt((int)(((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr.s_addr))); printfd(2,"interface netmask : "IPFMT"\n", ipfmt((int)(((struct sockaddr_in *)&ifr->ifr_netmask)->sin_addr.s_addr))); #endif /* make sure that the interface is UP & RUNNING */ ifr->ifr_flags |= IFF_PROMISC; ifr->ifr_flags |= IFF_UP |IFF_RUNNING; if(ioctl(nd->nd_fd, SIOCSIFFLAGS, ifr) < 0) { perrx("ioctl:SIOCGIFCONF"); return -1; } /* get interface index */ if (ioctl(nd->nd_fd,SIOCGIFINDEX,ifr)==-1) { perrx("SIOCGIFINDEX"); } if (setsockopt(nd->nd_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1) { perrx("setsockopt:SO_REUSEADDR"); return -1; } /* No need for this if (setsockopt(nd->nd_fd, SOL_SOCKET, SO_BINDTODEVICE, ifr->ifr_name, IFNAMSIZ-1) == -1) { perrx("SO_BINDTODEVICE"); return -1; } */ memset(&sll,0,sizeof(sll)); sll.sll_family = AF_PACKET; sll.sll_ifindex = ifr->ifr_ifindex; sll.sll_protocol = htons(ETH_P_ALL); if(bind(nd->nd_fd,(struct sockaddr*)&sll,sizeof(sll)) == -1) { perrx("bind"); return -1; } nd->nd_ops->xmit(nd,NULL); return 0; }