#include #include #include #include #include #include #include #include #include #include "pktlib.h" #include "pktbuf.h" #include "arplib.h" static char *make_srcmacaddr(in_addr_t ipaddr) { static char macaddr[ETHER_ADDR_LEN]; ipaddr = htonl(ipaddr); macaddr[0] = 0x00; macaddr[1] = 0x11; memcpy(&macaddr[2], &ipaddr, sizeof(in_addr_t)); return macaddr; } static in_addr_t proc_ip(pktbuf_t pktbuf, in_addr_t my_ipaddr) { char *p; struct ip iphdr; struct icmp *icmphdr; int hdrsize, cksum; p = pktbuf_get_header(pktbuf); /* アラインメントずれを考慮して,ローカル領域上で処理する */ memcpy(&iphdr, p, sizeof(iphdr)); hdrsize = iphdr.ip_hl << 2; if (iphdr.ip_p != IPPROTO_ICMP) return 0; if (ntohl(iphdr.ip_dst.s_addr) != my_ipaddr) return 0; icmphdr = (struct icmp *)(p + hdrsize); if (icmphdr->icmp_type != ICMP_ECHO) return 0; fprintf(stderr, "RECV ICMP Echo %-15s", inet_ntoa(iphdr.ip_src)); fprintf(stderr, " -> %-15s\n", inet_ntoa(iphdr.ip_dst)); icmphdr->icmp_type = ICMP_ECHOREPLY; cksum = ~ntohs(icmphdr->icmp_cksum) & 0xffff; cksum += ((ICMP_ECHOREPLY << 8) - (ICMP_ECHO << 8)); cksum = (cksum & 0xffff) + (cksum>> 16); icmphdr->icmp_cksum = htons(~cksum); iphdr.ip_dst.s_addr = iphdr.ip_src.s_addr; iphdr.ip_src.s_addr = htonl(my_ipaddr); iphdr.ip_sum = 0; iphdr.ip_sum = ~pktlib_ip_checksum(&iphdr, hdrsize); fprintf(stderr, "SEND ICMP Echo Reply %-15s", inet_ntoa(iphdr.ip_src)); fprintf(stderr, " -> %-15s\n", inet_ntoa(iphdr.ip_dst)); memcpy(p, &iphdr, sizeof(iphdr)); return ntohl(iphdr.ip_dst.s_addr); } struct ip_iface { pktif_t pktif; char macaddr[ETHER_ADDR_LEN]; in_addr_t ipaddr; in_addr_t ipmask; arptbl_t arptbl; }; struct ip_route { in_addr_t ipaddr; in_addr_t ipmask; in_addr_t gateway; struct ip_iface *ifp; }; int main(int argc, char *argv[]) { pktif_t pktif; pktbuf_t pktbuf; int ifnum = 0, rtnum = 0; in_addr_t dstaddr; struct in_addr in; struct ether_header *ehdr; struct ip iphdr; struct ip_iface iflist[16], *ifp = NULL; struct ip_route rtlist[16], *rtp = rtlist, *found; argc--; argv++; /* インターフェース情報を作成 */ for (ifp = iflist; argc> 2; argc -= 3, argv += 3) { if (!strcmp(argv[0], "--")) break; /* インターフェースをオープンする(自発パケットは受信しない) */ ifp->pktif = pktif_open(argv[0], PKTIF_OPEN_FLAG_RECV_NOTSENT, 0); ifp->ipaddr = ntohl(inet_addr(argv[1])); /* IPアドレス */ ifp->ipmask = ntohl(inet_addr(argv[2])); /* ネットマスク */ memcpy(ifp->macaddr, make_srcmacaddr(ifp->ipaddr), ETHER_ADDR_LEN); ifp->arptbl = arplib_table_create(ifp->ipaddr, ifp->macaddr); /* コネクテッド・ルートを作成する */ rtp->ipaddr = ifp->ipaddr & ifp->ipmask; rtp->ipmask = ifp->ipmask; rtp->gateway = 0; rtp->ifp = ifp; rtnum++; rtp++; ifnum++; ifp++; } argc--; argv++; /* 経路情報を作成 */ for (; argc> 2; argc -= 3, argv += 3) { rtp->ipaddr = ntohl(inet_addr(argv[0])); /* IPアドレス */ rtp->ipmask = ntohl(inet_addr(argv[1])); /* ネットマスク */ rtp->gateway = ntohl(inet_addr(argv[2])); /* 転送先 */ rtp->ifp = NULL; rtnum++; rtp++; } fprintf(stderr, "Interfaces:\n"); for (ifp = iflist; ifp < &iflist[ifnum]; ifp++) { fprintf(stderr, "\t%s", pktif_get_name(ifp->pktif)); in.s_addr = htonl(ifp->ipaddr); fprintf(stderr, " %s", inet_ntoa(in)); in.s_addr = htonl(ifp->ipmask); fprintf(stderr, "/%s\n", inet_ntoa(in)); } fprintf(stderr, "Routes:\n"); for (rtp = rtlist; rtp < &rtlist[rtnum]; rtp++) { in.s_addr = htonl(rtp->ipaddr); fprintf(stderr, "\t%s", inet_ntoa(in)); in.s_addr = htonl(rtp->ipmask); fprintf(stderr, "/%s", inet_ntoa(in)); if (rtp->ifp) { fprintf(stderr, " -> %s\n", pktif_get_name(rtp->ifp->pktif)); } else { in.s_addr = htonl(rtp->gateway); fprintf(stderr, " -> %s\n", inet_ntoa(in)); } } while (1) { pktif = pktlib_iflist_select(-1); /* 複数インターフェースで待ち受け */ if (pktif == NULL) continue; pktbuf = pktbuf_recv(pktif, 0); /* パケットを受信 */ if (pktbuf == NULL) continue; /* 受信インターフェースを検索 */ for (ifp = iflist; ifp < &iflist[ifnum]; ifp++) { if (pktif == ifp->pktif) break; } if (ifp == &iflist[ifnum]) goto discard; ehdr = (struct ether_header *)pktbuf_get_header(pktbuf); /* 宛先MACアドレスをチェックし,受信の可否を判断する */ if (!(ehdr->ether_dhost[0] & 1) && memcmp(ehdr->ether_dhost, ifp->macaddr, ETHER_ADDR_LEN)) goto discard; /* ARPの処理 */ if (ntohs(ehdr->ether_type) == ETHERTYPE_ARP) { pktbuf = arplib_packet_proc(ifp->arptbl, pktbuf); pktbuf = pktbuf_send_queue(ifp->pktif, pktbuf); /* 複数パケットの送信 */ goto discard; } if (ntohs(ehdr->ether_type) != ETHERTYPE_IP) goto discard; pktbuf_delete_header(pktbuf, ETHER_HDR_LEN); /* アラインメントずれを考慮して,ローカル領域上で処理する */ memcpy(&iphdr, pktbuf_get_header(pktbuf), sizeof(iphdr)); fprintf(stderr, "RECV IP Packet %s %-15s", pktif_get_name(ifp->pktif), inet_ntoa(iphdr.ip_src)); fprintf(stderr, " -> %-15s\n", inet_ntoa(iphdr.ip_dst)); /* 自身宛のパケットの処理 */ for (ifp = iflist; ifp < &iflist[ifnum]; ifp++) { dstaddr = proc_ip(pktbuf, ifp->ipaddr); /* ICMP Echo ならば応答する */ if (dstaddr) break; } memcpy(&iphdr, pktbuf_get_header(pktbuf), sizeof(iphdr)); dstaddr = ntohl(iphdr.ip_dst.s_addr); /* 経路を検索する */ while (1) { found = NULL; for (rtp = rtlist; rtp < &rtlist[rtnum]; rtp++) { if ((dstaddr & rtp->ipmask) == (rtp->ipaddr & rtp->ipmask)) { /* 複数の経路がヒットした場合には,ロンゲストマッチのルールで決定 */ if ((found == NULL) || (rtp->ipmask> found->ipmask)) found = rtp; } } if (found == NULL) /* 経路が見つからない場合 */ break; ifp = found->ifp; if (ifp) /* 送信先のインターフェースが決定したら送信する */ goto sendpkt; dstaddr = found->gateway; /* 転送先に対して経路を再検索する */ } goto discard; sendpkt: in.s_addr = htonl(dstaddr); fprintf(stderr, "SEND IP Packet %s %-15s\n", pktif_get_name(ifp->pktif), inet_ntoa(in)); pktbuf = arplib_packet_make(ifp->arptbl, pktbuf, ETHERTYPE_IP, dstaddr); pktbuf = pktbuf_send_queue(ifp->pktif, pktbuf); /* 複数パケットの送信 */ discard: pktbuf_destroy_queue(pktbuf); } return 0; }

AltStyle によって変換されたページ (->オリジナル) /