#include #include #include #include #ifndef USE_NETLIB #include #include #include #include #else #include #endif #include "pktlib.h" #include "pktbuf.h" #include "arplib.h" struct arpentry { /* ARPテーブル中のエントリ(IPアドレスとMACアドレスの組) */ struct arpentry *next; in_addr_t ipaddr; char macaddr[ETHER_ADDR_LEN]; pktbuf_t saved; /* ARP未解決パケットを一時保存する(リンクリスト管理) */ }; struct _arptbl { /* ARPテーブル */ in_addr_t my_ipaddr; /* 自身のIPアドレス */ char my_macaddr[ETHER_ADDR_LEN]; /* 自身のMACアドレス */ struct arpentry *entries; /* ARPテーブル中のエントリ(リンクリスト管理) */ }; #define MACADDR_NONE "\x00\x00\x00\x00\x00\x00" #define MACADDR_BROADCAST "\xff\xff\xff\xff\xff\xff" arptbl_t arplib_table_create(in_addr_t ipaddr, char *macaddr) { arptbl_t arptbl; arptbl = malloc(sizeof(*arptbl)); memset(arptbl, 0, sizeof(*arptbl)); arptbl->my_ipaddr = ipaddr; memcpy(arptbl->my_macaddr, macaddr, ETHER_ADDR_LEN); arptbl->entries = NULL; return arptbl; } static struct arpentry *table_search(arptbl_t arptbl, in_addr_t ipaddr) { struct arpentry *entry; for (entry = arptbl->entries; entry; entry = entry->next) { if (entry->ipaddr == ipaddr) /* IPアドレスをキーにして検索する */ return entry; } return NULL; } static struct arpentry *table_add(arptbl_t arptbl, in_addr_t ipaddr, char *macaddr) { struct arpentry *entry = table_search(arptbl, ipaddr); /* IPアドレスで検索 */ if (entry == NULL) { /* 見つからなかった場合は新規作成する */ entry = malloc(sizeof(*entry)); memset(entry, 0, sizeof(*entry)); entry->ipaddr = ipaddr; entry->saved = NULL; entry->next = arptbl->entries; /* リンクリストに接続する */ arptbl->entries = entry; } memcpy(entry->macaddr, macaddr, ETHER_ADDR_LEN); /* MACアドレスを記録する */ return entry; } in_addr_t arplib_table_get_my_ipaddr(arptbl_t arptbl) { return arptbl->my_ipaddr; } char *arplib_table_get_my_macaddr(arptbl_t arptbl) { return arptbl->my_macaddr; } static pktbuf_t make_ethernet(arptbl_t arptbl, pktbuf_t pktbuf, int type, in_addr_t ipaddr, char *macaddr); static pktbuf_t make_arp(arptbl_t arptbl, pktbuf_t pktbuf, int op, in_addr_t ipaddr, char *macaddr) { struct arphdr *arphdr; char *smac, *tmac, *sip, *tip; in_addr_t saddr, taddr; int size; size = sizeof(struct arphdr) + 2 * (ETHER_ADDR_LEN + sizeof(in_addr_t)); arphdr = (struct arphdr *)pktbuf_add_header(pktbuf, size); arphdr->ar_hrd = htons(ARPHRD_ETHER); arphdr->ar_pro = htons(ETHERTYPE_IP); arphdr->ar_hln = ETHER_ADDR_LEN; arphdr->ar_pln = sizeof(in_addr_t); arphdr->ar_op = htons(op); smac = (char *)arphdr + sizeof(struct arphdr); sip = smac + arphdr->ar_hln; tmac = sip + arphdr->ar_pln; tip = tmac + arphdr->ar_hln; saddr = htonl(arptbl->my_ipaddr); taddr = htonl(ipaddr); memcpy(smac, arptbl->my_macaddr, ETHER_ADDR_LEN); memcpy(sip, &saddr, sizeof(in_addr_t)); memcpy(tmac, macaddr ? macaddr : MACADDR_NONE, ETHER_ADDR_LEN); memcpy(tip, &taddr, sizeof(in_addr_t)); return make_ethernet(arptbl, pktbuf, ETHERTYPE_ARP, 0, macaddr); } static pktbuf_t proc_arp(arptbl_t arptbl, pktbuf_t pktbuf) { struct arphdr *arphdr; char *smac, *tmac, *sip, *tip; in_addr_t saddr, taddr; struct arpentry *entry; pktbuf_t reply = NULL, saved, p; arphdr = (struct arphdr *)pktbuf_get_header(pktbuf); if ((ntohs(arphdr->ar_hrd) != ARPHRD_ETHER) || (ntohs(arphdr->ar_pro) != ETHERTYPE_IP)) goto ret; smac = (char *)arphdr + sizeof(struct arphdr); sip = smac + arphdr->ar_hln; tmac = sip + arphdr->ar_pln; tip = tmac + arphdr->ar_hln; memcpy(&saddr, sip, sizeof(in_addr_t)); saddr = ntohl(saddr); memcpy(&taddr, tip, sizeof(in_addr_t)); taddr = ntohl(taddr); entry = table_add(arptbl, saddr, smac); /* アドレスを学習する */ /* ARP Request に対して ARP Reply を返す */ if ((ntohs(arphdr->ar_op) == ARPOP_REQUEST) && (taddr == arptbl->my_ipaddr)) { reply = pktbuf_create(-1); reply = make_arp(arptbl, reply, ARPOP_REPLY, saddr, smac); } /* 学習できたらARPエントリに保存してあったパケットを送信する */ if (memcmp(entry->macaddr, MACADDR_NONE, ETHER_ADDR_LEN)) { saved = entry->saved; entry->saved = NULL; while (saved) { p = pktbuf_dequeue(&saved); p = make_ethernet(arptbl, p, ETHERTYPE_IP, entry->ipaddr, NULL); if (p) pktbuf_enqueue(&reply, p); } } ret: pktbuf_destroy(pktbuf); return reply; } static pktbuf_t make_ethernet(arptbl_t arptbl, pktbuf_t pktbuf, int type, in_addr_t ipaddr, char *macaddr) { struct ether_header *ehdr; struct arpentry *entry; ehdr = (struct ether_header *)pktbuf_add_header(pktbuf, ETHER_HDR_LEN); if (macaddr == NULL) { /* 宛先MACアドレスが未指定の場合 */ if (type == ETHERTYPE_ARP) { macaddr = MACADDR_BROADCAST; goto make; } if (type != ETHERTYPE_IP) { pktbuf_destroy(pktbuf); return NULL; } entry = table_search(arptbl, ipaddr); /* MACアドレスを検索 */ if (entry == NULL) /* 存在しない場合はパケット保存用に暫定追加 */ entry = table_add(arptbl, ipaddr, MACADDR_NONE); if (!memcmp(entry->macaddr, MACADDR_NONE, ETHER_ADDR_LEN)) { /* MACアドレス不明の場合はパケットを一時的に保存し ARP Request を送信 */ pktbuf_delete_header(pktbuf, ETHER_HDR_LEN); pktbuf_enqueue(&entry->saved, pktbuf); pktbuf = pktbuf_create(-1); return make_arp(arptbl, pktbuf, ARPOP_REQUEST, ipaddr, NULL); } macaddr = entry->macaddr; } make: memcpy(ehdr->ether_dhost, macaddr, ETHER_ADDR_LEN); /* Ethernetヘッダ作成 */ memcpy(ehdr->ether_shost, arptbl->my_macaddr, ETHER_ADDR_LEN); ehdr->ether_type = htons(type); return pktbuf; } static pktbuf_t proc_ethernet(arptbl_t arptbl, pktbuf_t pktbuf) { struct ether_header *ehdr; ehdr = (struct ether_header *)pktbuf_get_header(pktbuf); if (!(ehdr->ether_dhost[0] & 1) && /* マルチキャストではなく自宛でもない */ memcmp(ehdr->ether_dhost, arptbl->my_macaddr, ETHER_ADDR_LEN)) goto discard; if (ntohs(ehdr->ether_type) != ETHERTYPE_ARP) /* ARP以外は無視する */ goto discard; pktbuf_delete_header(pktbuf, ETHER_HDR_LEN); return proc_arp(arptbl, pktbuf); discard: pktbuf_destroy(pktbuf); return NULL; } pktbuf_t arplib_packet_proc(arptbl_t arptbl, pktbuf_t pktbuf) { return proc_ethernet(arptbl, pktbuf); } pktbuf_t arplib_packet_make(arptbl_t arptbl, pktbuf_t pktbuf, int type, in_addr_t ipaddr) { return make_ethernet(arptbl, pktbuf, type, ipaddr, NULL); }

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