1/* 2 * Broadcom UPnP module linux netfilter configuration 3 * 4 * Copyright (C) 2010, Broadcom Corporation. All Rights Reserved. 5 * 6 * Permission to use, copy, modify, and/or distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 13 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 15 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 * 18 * $Id: upnpnat.c,v 1.5 2009/11/10 06:38:36 Exp $ 19 */ 20#include <stdio.h> 21#include <stdlib.h> 22#include <errno.h> 23#include <string.h> 24#include <arpa/inet.h> 25#include <netconf.h> 26 27/* 28 * UPnP portmapping -- 29 * Add port forward and a matching ACCEPT rule to the FORWARD table 30 */ 31static void 32add_nat_entry(netconf_nat_t *entry, int log_level) 33{ 34 int dir = NETCONF_FORWARD; 35 int target = (log_level & 2) ? NETCONF_LOG_ACCEPT : NETCONF_ACCEPT; 36 netconf_filter_t filter; 37 struct in_addr netmask = { 0xffffffff }; 38 netconf_nat_t nat = *entry; 39 40 /* Set up LAN side match */ 41 memset(&filter, 0, sizeof(filter)); 42 filter.match.ipproto = nat.match.ipproto; 43 filter.match.src.ports[1] = nat.match.src.ports[1]; 44 filter.match.dst.ipaddr.s_addr = nat.ipaddr.s_addr; 45 filter.match.dst.netmask.s_addr = netmask.s_addr; 46 filter.match.dst.ports[0] = nat.ports[0]; 47 filter.match.dst.ports[1] = nat.ports[1]; 48 strncpy(filter.match.in.name, nat.match.in.name, IFNAMSIZ); 49 50 /* Accept connection */ 51 filter.target = target; 52 filter.dir = dir; 53 54 /* Do it */ 55 netconf_add_nat(&nat); 56 netconf_add_filter(&filter); 57} 58 59/* Combination PREROUTING DNAT and FORWARD ACCEPT */ 60static void 61delete_nat_entry(netconf_nat_t *entry, int log_level) 62{ 63 int dir = NETCONF_FORWARD; 64 int target = (log_level & 2) ? NETCONF_LOG_ACCEPT : NETCONF_ACCEPT; 65 netconf_filter_t filter; 66 struct in_addr netmask = { 0xffffffff }; 67 netconf_nat_t nat = *entry; 68 69 /* Set up LAN side match */ 70 memset(&filter, 0, sizeof(filter)); 71 filter.match.ipproto = nat.match.ipproto; 72 filter.match.src.ports[1] = nat.match.src.ports[1]; 73 filter.match.dst.ipaddr.s_addr = nat.ipaddr.s_addr; 74 filter.match.dst.netmask.s_addr = netmask.s_addr; 75 filter.match.dst.ports[0] = nat.ports[0]; 76 filter.match.dst.ports[1] = nat.ports[1]; 77 strncpy(filter.match.in.name, nat.match.in.name, IFNAMSIZ); 78 79 /* Accept connection */ 80 filter.target = target; 81 filter.dir = dir; 82 83 /* Do it */ 84 errno = netconf_del_nat(&nat); 85 if (errno) 86 fprintf(stderr, "netconf_del_nat returned error %d\n", errno); 87 88 errno = netconf_del_filter(&filter); 89 if (errno) 90 fprintf(stderr, "netconf_del_filter returned error %d\n", errno); 91} 92 93void 94usage(void) 95{ 96 fprintf(stderr, 97 "usage: upnpnat [-i ifname] [-remote value] " 98 "[-eport value] [-proto value] [-eport value] " 99 "[-client value] [-en vlaue] [-loglevel value]"); 100 exit(0); 101} 102 103 104/* Command to add or delete from NAT engine */ 105int 106main(int argc, char *argv[]) 107{ 108 netconf_nat_t nat, *entry = &nat; 109 char ifname[IFNAMSIZ] = {0}; 110 char Proto[8] = {0}; 111 char IntIP[sizeof("255.255.255.255")] = {0}; 112 char rthost[sizeof("255.255.255.255")] = {0}; 113 unsigned short IntPort = 0; 114 unsigned short ExtPort = 0; 115 int enable = 0; 116 int log_level = 0; 117 118 /* Skip program name */ 119 --argc; 120 ++argv; 121 122 if (!*argv) 123 usage(); 124 125 for (; *argv; ++argv) { 126 if (!strcmp(*argv, "-i")) { 127 if (*++argv) { 128 strncpy(ifname, *argv, sizeof(ifname)); 129 } 130 } 131 else if (!strcmp(*argv, "-remote")) { 132 if (*++argv) { 133 strncpy(rthost, *argv, sizeof(rthost)); 134 rthost[sizeof(rthost)-1] = 0; 135 } 136 } 137 else if (!strcmp(*argv, "-eport")) { 138 if (*++argv) { 139 ExtPort = atoi(*argv); 140 } 141 } 142 else if (!strcmp(*argv, "-proto")) { 143 if (*++argv) { 144 strncpy(Proto, *argv, sizeof(Proto)); 145 Proto[sizeof(Proto)-1] = 0; 146 } 147 } 148 else if (!strcmp(*argv, "-iport")) { 149 if (*++argv) { 150 IntPort = atoi(*argv); 151 } 152 } 153 else if (!strcmp(*argv, "-client")) { 154 if (*++argv) { 155 strncpy(IntIP, *argv, sizeof(IntIP)); 156 IntIP[sizeof(IntIP)-1] = 0; 157 } 158 } 159 else if (!strcmp(*argv, "-en")) { 160 if (*++argv) { 161 enable = atoi(*argv); 162 } 163 } 164 else if (!strcmp(*argv, "-log_level")) { 165 if (*++argv) { 166 log_level = atoi(*argv); 167 } 168 } 169 else { 170 usage(); 171 } 172 } 173 174 memset(entry, 0, sizeof(netconf_nat_t)); 175 176 /* accept from any port */ 177 strncpy(entry->match.in.name, ifname, IFNAMSIZ); 178 entry->match.src.ports[0] = 0; 179 entry->match.src.ports[1] = htons(0xffff); 180 entry->match.dst.ports[0] = htons(ExtPort); 181 entry->match.dst.ports[1] = htons(ExtPort); 182 183 if (strlen(rthost)) { 184 inet_aton("255.255.255.255", &entry->match.dst.netmask); 185 inet_aton(rthost, &entry->match.dst.ipaddr); 186 } 187 188 /* parse the specification of the internal NAT client. */ 189 entry->target = NETCONF_DNAT; 190 191 if (IntPort != 0) { 192 /* parse the internal ip address. */ 193 inet_aton(IntIP, (struct in_addr *)&entry->ipaddr); 194 195 /* parse the internal port number */ 196 entry->ports[0] = htons(IntPort); 197 entry->ports[1] = htons(IntPort); 198 } 199 200 if (strcasecmp(Proto, "TCP") == 0) { 201 entry->match.ipproto = IPPROTO_TCP; 202 } 203 else if (strcasecmp(Proto, "UDP") == 0) { 204 entry->match.ipproto = IPPROTO_UDP; 205 } 206 207 /* set to NAT kernel */ 208 if (enable) { 209 entry->match.flags &= ~NETCONF_DISABLED; 210 add_nat_entry(entry, log_level); 211 } 212 else { 213 entry->match.flags |= NETCONF_DISABLED; 214 delete_nat_entry(entry, log_level); 215 } 216 217 return 0; 218} 219