#ifdef __linux__ #define _BSD_SOURCE #endif #include #include #include #include #include #include #include #include #include #include #include "pktlib.h" #include "pktbuf.h" #include "nat.h" struct natentry { struct { in_addr_t ipaddr; int port; } global; struct { in_addr_t ipaddr; int port; } local; }; struct nattable { /* NATテーブル */ int num; struct natentry *entries; }; struct _natif { in_addr_t ipaddr; struct nattable icmp; struct nattable tcp; struct nattable udp; }; static int nattable_init(struct nattable *tbl, int num) { int i; tbl->num = num; tbl->entries = malloc(sizeof(tbl->entries[0]) * num); memset(tbl->entries, 0, sizeof(tbl->entries[0]) * num); for (i = 0; i < num; i++) { tbl->entries[i].global.port = 10000 + i; } return 0; } static struct natentry *nattable_get_free_entry(struct nattable *tbl) { int i; for (i = 0; i < tbl->num; i++) { if (tbl->entries[i].local.port == 0) return &tbl->entries[i]; } return NULL; } static struct natentry *nattable_add_entry(struct nattable *tbl, in_addr_t global_ipaddr, in_addr_t local_ipaddr, int local_port) { struct natentry *entry; entry = nattable_get_free_entry(tbl); entry->global.ipaddr = global_ipaddr; entry->local.ipaddr = local_ipaddr; entry->local.port = local_port; return entry; } static struct natentry *nattable_search_global(struct nattable *tbl, in_addr_t global_ipaddr, int global_port) { int i; for (i = 0; i < tbl->num; i++) { if ((tbl->entries[i].global.ipaddr == global_ipaddr) && (tbl->entries[i].global.port == global_port)) { return &tbl->entries[i]; } } return NULL; } static struct natentry *nattable_search_local(struct nattable *tbl, in_addr_t local_ipaddr, int local_port) { int i; for (i = 0; i < tbl->num; i++) { if ((tbl->entries[i].local.ipaddr == local_ipaddr) && (tbl->entries[i].local.port == local_port)) { return &tbl->entries[i]; } } return NULL; } natif_t natif_create(int entry_num, in_addr_t ipaddr) { natif_t natif; natif = malloc(sizeof(*natif)); memset(natif, 0, sizeof(*natif)); natif->ipaddr = ipaddr; nattable_init(&natif->icmp, entry_num); nattable_init(&natif->tcp, entry_num); nattable_init(&natif->udp, entry_num); return natif; } enum { NAT_DIRECTION_INCOMING, NAT_DIRECTION_OUTGOING, }; static pktbuf_t nat_icmp(natif_t natif, pktbuf_t pktbuf, struct ip *iphdr, int direction) { char *p; struct icmp *icmphdr; struct natentry *entry; p = pktbuf_get_header(pktbuf); if (pktbuf_get_size(pktbuf) < sizeof(*icmphdr)) return pktbuf; icmphdr = (struct icmp *)p; switch (direction) { case NAT_DIRECTION_INCOMING: entry = nattable_search_global(&natif->icmp, ntohl(iphdr->ip_dst.s_addr), ntohs(icmphdr->icmp_id)); if (entry == NULL) return pktbuf; iphdr->ip_dst.s_addr = htonl(entry->local.ipaddr); icmphdr->icmp_id = htons(entry->local.port); break; case NAT_DIRECTION_OUTGOING: entry = nattable_search_local(&natif->icmp, ntohl(iphdr->ip_src.s_addr), ntohs(icmphdr->icmp_id)); if (entry == NULL) { entry = nattable_add_entry(&natif->icmp, natif->ipaddr, ntohl(iphdr->ip_src.s_addr), ntohs(icmphdr->icmp_id)); } iphdr->ip_src.s_addr = htonl(natif->ipaddr); icmphdr->icmp_id = htons(entry->global.port); break; default: break; } return pktbuf; } static pktbuf_t nat_tcp(natif_t natif, pktbuf_t pktbuf, struct ip *iphdr, int direction) { char *p; struct tcphdr *tcphdr; struct natentry *entry; p = pktbuf_get_header(pktbuf); if (pktbuf_get_size(pktbuf) < sizeof(*tcphdr)) return pktbuf; tcphdr = (struct tcphdr *)p; switch (direction) { case NAT_DIRECTION_INCOMING: entry = nattable_search_global(&natif->tcp, ntohl(iphdr->ip_dst.s_addr), ntohs(tcphdr->th_dport)); if (entry == NULL) return pktbuf; iphdr->ip_dst.s_addr = htonl(entry->local.ipaddr); tcphdr->th_dport = htons(entry->local.port); break; case NAT_DIRECTION_OUTGOING: entry = nattable_search_local(&natif->tcp, ntohl(iphdr->ip_src.s_addr), ntohs(tcphdr->th_sport)); if (entry == NULL) { entry = nattable_add_entry(&natif->tcp, natif->ipaddr, ntohl(iphdr->ip_src.s_addr), ntohs(tcphdr->th_sport)); } iphdr->ip_src.s_addr = htonl(natif->ipaddr); tcphdr->th_sport = htons(entry->global.port); break; default: break; } return pktbuf; } static pktbuf_t nat_udp(natif_t natif, pktbuf_t pktbuf, struct ip *iphdr, int direction) { char *p; struct udphdr *udphdr; struct natentry *entry; p = pktbuf_get_header(pktbuf); if (pktbuf_get_size(pktbuf) < sizeof(*udphdr)) return pktbuf; udphdr = (struct udphdr *)p; switch (direction) { case NAT_DIRECTION_INCOMING: entry = nattable_search_global(&natif->udp, ntohl(iphdr->ip_dst.s_addr), ntohs(udphdr->uh_dport)); if (entry == NULL) return pktbuf; iphdr->ip_dst.s_addr = htonl(entry->local.ipaddr); udphdr->uh_dport = htons(entry->local.port); break; case NAT_DIRECTION_OUTGOING: entry = nattable_search_local(&natif->udp, ntohl(iphdr->ip_src.s_addr), ntohs(udphdr->uh_sport)); if (entry == NULL) { entry = nattable_add_entry(&natif->udp, natif->ipaddr, ntohl(iphdr->ip_src.s_addr), ntohs(udphdr->uh_sport)); } iphdr->ip_src.s_addr = htonl(natif->ipaddr); udphdr->uh_sport = htons(entry->global.port); break; default: break; } return pktbuf; } static pktbuf_t proc_ip(natif_t natif, pktbuf_t pktbuf, int direction) { char *p; struct ip *iphdr; int hdrsize, paysize; p = pktbuf_get_header(pktbuf); if (pktbuf_get_size(pktbuf) < sizeof(*iphdr)) return pktbuf; iphdr = (struct ip *)p; hdrsize = iphdr->ip_hl << 2; paysize = ntohs(iphdr->ip_len) - hdrsize; if (pktbuf_get_size(pktbuf) < hdrsize) return pktbuf; switch (direction) { case NAT_DIRECTION_INCOMING: if (ntohl(iphdr->ip_dst.s_addr) != natif->ipaddr) return pktbuf; break; case NAT_DIRECTION_OUTGOING: if (ntohl(iphdr->ip_src.s_addr) == natif->ipaddr) return pktbuf; break; default: break; } fprintf(stderr, "NAT(before) %-15s", inet_ntoa(iphdr->ip_src)); fprintf(stderr, " -> %-15s\n", inet_ntoa(iphdr->ip_dst)); if (pktbuf_get_size(pktbuf) < hdrsize + paysize) return pktbuf; pktbuf_delete_header(pktbuf, hdrsize); switch (iphdr->ip_p) { case IPPROTO_ICMP: pktbuf = nat_icmp(natif, pktbuf, iphdr, direction); break; case IPPROTO_TCP: pktbuf = nat_tcp( natif, pktbuf, iphdr, direction); break; case IPPROTO_UDP: pktbuf = nat_udp( natif, pktbuf, iphdr, direction); break; default: break; } if (pktbuf == NULL) return NULL; pktbuf_add_header(pktbuf, hdrsize); fprintf(stderr, "NAT(after) %-15s", inet_ntoa(iphdr->ip_src)); fprintf(stderr, " -> %-15s\n", inet_ntoa(iphdr->ip_dst)); return pktbuf; } pktbuf_t natif_packet_incoming(natif_t natif, pktbuf_t pktbuf) { return proc_ip(natif, pktbuf, NAT_DIRECTION_INCOMING); } pktbuf_t natif_packet_outgoing(natif_t natif, pktbuf_t pktbuf) { return proc_ip(natif, pktbuf, NAT_DIRECTION_OUTGOING); } int natif_add_entry_tcp(natif_t natif, int global_port, in_addr_t local_ipaddr, int local_port) { struct natentry *entry; entry = nattable_add_entry(&natif->tcp, natif->ipaddr, local_ipaddr, local_port); entry->global.port = global_port; return 0; } int natif_add_entry_udp(natif_t natif, int global_port, in_addr_t local_ipaddr, int local_port) { struct natentry *entry; entry = nattable_add_entry(&natif->udp, natif->ipaddr, local_ipaddr, local_port); entry->global.port = global_port; return 0; }

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