#include #include #include #include #include #include #include #ifndef USE_NETLIB #include #include #ifdef __linux__ #include #endif #include #else #include #endif #include "pktlib.h" #include "pktbuf.h" #include "timer.h" #include "md5.h" struct macaddr_entry { struct ether_addr macaddr; int vid; pktif_t pktif; unsigned int flags; #define MACADDR_ENTRY_FLAG_UPDATED (1 << 0) }; #define MACADDR_TABLE_ALLNUM (1024*4) #define MACADDR_TABLE_LINENUM (16*4) #define MACADDR_TABLE_COLNUM (MACADDR_TABLE_ALLNUM / MACADDR_TABLE_LINENUM) #define MACADDR_TABLE_HASH(macaddr) \ ( \ ((unsigned int)((unsigned char *)(macaddr))[2] << 24) | \ ((unsigned int)((unsigned char *)(macaddr))[3] << 16) | \ ((unsigned int)((unsigned char *)(macaddr))[4] << 8) | \ ((unsigned int)((unsigned char *)(macaddr))[5] << 0) \ ) #define MACADDR_TABLE_INDEX(macaddr) \ (MACADDR_TABLE_HASH(macaddr) % MACADDR_TABLE_LINENUM) static struct macaddr_entry macaddr_table[MACADDR_TABLE_LINENUM][MACADDR_TABLE_COLNUM]; static unsigned int macaddr_hash[MACADDR_TABLE_LINENUM][MACADDR_TABLE_COLNUM]; int macaddr_table_init() { memset(macaddr_table, 0, sizeof(macaddr_table)); memset(macaddr_hash, 0, sizeof(macaddr_hash)); return 0; } int macaddr_entry_dump() { struct macaddr_entry *entry; int index, i; printf("---- MAC Address Table ----\n"); for (index = 0; index < MACADDR_TABLE_LINENUM; index++) { for (i = 0; i < MACADDR_TABLE_COLNUM; i++) { entry = &macaddr_table[index][i]; if (entry->pktif) { printf("LINE[%04d]:\tMAC Address: %s (VID: %d, Interface: %s, Flags: %08x)\n", index, ether_ntoa(&entry->macaddr), entry->vid, pktif_get_name(entry->pktif), entry->flags); } } } fflush(stdout); return 0; } struct macaddr_entry *macaddr_entry_search(char macaddr[], int vid) { struct macaddr_entry *entry; unsigned int hash; int index, i; hash = MACADDR_TABLE_HASH(macaddr); index = MACADDR_TABLE_INDEX(macaddr); for (i = 0; i < MACADDR_TABLE_COLNUM; i++) { if (macaddr_hash[index][i] == hash) { entry = &macaddr_table[index][i]; if (!memcmp(macaddr, &entry->macaddr, ETHER_ADDR_LEN) && entry->vid == vid) return entry; } } return NULL; } struct macaddr_entry *macaddr_entry_create(char macaddr[], int vid) { struct macaddr_entry *entry; int index, i; index = MACADDR_TABLE_INDEX(macaddr); for (i = 0; i < MACADDR_TABLE_COLNUM; i++) { entry = &macaddr_table[index][i]; if (entry->pktif == NULL) { memcpy(&entry->macaddr, macaddr, ETHER_ADDR_LEN); macaddr_hash[index][i] = MACADDR_TABLE_HASH(macaddr); entry->vid = vid; return entry; } } return NULL; } struct macaddr_entry *macaddr_entry_add(char macaddr[], int vid, pktif_t pktif) { struct macaddr_entry *entry; entry = macaddr_entry_search(macaddr, vid); if (entry == NULL) entry = macaddr_entry_create(macaddr, vid); if (entry) { entry->flags |= MACADDR_ENTRY_FLAG_UPDATED; if (entry->pktif != pktif) { entry->pktif = pktif; macaddr_entry_dump(); } } return entry; } struct macaddr_entry *macaddr_entry_delete(struct macaddr_entry *entry) { if (entry) memset(entry, 0, sizeof(*entry)); macaddr_entry_dump(); return entry; } int macaddr_entry_ageout() { struct macaddr_entry *entry; int index, i; for (index = 0; index < MACADDR_TABLE_LINENUM; index++) { for (i = 0; i < MACADDR_TABLE_COLNUM; i++) { entry = &macaddr_table[index][i]; if (entry->pktif) { if (entry->flags & MACADDR_ENTRY_FLAG_UPDATED) entry->flags &= ~MACADDR_ENTRY_FLAG_UPDATED; else macaddr_entry_delete(entry); } } } return 0; } struct macfilter_entry { struct ether_addr macaddr; pktif_t pktif; }; #define MACFILTER_TABLE_ALLNUM (256*4) #define MACFILTER_TABLE_LINENUM (16*4) #define MACFILTER_TABLE_COLNUM (MACFILTER_TABLE_ALLNUM / MACFILTER_TABLE_LINENUM) #define MACFILTER_TABLE_HASH(macaddr) \ ( \ ((unsigned int)((unsigned char *)(macaddr))[2] << 24) | \ ((unsigned int)((unsigned char *)(macaddr))[3] << 16) | \ ((unsigned int)((unsigned char *)(macaddr))[4] << 8) | \ ((unsigned int)((unsigned char *)(macaddr))[5] << 0) \ ) #define MACFILTER_TABLE_INDEX(macaddr) \ (MACFILTER_TABLE_HASH(macaddr) % MACFILTER_TABLE_LINENUM) static struct macfilter_entry macfilter_table[MACFILTER_TABLE_LINENUM][MACFILTER_TABLE_COLNUM]; int macfilter_table_init() { memset(macfilter_table, 0, sizeof(macfilter_table)); return 0; } int macfilter_entry_get_index(struct macfilter_entry *entry) { if (!entry) return -1; return entry - (struct macfilter_entry *)macfilter_table; } struct macfilter_entry *macfilter_entry_get_entry(int index) { if (index < 0) return NULL; return ((struct macfilter_entry *)macfilter_table) + index; } struct macfilter_entry *macfilter_entry_search(char macaddr[], pktif_t pktif) { struct macfilter_entry *entry; int index, i; index = MACFILTER_TABLE_INDEX(macaddr); for (i = 0; i < MACFILTER_TABLE_COLNUM; i++) { entry = &macfilter_table[index][i]; if (!memcmp(macaddr, &entry->macaddr, ETHER_ADDR_LEN) && entry->pktif == pktif) return entry; } return NULL; } struct macfilter_entry *macfilter_entry_create(char macaddr[], pktif_t pktif) { struct macfilter_entry *entry; int index, i; index = MACFILTER_TABLE_INDEX(macaddr); for (i = 0; i < MACFILTER_TABLE_COLNUM; i++) { entry = &macfilter_table[index][i]; if (entry->pktif == NULL) { memcpy(&entry->macaddr, macaddr, ETHER_ADDR_LEN); entry->pktif = pktif; return entry; } } return NULL; } struct macfilter_entry *macfilter_entry_add(char macaddr[], pktif_t pktif) { struct macfilter_entry *entry; entry = macfilter_entry_search(macaddr, pktif); if (entry == NULL) entry = macfilter_entry_create(macaddr, pktif); return entry; } struct macfilter_entry *macfilter_entry_delete(struct macfilter_entry *entry) { if (entry) memset(entry, 0, sizeof(*entry)); return entry; } struct pktif_option { int vid; int port; int macfilter; char *password; }; static unsigned int vlan_portbitmap[4096]; static unsigned int tagvlan_portbitmap[4096]; static unsigned int vlan_maskbitmap[4096]; static unsigned int tagvlan_maskbitmap[4096]; int vlan_port_isset(int vid, int port) { return (vlan_portbitmap[vid] & (1 << port)) ? 1 : 0; } void vlan_port_set(int vid, int port) { vlan_portbitmap[vid] |= (1 << port); } void vlan_port_reset(int vid, int port) { vlan_portbitmap[vid] &= ~(1 << port); } int vlan_mask_isset(int vid, int port) { return (vlan_maskbitmap[vid] & (1 << port)) ? 1 : 0; } void vlan_mask_set(int vid, int port) { vlan_maskbitmap[vid] |= (1 << port); } void vlan_mask_reset(int vid, int port) { vlan_maskbitmap[vid] &= ~(1 << port); } int vlan_port_isactive(int vid, int port) { return ((vlan_portbitmap[vid] & ~vlan_maskbitmap[vid]) & (1 << port)) ? 1 : 0; } int tagvlan_port_isset(int vid, int port) { return (tagvlan_portbitmap[vid] & (1 << port)) ? 1 : 0; } void tagvlan_port_set(int vid, int port) { tagvlan_portbitmap[vid] |= (1 << port); } void tagvlan_port_reset(int vid, int port) { tagvlan_portbitmap[vid] &= ~(1 << port); } int tagvlan_mask_isset(int vid, int port) { return (tagvlan_maskbitmap[vid] & (1 << port)) ? 1 : 0; } void tagvlan_mask_set(int vid, int port) { tagvlan_maskbitmap[vid] |= (1 << port); } void tagvlan_mask_reset(int vid, int port) { tagvlan_maskbitmap[vid] &= ~(1 << port); } int tagvlan_port_isactive(int vid, int port) { return ((tagvlan_portbitmap[vid] & ~tagvlan_maskbitmap[vid]) & (1 << port)) ? 1 : 0; } int vlan_init() { memset(vlan_portbitmap, 0, sizeof(vlan_portbitmap)); memset(tagvlan_portbitmap, 0, sizeof(tagvlan_portbitmap)); memset(vlan_maskbitmap, 0, sizeof(vlan_maskbitmap)); memset(tagvlan_maskbitmap, 0, sizeof(tagvlan_maskbitmap)); return 0; } int vlan_if_set(int vid, pktif_t pktif) { struct pktif_option *ifopt; int port; ifopt = (struct pktif_option *)pktif_get_option(pktif); port = ifopt->port; vlan_port_reset(ifopt->vid, port); ifopt->vid = vid; vlan_port_set(ifopt->vid, port); return 0; } int tagvlan_if_set(int vid, pktif_t pktif) { struct pktif_option *ifopt; int port; ifopt = (struct pktif_option *)pktif_get_option(pktif); port = ifopt->port; tagvlan_port_set(vid, port); return 0; } #define ETHERTYPE_LOOPDETECT 0x8899 struct loopdetect { uint32_t id; }; pktbuf_t loopdetect_create_packet(int id) { pktbuf_t pktbuf; struct loopdetect *ldhdr; struct ether_header *ehdr; char macaddr[ETHER_ADDR_LEN]; pktbuf = pktbuf_create(-1); if (!pktbuf) return NULL; ldhdr = (struct loopdetect *)pktbuf_add_header(pktbuf, sizeof(*ldhdr)); ldhdr->id = htonl(id); macaddr[0] = 0x00; macaddr[1] = 0x11; memcpy(&macaddr[2], &ldhdr->id, sizeof(ldhdr->id)); ehdr = (struct ether_header *)pktbuf_add_header(pktbuf, ETHER_HDR_LEN); memcpy(ehdr->ether_dhost, "\xff\xff\xff\xff\xff\xff", ETHER_ADDR_LEN); memcpy(ehdr->ether_shost, macaddr, ETHER_ADDR_LEN); ehdr->ether_type = htons(ETHERTYPE_LOOPDETECT); return pktbuf; } int loopdetect_check_packet(pktbuf_t pktbuf, int id) { struct loopdetect *ldhdr; ldhdr = (struct loopdetect *)(pktbuf_get_header(pktbuf) + ETHER_HDR_LEN); if (ntohl(ldhdr->id) != id) return 0; return 1; } #define ETHERTYPE_SPECIALAUTH 0x889A struct easyauth { uint32_t id; uint8_t macaddr[ETHER_ADDR_LEN]; uint8_t version; #define EASYAUTH_TYPE_VERSION_1 0 #define EASYAUTH_TYPE_VERSION_2 1 uint8_t type; #define EASYAUTH_TYPE_PR 0 #define EASYAUTH_TYPE_AUTH 1 uint8_t digest[MD5_DIGEST_SIZE]; }; pktbuf_t easyauth_create_packet(int id, char macaddr[], char *password) { pktbuf_t pktbuf; struct easyauth *eahdr; struct ether_header *ehdr; pktbuf = pktbuf_create(-1); if (!pktbuf) return NULL; eahdr = (struct easyauth *)pktbuf_add_header(pktbuf, sizeof(*eahdr)); memset(eahdr, 0, sizeof(*eahdr)); eahdr->id = htonl(id); eahdr->version = EASYAUTH_TYPE_VERSION_2; eahdr->type = EASYAUTH_TYPE_PR; memcpy(eahdr->macaddr, macaddr, ETHER_ADDR_LEN); md5_calc(eahdr->digest, 3, &eahdr->id, sizeof(eahdr->id), eahdr->macaddr, ETHER_ADDR_LEN, password, strlen(password)); ehdr = (struct ether_header *)pktbuf_add_header(pktbuf, ETHER_HDR_LEN); memcpy(ehdr->ether_dhost, "\xff\xff\xff\xff\xff\xff", ETHER_ADDR_LEN); memcpy(ehdr->ether_shost, macaddr, ETHER_ADDR_LEN); ehdr->ether_type = htons(ETHERTYPE_SPECIALAUTH); return pktbuf; } void usage() { printf("[-l ] [-n ] [-d ] \\\n"); printf("[-c ] \\\n"); printf("[-i [-v ] [-t ]... [-f ]... [-a ]]...\n"); exit(0); } struct pktbuf_option { pktif_t rcvif; }; int macaddr_table_ageout(int arg, void *p) { macaddr_entry_ageout(); return -1; } pktbuf_t send_packet(pktbuf_t pktbuf, pktif_t pktif, int vid, int force) { struct pktif_option *ifopt; int port; ifopt = (struct pktif_option *)pktif_get_option(pktif); port = ifopt->port; if (force ? vlan_port_isset(vid, port) : vlan_port_isactive(vid, port)) { pktbuf_send(pktif, pktbuf_clone(pktbuf)); } if (force ? tagvlan_port_isset(vid, port) : tagvlan_port_isactive(vid, port)) { pktbuf_insert_vlantag(pktbuf, vid); pktbuf_send(pktif, pktbuf_clone(pktbuf)); pktbuf_delete_vlantag(pktbuf, NULL); } return pktbuf; } int loopdetect_send(int arg, void *p) { pktif_t pktif; pktbuf_t pktbuf; int vid, loopdetect = arg; pktbuf = loopdetect_create_packet(loopdetect); for (pktif = pktlib_iflist_get_list(); pktif; pktif = pktif_get_next(pktif)) { for (vid = 1; vid < 4096; vid++) { send_packet(pktbuf, pktif, vid, 1); } } pktbuf_destroy(pktbuf); return -1; } int port_open(int arg, void *p) { pktif_t pktif = p; int vid, port, tagged, id = arg; vid = (id>> 16) & 0xfff; port = (id>> 8) & 0xff; tagged = id & 1; printf("LOOP TIMEOUT on %s VID:%d%s", pktif_get_name(pktif), vid, tagged ? "(tag)" : ""); if (tagged) { if (tagvlan_mask_isset(vid, port)) { printf(" (PORT OPENED)"); tagvlan_mask_reset(vid, port); } } else { if (vlan_mask_isset(vid, port)) { printf(" (PORT OPENED)"); vlan_mask_reset(vid, port); } } printf("\n"); return 0; } int macfilter_del(int arg, void *p) { struct macfilter_entry *entry = p; printf("EASYAUTH TIMEOUT on %s (%s)\n", pktif_get_name(entry->pktif), ether_ntoa(&entry->macaddr)); macfilter_entry_delete(entry); return 0; } int easyauth_send(int arg, void *p) { pktif_t pktif; pktbuf_t pktbuf; struct pktif_option *ifopt; int vid, *easyauth_id = (int *)p; uint32_t id; char macaddr[ETHER_ADDR_LEN]; *easyauth_id = rand(); id = htonl(*easyauth_id); macaddr[0] = 0x00; macaddr[1] = 0x12; memcpy(&macaddr[2], &id, sizeof(id)); for (pktif = pktlib_iflist_get_list(); pktif; pktif = pktif_get_next(pktif)) { ifopt = (struct pktif_option *)pktif_get_option(pktif); if (!ifopt->macfilter) continue; pktbuf = easyauth_create_packet(*easyauth_id, macaddr, ifopt->password); for (vid = 1; vid < 4096; vid++) { send_packet(pktbuf, pktif, vid, 0); } pktbuf_destroy(pktbuf); } return -1; } #define TIMER_ID_MACADDR_TABLE_AGEOUT (1 << 28) #define TIMER_ID_LOOPDETECT_PORTOPEN (2 << 28) #define TIMER_ID_LOOPDETECT_SEND (3 << 28) #define TIMER_ID_LOOPDETECT_MACFILDEL (4 << 28) #define TIMER_ID_EASYAUTH_SEND (5 << 28) int main(int argc, char *argv[]) { pktif_t pktif, p; int r, ch, lost_rate = 0, noise_rate = 0, delay_rate = 0; pktbuf_t pktbuf; int type, vid, portnum = 0, loopdetect = 0, id; struct header_param param; struct macaddr_entry *entry; pktbuf_t packets = NULL, waiting = NULL; struct pktif_option *ifopt; int easyauth_id; vlan_init(); timer_init(); macaddr_table_init(); macfilter_table_init(); pktif = NULL; while ((ch = getopt(argc, argv, "l:n:d:c:i:v:t:f:a:")) != -1) { switch (ch) { case 'l': lost_rate = atoi(optarg); break; case 'n': noise_rate = atoi(optarg); break; case 'd': delay_rate = atoi(optarg); break; case 'c': loopdetect = atoi(optarg); break; case 'i': /* インターフェースをオープンする(自発パケットは受信しない) */ pktif = pktif_open(optarg, PKTIF_OPEN_FLAG_RECV_NOTSENT, sizeof(struct pktif_option)); ifopt = (struct pktif_option *)pktif_get_option(pktif); ifopt->vid = 0; ifopt->port = portnum++; vlan_if_set(1, pktif); break; case 'v': if (pktif) { vlan_if_set(atoi(optarg), pktif); } break; case 't': if (pktif) { tagvlan_if_set(atoi(optarg), pktif); } break; case 'f': if (pktif) { macfilter_entry_add((char *)ether_aton(optarg), pktif); ifopt = (struct pktif_option *)pktif_get_option(pktif); ifopt->macfilter = 1; } break; case 'a': if (pktif) { ifopt = (struct pktif_option *)pktif_get_option(pktif); ifopt->macfilter = 1; ifopt->password = strdup(optarg); } break; case '?': default: usage(); } } srand(time(NULL)); pktbuf_init(sizeof(struct pktbuf_option)); timer_add(TIMER_ID_MACADDR_TABLE_AGEOUT, 60000, macaddr_table_ageout, 0, NULL); if (loopdetect) { timer_add(TIMER_ID_LOOPDETECT_SEND, 3000, loopdetect_send, loopdetect, NULL); } timer_add(TIMER_ID_EASYAUTH_SEND, 10000, easyauth_send, 0, &easyauth_id); while (1) { timer_expire(); if (packets == NULL) { pktif = pktlib_iflist_select(1000000); /* 複数インターフェースで待ち受け */ if (pktif) { pktbuf = pktbuf_recv(pktif, 0); /* パケットを受信 */ if (pktbuf) ((struct pktbuf_option *)pktbuf_get_option(pktbuf))->rcvif = pktif; pktbuf_enqueue(&packets, pktbuf); } pktbuf_enqueue(&packets, waiting); waiting = NULL; continue; } pktbuf = pktbuf_dequeue(&packets); pktif = ((struct pktbuf_option *)pktbuf_get_option(pktbuf))->rcvif; if ((delay_rate> 0) && ((rand() % 100) < delay_rate)) { /* 指定された確率で遅延させる */ pktbuf_enqueue(&waiting, pktbuf); continue; } if ((lost_rate> 0) && ((rand() % 100) < lost_rate)) goto discard; /* 指定された確率でパケットを廃棄する */ if ((noise_rate> 0) && ((rand() % 100) < noise_rate)) { /* 指定された確率でノイズを入れる */ pktbuf_get_header(pktbuf)[rand() % pktbuf_get_size(pktbuf)] ^= (1 << (rand() % 8)); } type = pktif_get_linktype(pktif); if (type != DLT_EN10MB) goto discard; r = pktbuf_analyze_ethernet(pktbuf, ¶m); if (r < 1) goto discard; ifopt = (struct pktif_option *)pktif_get_option(pktif); if (param.ethernet.vid) { vid = param.ethernet.vid; if (!tagvlan_port_isset(vid, ifopt->port)) goto discard; pktbuf_delete_vlantag(pktbuf, NULL); } else { vid = ifopt->vid; } if (loopdetect && (param.ethernet.type == ETHERTYPE_LOOPDETECT) && loopdetect_check_packet(pktbuf, loopdetect)) { printf("LOOP DETECTED on %s VID:%d%s", pktif_get_name(pktif), vid, param.ethernet.vid ? "(tag)" : ""); id = TIMER_ID_LOOPDETECT_PORTOPEN | (vid << 16) | (ifopt->port << 8) | (param.ethernet.vid ? 1 : 0); if (param.ethernet.vid) { if (!tagvlan_mask_isset(vid, ifopt->port)) { printf(" (PORT CLOSED)"); tagvlan_mask_set(vid, ifopt->port); } else { timer_del(id); } timer_add(id, 10000, port_open, id, pktif); } else { if (!vlan_mask_isset(vid, ifopt->port)) { printf(" (PORT CLOSED)"); vlan_mask_set(vid, ifopt->port); } else { timer_del(id); } timer_add(id, 10000, port_open, id, pktif); } printf("\n"); goto discard; } if (param.ethernet.vid) { if (!tagvlan_port_isactive(vid, ifopt->port)) goto discard; } else { if (!vlan_port_isactive(vid, ifopt->port)) goto discard; } if (ifopt->macfilter) { if (param.ethernet.type == ETHERTYPE_SPECIALAUTH) { struct macfilter_entry *entry; struct easyauth *eahdr; unsigned char digest[MD5_DIGEST_SIZE]; if (ifopt->password == NULL) goto discard; if (pktbuf_get_size(pktbuf) < param.ethernet.header_size + sizeof(*eahdr)) goto discard; eahdr = (struct easyauth *)(pktbuf_get_header(pktbuf) + param.ethernet.header_size); if (easyauth_id != ntohl(eahdr->id)) goto discard; switch (eahdr->version) { case EASYAUTH_TYPE_VERSION_1: if (param.ethernet.dst_macaddr[0] & 1) goto discard; break; case EASYAUTH_TYPE_VERSION_2: default: switch (eahdr->type) { case EASYAUTH_TYPE_PR: goto discard; case EASYAUTH_TYPE_AUTH: break; default: goto discard; } break; } md5_calc(digest, 3, &eahdr->id, sizeof(eahdr->id), eahdr->macaddr, ETHER_ADDR_LEN, ifopt->password, strlen(ifopt->password)); if (memcmp(eahdr->digest, digest, sizeof(digest))) goto discard; printf("EASYAUTH on %s VID:%d%s", pktif_get_name(pktif), vid, param.ethernet.vid ? "(tag)" : ""); entry = macfilter_entry_search((char *)eahdr->macaddr, pktif); if (entry) { printf(" (UPDATED)"); id = TIMER_ID_LOOPDETECT_MACFILDEL | macfilter_entry_get_index(entry); timer_del(id); } else { printf(" (ADDED)"); entry = macfilter_entry_add((char *)eahdr->macaddr, pktif); } if (entry) { printf(" (TIMER SET)"); id = TIMER_ID_LOOPDETECT_MACFILDEL | macfilter_entry_get_index(entry); timer_add(id, 60000, macfilter_del, id, entry); } printf("\n"); goto discard; } if (macfilter_entry_search(param.ethernet.src_macaddr, pktif) == NULL) { printf("UNKNOWN ADDRESS on %s (%s)\n", pktif_get_name(pktif), ether_ntoa((struct ether_addr *)¶m.ethernet.src_macaddr)); goto discard; } } /* 送信元MACアドレスを学習 */ macaddr_entry_add(param.ethernet.src_macaddr, vid, pktif); /* パケットを送信 */ entry = macaddr_entry_search(param.ethernet.dst_macaddr, vid); if ((param.ethernet.dst_macaddr[0] & 1) || (entry == NULL)) { /* ブロードキャストはVLAN内の全ポートに送信 */ for (p = pktlib_iflist_get_list(); p; p = pktif_get_next(p)) { if (p == pktif) continue; send_packet(pktbuf, p, vid, 0); } } else { send_packet(pktbuf, entry->pktif, vid, 0); } discard: pktbuf_destroy(pktbuf); } return 0; }

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