📄 iptcrdr.c
字号:
/* $Id: iptcrdr.c,v 1.27 2008/03/03 01:37:43 nanard Exp $ *//* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (c) 2006-2008 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <syslog.h>#include <sys/errno.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <dlfcn.h>#include <libiptc/libiptc.h>#include <iptables.h>#include <linux/version.h>#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)#include <linux/netfilter_ipv4/ip_nat.h>#else#include <linux/netfilter/nf_nat.h>/*#define ip_nat_multi_range nf_nat_multi_range#define ip_nat_range nf_nat_range*/#endif#include "iptcrdr.h"/* dummy init and shutdown functions */int init_redirect(void){ return 0;}void shutdown_redirect(void){ return;}/* chain name to use, both in the nat table * and the filter table */static const char miniupnpd_chain[] = "MINIUPNPD";/* convert an ip address to string */static int snprintip(char * dst, size_t size, uint32_t ip){ return snprintf(dst, size, "%u.%u.%u.%u", ip >> 24, (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff);}/* netfilter cannot store redirection descriptions, so we use our * own structure to store them */struct rdr_desc { struct rdr_desc * next; unsigned short eport; short proto; char str[];};/* pointer to the chained list where descriptions are stored */static struct rdr_desc * rdr_desc_list = 0;static voidadd_redirect_desc(unsigned short eport, int proto, const char * desc){ struct rdr_desc * p; size_t l; if(desc) { l = strlen(desc) + 1; p = malloc(sizeof(struct rdr_desc) + l); if(p) { p->next = rdr_desc_list; p->eport = eport; p->proto = (short)proto; memcpy(p->str, desc, l); rdr_desc_list = p; } }}static voiddel_redirect_desc(unsigned short eport, int proto){ struct rdr_desc * p, * last; p = rdr_desc_list; last = 0; while(p) { if(p->eport == eport && p->proto == proto) { if(!last) rdr_desc_list = p->next; else last->next = p->next; free(p); return; } last = p; p = p->next; }}static voidget_redirect_desc(unsigned short eport, int proto, char * desc, int desclen){ struct rdr_desc * p; if(!desc || (desclen == 0)) return; for(p = rdr_desc_list; p; p = p->next) { if(p->eport == eport && p->proto == (short)proto) { strncpy(desc, p->str, desclen); return; } } /* if no description was found, return miniupnpd as default */ strncpy(desc, "miniupnpd", desclen);}/* add_redirect_rule2() */intadd_redirect_rule2(const char * ifname, unsigned short eport, const char * iaddr, unsigned short iport, int proto, const char * desc){ int r = addnatrule(proto, eport, iaddr, iport); if(r >= 0) add_redirect_desc(eport, proto, desc); return r;}intadd_filter_rule2(const char * ifname, const char * iaddr, unsigned short eport, unsigned short iport, int proto, const char * desc){ return add_filter_rule(proto, iaddr, iport);}/* get_redirect_rule() * returns -1 if the rule is not found */intget_redirect_rule(const char * ifname, unsigned short eport, int proto, char * iaddr, int iaddrlen, unsigned short * iport, char * desc, int desclen, u_int64_t * packets, u_int64_t * bytes){ int r = -1; iptc_handle_t h; const struct ipt_entry * e; const struct ipt_entry_target * target; const struct ip_nat_multi_range * mr; const struct ipt_entry_match *match; h = iptc_init("nat"); if(!h) { syslog(LOG_ERR, "get_redirect_rule() : " "iptc_init() failed : %s", iptc_strerror(errno)); return -1; } if(!iptc_is_chain(miniupnpd_chain, h)) { syslog(LOG_ERR, "chain %s not found", miniupnpd_chain); } else { for(e = iptc_first_rule(miniupnpd_chain, &h); e; e = iptc_next_rule(e, &h)) { if(proto==e->ip.proto) { match = (const struct ipt_entry_match *)&e->elems; if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN)) { const struct ipt_tcp * info; info = (const struct ipt_tcp *)match->data; if(eport != info->dpts[0]) continue; } else { const struct ipt_udp * info; info = (const struct ipt_udp *)match->data; if(eport != info->dpts[0]) continue; } target = (void *)e + e->target_offset; mr = (const struct ip_nat_multi_range *)&target->data[0]; snprintip(iaddr, iaddrlen, ntohl(mr->range[0].min_ip)); *iport = ntohs(mr->range[0].min.all); /*if(desc) strncpy(desc, "miniupnpd", desclen);*/ get_redirect_desc(eport, proto, desc, desclen); if(packets) *packets = e->counters.pcnt; if(bytes) *bytes = e->counters.bcnt; r = 0; break; } } } iptc_free(&h); return r;}/* get_redirect_rule_by_index() * return -1 when the rule was not found */intget_redirect_rule_by_index(int index, char * ifname, unsigned short * eport, char * iaddr, int iaddrlen, unsigned short * iport, int * proto, char * desc, int desclen, u_int64_t * packets, u_int64_t * bytes){ int r = -1; int i = 0; iptc_handle_t h; const struct ipt_entry * e; const struct ipt_entry_target * target; const struct ip_nat_multi_range * mr; const struct ipt_entry_match *match; h = iptc_init("nat"); if(!h) { syslog(LOG_ERR, "get_redirect_rule_by_index() : " "iptc_init() failed : %s", iptc_strerror(errno)); return -1; } if(!iptc_is_chain(miniupnpd_chain, h)) { syslog(LOG_ERR, "chain %s not found", miniupnpd_chain); } else { for(e = iptc_first_rule(miniupnpd_chain, &h); e; e = iptc_next_rule(e, &h)) { if(i==index) { *proto = e->ip.proto; match = (const struct ipt_entry_match *)&e->elems; if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN)) { const struct ipt_tcp * info; info = (const struct ipt_tcp *)match->data; *eport = info->dpts[0]; } else { const struct ipt_udp * info; info = (const struct ipt_udp *)match->data; *eport = info->dpts[0]; } target = (void *)e + e->target_offset; mr = (const struct ip_nat_multi_range *)&target->data[0]; snprintip(iaddr, iaddrlen, ntohl(mr->range[0].min_ip)); *iport = ntohs(mr->range[0].min.all); /*if(desc) strncpy(desc, "miniupnpd", desclen);*/ get_redirect_desc(*eport, *proto, desc, desclen); if(packets) *packets = e->counters.pcnt; if(bytes) *bytes = e->counters.bcnt; r = 0; break; } i++; } } iptc_free(&h); return r;}/* delete_rule_and_commit() : * subfunction used in delete_redirect_and_filter_rules() */static intdelete_rule_and_commit(unsigned int index, iptc_handle_t *h, const char * logcaller){ int r = 0; if(!iptc_delete_num_entry(miniupnpd_chain, index, h)) { syslog(LOG_ERR, "%s() : iptc_delete_num_entry(): %s\n", logcaller, iptc_strerror(errno)); r = -1; } else if(!iptc_commit(h)) { syslog(LOG_ERR, "%s() : iptc_commit(): %s\n", logcaller, iptc_strerror(errno)); r = -1; } return r;}/* delete_redirect_and_filter_rules() */intdelete_redirect_and_filter_rules(unsigned short eport, int proto){ int r = -1; unsigned index = 0; unsigned i = 0; iptc_handle_t h; const struct ipt_entry * e; const struct ipt_entry_match *match; h = iptc_init("nat"); if(!h) { syslog(LOG_ERR, "delete_redirect_and_filter_rules() : " "iptc_init() failed : %s", iptc_strerror(errno)); return -1; } if(!iptc_is_chain(miniupnpd_chain, h)) { syslog(LOG_ERR, "chain %s not found", miniupnpd_chain); } else { for(e = iptc_first_rule(miniupnpd_chain, &h); e; e = iptc_next_rule(e, &h), i++) { if(proto==e->ip.proto) { match = (const struct ipt_entry_match *)&e->elems; if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN)) { const struct ipt_tcp * info; info = (const struct ipt_tcp *)match->data; if(eport != info->dpts[0]) continue; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -