📄 upnpredirect.c
字号:
/* $Id: upnpredirect.c,v 1.34 2007/11/02 22:56:04 nanard Exp $ *//* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (c) 2006-2007 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */#include <stdlib.h>#include <string.h>#include <syslog.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <net/if.h>#include <arpa/inet.h>#include "config.h"#include "upnpredirect.h"#include "upnpglobalvars.h"#if defined(USE_NETFILTER)#include "netfilter/iptcrdr.h"#endif#if defined(USE_PF)#include "pf/obsdrdr.h"#endif#if defined(USE_IPF)#include "ipf/ipfrdr.h"#endif#ifdef USE_MINIUPNPDCTL#include <stdio.h>#include <unistd.h>#endif/* proto_atoi() * convert the string "UDP" or "TCP" to IPPROTO_UDP and IPPROTO_UDP */static intproto_atoi(const char * protocol){ int proto = IPPROTO_TCP; if(strcmp(protocol, "UDP") == 0) proto = IPPROTO_UDP; return proto;}/* upnp_redirect() * calls OS/fw dependant implementation of the redirection. * protocol should be the string "TCP" or "UDP" * returns: 0 on success * -1 failed to redirect * -2 already redirected * -3 permission check failed */intupnp_redirect(unsigned short eport, const char * iaddr, unsigned short iport, const char * protocol, const char * desc){ int proto, r; char iaddr_old[32]; unsigned short iport_old; struct in_addr address; proto = proto_atoi(protocol); if(inet_aton(iaddr, &address) < 0) { syslog(LOG_ERR, "inet_aton(%s) : %m", iaddr); return -1; } if(!check_upnp_rule_against_permissions(upnppermlist, num_upnpperm, eport, address, iport)) { syslog(LOG_INFO, "redirection permission check failed for " "%hu->%s:%hu %s", eport, iaddr, iport, protocol); return -3; } r = get_redirect_rule(ext_if_name, eport, proto, iaddr_old, sizeof(iaddr_old), &iport_old, 0, 0, 0, 0); if(r == 0) { /* if existing redirect rule matches redirect request return success * xbox 360 does not keep track of the port it redirects and will * redirect another port when receiving ConflictInMappingEntry */ if(strcmp(iaddr,iaddr_old)==0 && iport==iport_old) { syslog(LOG_INFO, "ignoring redirect request as it matches existing redirect"); } else { syslog(LOG_INFO, "port %hu protocol %s already redirected to %s:%hu", eport, protocol, iaddr_old, iport_old); return -2; } } else { syslog(LOG_INFO, "redirecting port %hu to %s:%hu protocol %s for: %s", eport, iaddr, iport, protocol, desc); return upnp_redirect_internal(eport, iaddr, iport, proto, desc);#if 0 if(add_redirect_rule2(ext_if_name, eport, iaddr, iport, proto, desc) < 0) { return -1; } syslog(LOG_INFO, "creating pass rule to %s:%hu protocol %s for: %s", iaddr, iport, protocol, desc); if(add_filter_rule2(ext_if_name, iaddr, eport, iport, proto, desc) < 0) { /* clean up the redirect rule */#if !defined(__linux__) delete_redirect_rule(ext_if_name, eport, proto);#endif return -1; }#endif } return 0;}intupnp_redirect_internal(unsigned short eport, const char * iaddr, unsigned short iport, int proto, const char * desc){ /*syslog(LOG_INFO, "redirecting port %hu to %s:%hu protocol %s for: %s", eport, iaddr, iport, protocol, desc); */ if(add_redirect_rule2(ext_if_name, eport, iaddr, iport, proto, desc) < 0) { return -1; }/* syslog(LOG_INFO, "creating pass rule to %s:%hu protocol %s for: %s", iaddr, iport, protocol, desc);*/ if(add_filter_rule2(ext_if_name, iaddr, eport, iport, proto, desc) < 0) { /* clean up the redirect rule */#if !defined(__linux__) delete_redirect_rule(ext_if_name, eport, proto);#endif return -1; } return 0;}intupnp_get_redirection_infos(unsigned short eport, const char * protocol, unsigned short * iport, char * iaddr, int iaddrlen, char * desc, int desclen){ if(desc && (desclen > 0)) desc[0] = '\0'; return get_redirect_rule(ext_if_name, eport, proto_atoi(protocol), iaddr, iaddrlen, iport, desc, desclen, 0, 0);}intupnp_get_redirection_infos_by_index(int index, unsigned short * eport, char * protocol, unsigned short * iport, char * iaddr, int iaddrlen, char * desc, int desclen){ /*char ifname[IFNAMSIZ];*/ int proto = 0; if(desc && (desclen > 0)) desc[0] = '\0'; if(get_redirect_rule_by_index(index, 0/*ifname*/, eport, iaddr, iaddrlen, iport, &proto, desc, desclen, 0, 0) < 0) return -1; else { if(proto == IPPROTO_TCP) memcpy(protocol, "TCP", 4); else memcpy(protocol, "UDP", 4); return 0; }}int_upnp_delete_redir(unsigned short eport, int proto){ int r;#if defined(__linux__) r = delete_redirect_and_filter_rules(eport, proto);#else r = delete_redirect_rule(ext_if_name, eport, proto); delete_filter_rule(ext_if_name, eport, proto);#endif return r;}intupnp_delete_redirection(unsigned short eport, const char * protocol){ syslog(LOG_INFO, "removing redirect rule port %hu %s", eport, protocol); return _upnp_delete_redir(eport, proto_atoi(protocol));}/* functions used to remove unused rules */struct rule_state *get_upnp_rules_state_list(int max_rules_number_target){ char ifname[IFNAMSIZ]; int proto; unsigned short iport; struct rule_state * tmp; struct rule_state * list = 0; int i = 0; tmp = malloc(sizeof(struct rule_state)); if(!tmp) return 0; while(get_redirect_rule_by_index(i, ifname, &tmp->eport, 0, 0, &iport, &proto, 0, 0, &tmp->packets, &tmp->bytes) >= 0) { tmp->proto = (short)proto; /* add tmp to list */ tmp->next = list; list = tmp; /* prepare next iteration */ i++; tmp = malloc(sizeof(struct rule_state)); if(!tmp) break; } free(tmp); /* return empty list if not enough redirections */ if(i<=max_rules_number_target) while(list) { tmp = list; list = tmp->next; free(tmp); } /* return list */ return list;}voidremove_unused_rules(struct rule_state * list){ char ifname[IFNAMSIZ]; unsigned short iport; struct rule_state * tmp; u_int64_t packets; u_int64_t bytes; int n = 0; while(list) { /* remove the rule if no traffic has used it */ if(get_redirect_rule(ifname, list->eport, list->proto, 0, 0, &iport, 0, 0, &packets, &bytes) >= 0) { if(packets == list->packets && bytes == list->bytes) { _upnp_delete_redir(list->eport, list->proto); n++; } } tmp = list; list = tmp->next; free(tmp); } if(n>0) syslog(LOG_NOTICE, "removed %d unused rules", n);}/* stuff for miniupnpdctl */#ifdef USE_MINIUPNPDCTLvoidwrite_ruleset_details(int s){ char ifname[IFNAMSIZ]; int proto = 0; unsigned short eport, iport; char desc[64]; char iaddr[32]; u_int64_t packets; u_int64_t bytes; int i = 0; char buffer[256]; int n; while(get_redirect_rule_by_index(i, ifname, &eport, iaddr, sizeof(iaddr), &iport, &proto, desc, sizeof(desc), &packets, &bytes) >= 0) { n = snprintf(buffer, sizeof(buffer), "%2d %s %s %hu->%s:%hu " "'%s' %llu %llu\n", i, ifname, proto==IPPROTO_TCP?"TCP":"UDP", eport, iaddr, iport, desc, packets, bytes); write(s, buffer, n); i++; }}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -