📄 ip_nat.c
字号:
*/ if (n->in_space) { if ((n->in_flags & IPN_IPRANGE) != 0) n->in_space += 1; else n->in_space -= 1; } else n->in_space = 1; if ((n->in_outmsk != 0xffffffff) && (n->in_outmsk != 0) && ((n->in_flags & (IPN_IPRANGE|IPN_SPLIT)) == 0)) n->in_nip = ntohl(n->in_outip) + 1; else if ((n->in_flags & IPN_SPLIT) && (n->in_redir & NAT_REDIRECT)) n->in_nip = ntohl(n->in_inip); else n->in_nip = ntohl(n->in_outip); if (n->in_redir & NAT_MAP) { n->in_pnext = ntohs(n->in_pmin); /* * Multiply by the number of ports made available. */ if (ntohs(n->in_pmax) >= ntohs(n->in_pmin)) { n->in_space *= (ntohs(n->in_pmax) - ntohs(n->in_pmin) + 1); /* * Because two different sources can map to * different destinations but use the same * local IP#/port #. * If the result is smaller than in_space, then * we may have wrapped around 32bits. */ i = n->in_inmsk; if ((i != 0) && (i != 0xffffffff)) { j = n->in_space * (~ntohl(i) + 1); if (j >= n->in_space) n->in_space = j; else n->in_space = 0xffffffff; } } /* * If no protocol is specified, multiple by 256. */ if ((n->in_flags & IPN_TCPUDP) == 0) { j = n->in_space * 256; if (j >= n->in_space) n->in_space = j; else n->in_space = 0xffffffff; } } /* Otherwise, these fields are preset */ n = NULL; nat_stats.ns_rules++; break; case SIOCRMNAT : if (!(mode & FWRITE)) { error = EPERM; n = NULL; break; } if (!n) { error = ESRCH; break; } if (n->in_redir & NAT_REDIRECT) nat_delrdr(n); if (n->in_redir & (NAT_MAPBLK|NAT_MAP)) nat_delnat(n); if (nat_list == NULL) { nat_masks = 0; rdr_masks = 0; } *np = n->in_next; if (!n->in_use) { if (n->in_apr) appr_free(n->in_apr); KFREE(n); nat_stats.ns_rules--; } else { n->in_flags |= IPN_DELETE; n->in_next = NULL; } n = NULL; break; case SIOCGNATS : MUTEX_DOWNGRADE(&ipf_nat); nat_stats.ns_table[0] = nat_table[0]; nat_stats.ns_table[1] = nat_table[1]; nat_stats.ns_list = nat_list; nat_stats.ns_nattab_sz = ipf_nattable_sz; nat_stats.ns_rultab_sz = ipf_natrules_sz; nat_stats.ns_rdrtab_sz = ipf_rdrrules_sz; nat_stats.ns_instances = nat_instances; nat_stats.ns_apslist = ap_sess_list; error = IWCOPYPTR((char *)&nat_stats, (char *)data, sizeof(nat_stats)); break; case SIOCGNATL : { natlookup_t nl; MUTEX_DOWNGRADE(&ipf_nat); error = IRCOPYPTR((char *)data, (char *)&nl, sizeof(nl)); if (error) break; if (nat_lookupredir(&nl)) { error = IWCOPYPTR((char *)&nl, (char *)data, sizeof(nl)); } else error = ESRCH; break; } case SIOCIPFFL : /* old SIOCFLNAT & SIOCCNATL */ if (!(mode & FWRITE)) { error = EPERM; break; } error = 0; if (arg == 0) ret = nat_flushtable(); else if (arg == 1) ret = nat_clearlist(); else error = EINVAL; MUTEX_DOWNGRADE(&ipf_nat); if (!error) { error = IWCOPY((caddr_t)&ret, data, sizeof(ret)); if (error) error = EFAULT; } break; case SIOCSTLCK : error = IRCOPY(data, (caddr_t)&arg, sizeof(arg)); if (!error) { error = IWCOPY((caddr_t)&fr_nat_lock, data, sizeof(fr_nat_lock)); if (!error) fr_nat_lock = arg; } else error = EFAULT; break; case SIOCSTPUT : if (fr_nat_lock) error = fr_natputent(data); else error = EACCES; break; case SIOCSTGSZ : if (fr_nat_lock) error = fr_natgetsz(data); else error = EACCES; break; case SIOCSTGET : if (fr_nat_lock) error = fr_natgetent(data); else error = EACCES; break; case FIONREAD :#ifdef IPFILTER_LOG arg = (int)iplused[IPL_LOGNAT]; MUTEX_DOWNGRADE(&ipf_nat); error = IWCOPY((caddr_t)&arg, (caddr_t)data, sizeof(arg)); if (error) error = EFAULT;#endif break; default : error = EINVAL; break; } RWLOCK_EXIT(&ipf_nat); /* READ/WRITE */done: if (nt) KFREE(nt); return error;}static int fr_natgetsz(data)caddr_t data;{ ap_session_t *aps; nat_t *nat, *n; int error = 0; natget_t ng; error = IRCOPY(data, (caddr_t)&ng, sizeof(ng)); if (error) return EFAULT; nat = ng.ng_ptr; if (!nat) { nat = nat_instances; ng.ng_sz = 0; if (nat == NULL) { error = IWCOPY((caddr_t)&ng, data, sizeof(ng)); if (error) error = EFAULT; return error; } } else { /* * Make sure the pointer we're copying from exists in the * current list of entries. Security precaution to prevent * copying of random kernel data. */ for (n = nat_instances; n; n = n->nat_next) if (n == nat) break; if (!n) return ESRCH; } ng.ng_sz = sizeof(nat_save_t); aps = nat->nat_aps; if ((aps != NULL) && (aps->aps_data != 0)) { ng.ng_sz += sizeof(ap_session_t); ng.ng_sz += aps->aps_psiz; } error = IWCOPY((caddr_t)&ng, data, sizeof(ng)); if (error) error = EFAULT; return error;}static int fr_natgetent(data)caddr_t data;{ nat_save_t ipn, *ipnp, *ipnn = NULL; register nat_t *n, *nat; ap_session_t *aps; int error; error = IRCOPY(data, (caddr_t)&ipnp, sizeof(ipnp)); if (error) return EFAULT; error = IRCOPY((caddr_t)ipnp, (caddr_t)&ipn, sizeof(ipn)); if (error) return EFAULT; nat = ipn.ipn_next; if (!nat) { nat = nat_instances; if (nat == NULL) { if (nat_instances == NULL) return ENOENT; return 0; } } else { /* * Make sure the pointer we're copying from exists in the * current list of entries. Security precaution to prevent * copying of random kernel data. */ for (n = nat_instances; n; n = n->nat_next) if (n == nat) break; if (!n) return ESRCH; } ipn.ipn_next = nat->nat_next; ipn.ipn_dsize = 0; bcopy((char *)nat, (char *)&ipn.ipn_nat, sizeof(ipn.ipn_nat)); ipn.ipn_nat.nat_data = NULL; if (nat->nat_ptr) { bcopy((char *)nat->nat_ptr, (char *)&ipn.ipn_ipnat, sizeof(ipn.ipn_ipnat)); } if (nat->nat_fr) bcopy((char *)nat->nat_fr, (char *)&ipn.ipn_rule, sizeof(ipn.ipn_rule)); if ((aps = nat->nat_aps)) { ipn.ipn_dsize = sizeof(*aps); if (aps->aps_data) ipn.ipn_dsize += aps->aps_psiz; KMALLOCS(ipnn, nat_save_t *, sizeof(*ipnn) + ipn.ipn_dsize); if (ipnn == NULL) return ENOMEM; bcopy((char *)&ipn, (char *)ipnn, sizeof(ipn)); bcopy((char *)aps, ipnn->ipn_data, sizeof(*aps)); if (aps->aps_data) { bcopy(aps->aps_data, ipnn->ipn_data + sizeof(*aps), aps->aps_psiz); ipnn->ipn_dsize += aps->aps_psiz; } error = IWCOPY((caddr_t)ipnn, ipnp, sizeof(ipn) + ipn.ipn_dsize); if (error) error = EFAULT; KFREES(ipnn, sizeof(*ipnn) + ipn.ipn_dsize); } else { error = IWCOPY((caddr_t)&ipn, ipnp, sizeof(ipn)); if (error) error = EFAULT; } return error;}static int fr_natputent(data)caddr_t data;{ nat_save_t ipn, *ipnp, *ipnn = NULL; register nat_t *n, *nat; ap_session_t *aps; frentry_t *fr; ipnat_t *in; int error; error = IRCOPY(data, (caddr_t)&ipnp, sizeof(ipnp)); if (error) return EFAULT; error = IRCOPY((caddr_t)ipnp, (caddr_t)&ipn, sizeof(ipn)); if (error) return EFAULT; nat = NULL; if (ipn.ipn_dsize) { KMALLOCS(ipnn, nat_save_t *, sizeof(ipn) + ipn.ipn_dsize); if (ipnn == NULL) return ENOMEM; bcopy((char *)&ipn, (char *)ipnn, sizeof(ipn)); error = IRCOPY((caddr_t)ipnp, (caddr_t)ipn.ipn_data, ipn.ipn_dsize); if (error) { error = EFAULT; goto junkput; } } else ipnn = NULL; KMALLOC(nat, nat_t *); if (nat == NULL) { error = EFAULT; goto junkput; } bcopy((char *)&ipn.ipn_nat, (char *)nat, sizeof(*nat)); /* * Initialize all these so that nat_delete() doesn't cause a crash. */ nat->nat_phnext[0] = NULL; nat->nat_phnext[1] = NULL; fr = nat->nat_fr; nat->nat_fr = NULL; aps = nat->nat_aps; nat->nat_aps = NULL; in = nat->nat_ptr; nat->nat_ptr = NULL; nat->nat_data = NULL; /* * Restore the rule associated with this nat session */ if (in) { KMALLOC(in, ipnat_t *); if (in == NULL) { error = ENOMEM; goto junkput; } nat->nat_ptr = in; bcopy((char *)&ipn.ipn_ipnat, (char *)in, sizeof(*in)); in->in_use = 1; in->in_flags |= IPN_DELETE; in->in_next = NULL; in->in_rnext = NULL; in->in_prnext = NULL; in->in_mnext = NULL; in->in_pmnext = NULL; in->in_ifp = GETUNIT(in->in_ifname, 4); if (in->in_plabel[0] != '\0') { in->in_apr = appr_match(in->in_p, in->in_plabel); } } /* * Restore ap_session_t structure. Include the private data allocated * if it was there. */ if (aps) { KMALLOC(aps, ap_session_t *); if (aps == NULL) { error = ENOMEM; goto junkput; } nat->nat_aps = aps; aps->aps_next = ap_sess_list; ap_sess_list = aps; bcopy(ipnn->ipn_data, (char *)aps, sizeof(*aps)); if (in) aps->aps_apr = in->in_apr; if (aps->aps_psiz) { KMALLOCS(aps->aps_data, void *, aps->aps_psiz); if (aps->aps_data == NULL) { error = ENOMEM; goto junkput; } bcopy(ipnn->ipn_data + sizeof(*aps), aps->aps_data, aps->aps_psiz); } else { aps->aps_psiz = 0; aps->aps_data = NULL; } } /* * If there was a filtering rule associated with this entry then * build up a new one. */ if (fr != NULL) { if (nat->nat_flags & FI_NEWFR) { KMALLOC(fr, frentry_t *); nat->nat_fr = fr; if (fr == NULL) { error = ENOMEM; goto junkput; } bcopy((char *)&ipn.ipn_fr, (char *)fr, sizeof(*fr)); ipn.ipn_nat.nat_fr = fr; error = IWCOPY((caddr_t)&ipn, ipnp, sizeof(ipn)); if (error) { error = EFAULT; goto junkput; } } else { for (n = nat_instances; n; n = n->nat_next) if (n->nat_fr == fr) break; if (!n) { error = ESRCH; goto junkput; } } } if (ipnn) KFREES(ipnn, sizeof(ipn) + ipn.ipn_dsize); nat_insert(nat); return 0;junkput: if (ipnn) KFREES(ipnn, sizeof(ipn) + ipn.ipn_dsize); if (nat) nat_delete(nat); return error;}/* * Delete a nat entry from the various lists and table. */static void nat_delete(natd)struct nat *natd;{ struct ipnat *ipn; if (natd->nat_flags & FI_WILDP) nat_stats.ns_wilds--; if (natd->nat_hnext[0]) natd->nat_hnext[0]->nat_phnext[0] = natd->nat_phnext[0]; *natd->nat_phnext[0] = natd->nat_hnext[0]; if (natd->nat_hnext[1]) natd->nat_hnext[1]->nat_phnext[1] = natd->nat_phnext[1]; *natd->nat_phnext[1] = natd->nat_hnext[1]; if (natd->nat_fr != NULL) { ATOMIC_DEC32(natd->nat_fr->fr_ref); } if (natd->nat_hm != NULL) nat_hostmapdel(natd->nat_hm); /* * If there is an active reference from the nat entry to its parent * rule, decrement the rule's reference count and free it too if no * longer being used. */ ipn = natd->nat_ptr; if (ipn != NULL) { ipn->in_space++; ipn->in_use--; if (!ipn->in_use && (ipn->in_flags & IPN_DELETE)) { if (ipn->in_apr) appr_free(ipn->in_apr); KFREE(ipn); nat_stats.ns_rules--; } } MUTEX_DESTROY(&natd->nat_lock); /* * If there's a fragment table entry too for this nat entry, then * dereference that as well. */ ipfr_forget((void *)natd); aps_free(natd->nat_aps); nat_stats.ns_inuse--; KFREE(natd);}/* * nat_flushtable - clear the NAT table of all mapping entries. */static int nat_flushtable(){ register nat_t *nat, **natp; register int j = 0; /* * ALL NAT mappings deleted, so lets just make the deletions * quicker. */ if (nat_table[0] != NULL) bzero((char *)nat_table[0], sizeof(nat_table[0]) * ipf_nattable_sz); if (nat_table[1] != NULL) bzero((char *)nat_table[1], sizeof(nat_table[1]) * ipf_nattable_sz); for (natp = &nat_instances; (nat = *natp); ) { *natp = nat->nat_next;#ifdef IPFILTER_LOG nat_log(nat, NL_FLUSH);#endif nat_delete(nat);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -