1/*
2 * Copyright 2004, Broadcom Corporation
3 * All Rights Reserved.
4 *
5 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
6 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
7 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
8 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
9 *
10 * $Id: ipt.c,v 1.1.1.1 2008/10/15 03:31:35 james26_jang Exp $
11 */
12
13#include "upnp_dbg.h"
14#include "upnp_osl.h"
15#include "upnp.h"
16#include "igd.h"
17#include "wanipc.h"
18#include "netconf.h"
19#include "bcmnvram.h"
20#include "mapmgr.h"
21
22
23
24void print_rule(const netconf_nat_t *nat_current);
25void print_mapping(const mapping_t *m);
26
27/* extern and forward declaration */
28netconf_nat_t *parse_dnat(netconf_nat_t *entry, const char *Protocol,
29			  const char *RemoteHost, const char *ExternalStartPort, const char *ExternalEndPort,
30			  const char *InternalClient, const char *InternalStartPort, const char *InternalEndPort);
31
32static bool SameMatchInfo(const netconf_nat_t *e1, const netconf_nat_t *e2);
33
34
35void print_mapping(const mapping_t *m)
36{
37    printf("%s (%s)\n", m->desc, ((m->match.flags & NETCONF_DISABLED) ? "disabled" : "enabled"));
38    print_rule((netconf_nat_t *)m);
39}
40
41void print_rule(const netconf_nat_t *nat_current)
42{
43    const unsigned char *bytep;
44
45    printf("rule 0x%x ", (unsigned int) nat_current);
46    switch (nat_current->match.ipproto) {
47    case IPPROTO_TCP:
48	printf("TCP  ");
49	break;
50    case IPPROTO_UDP:
51	printf("UDP  ");
52	break;
53    default:
54	printf("unknown <0x%x>  ", nat_current->match.ipproto);
55    }
56    if (nat_current->target == NETCONF_DNAT)
57	printf("DNAT\n");
58    else
59	printf("UNNOWN <0x%x>\n", nat_current->target);
60
61    if (strlen(nat_current->match.in.name) > 0) {
62	printf("\tinput interface: %s\n", nat_current->match.in.name);
63    }
64    if (strlen(nat_current->match.out.name) > 0) {
65	printf("\toutput interface: %s\n", nat_current->match.out.name);
66    }
67
68    printf("wan ports:\t%ld - ",
69	   (unsigned long)ntohs(nat_current->match.dst.ports[0]));
70    printf("%ld\n",
71	   (unsigned long)ntohs(nat_current->match.dst.ports[1]));
72    bytep = (const unsigned char *) &(nat_current->ipaddr.s_addr);
73    printf("lan client: %d.%d.%d.%d\n", bytep[0], bytep[1], bytep[2], bytep[3]);
74    printf("lan ports:\t%ld - ",
75	   (unsigned long)ntohs(nat_current->ports[0]) );
76    printf("%ld\n",
77	   (unsigned long)ntohs(nat_current->ports[1]));
78}
79
80static bool SameInternalClient(netconf_nat_t *e1,   netconf_nat_t *e2)
81{
82    return (e1->ipaddr.s_addr == e2->ipaddr.s_addr);
83}
84
85/* Two mappings conflict if the ExternalPort,
86   PortMappingProtocol, and InternalClient are the same,
87   but RemoteHost is different.
88   pp 15, WANIPConection Sevice.
89*/
90static bool OverlappingRange(netconf_nat_t *e1, netconf_nat_t *e2)
91{
92    bool overlap = FALSE; /* assume no conflict */
93
94    do {
95	if (e1->ports[1] < e2->ports[0])
96	    break;
97	if (e1->ports[0] > e2->ports[1])
98	    break;
99
100	overlap = TRUE;
101	printf("OverlappingRange.\n");
102	printf("rule 1\n");
103	print_rule(e1);
104	printf("rule 2\n");
105	print_rule(e2);
106    } while(0);
107
108    printf("%s\n", (overlap ? "OverlappingRange" : "not OverlappingRange"));
109    return overlap;
110}
111
112int AddPortMapping( UFILE *uclient, PService psvc, PAction ac, pvar_entry_t args, int nargs)
113/* {"NewRemoteHost", VAR_RemoteHost, VAR_IN},				*/
114/* {"NewExternalPort", VAR_ExternalPort, VAR_IN},			*/
115/* {"NewProtocol", VAR_PortMappingProtocol, VAR_IN},			*/
116/* {"NewInternalPort", VAR_InternalPort, VAR_IN},			*/
117/* {"NewInternalClient", VAR_InternalClient, VAR_IN},			*/
118/* {"NewEnabled", VAR_PortMappingEnabled, VAR_IN},			*/
119/* {"NewPortMappingDescription", VAR_PortMappingDescription, VAR_IN},	*/
120/* {"NewLeaseDuration", VAR_PortMappingLeaseDuration, VAR_IN},		*/
121{
122    int i, parse_status, status = 0;
123    char *LeaseDuration =  ac->params[7].value;
124    char *Description = ac->params[6].value;
125    bool bEnabled = (bool) atoi(ac->params[5].value);
126    bool found_match;
127    netconf_nat_t e;
128    mapping_t mapping;
129    char *wan_ip;
130
131    // bypass port mapping when NAT is disabled
132    if (nvram_invmatch("wan_nat_x", "1")) return 0;
133
134    do {
135	if (atoi(LeaseDuration) != 0) {
136	    status = SOAP_ONLYPERMANENTLEASESSUPPORTED;
137	    continue;
138	}
139
140	if (nvram_invmatch("wan_ipaddr_t", ""))
141	{
142	     wan_ip = nvram_safe_get("wan_ipaddr_t");
143	}
144	else wan_ip = ac->params[0].value;
145
146	parse_status = (int) parse_dnat(&e,
147					ac->params[2].value, /* NewProtocol */
148					wan_ip, //ac->params[0].value, /* NewRemoteHost */
149					ac->params[1].value, NULL, /* NewExternalPort */
150					ac->params[4].value, /* NewInternalClient */
151					ac->params[3].value, NULL /* NewInternalPort */
152	);
153	if (!parse_status) {
154	    status = SOAP_INVALID_ARGS;
155	    continue;
156	}
157
158
159	found_match = FALSE;
160	for (i = 0; mapmgr_get_port_map(i, &mapping); i++) {
161	    if (SameMatchInfo(&e, (netconf_nat_t*)&mapping)) {
162		found_match = TRUE;
163		break;
164	    }
165	}
166
167	if (found_match) {
168	    if (!SameInternalClient(&e, &mapping)) {
169		// we already have that mapping, but a different target...error.
170		status = SOAP_CONFLICTINMAPPINGENTRY;
171		continue;
172	    } else {
173		mapmgr_delete_port_map(i);
174	    }
175	}
176
177	/* Enabled/disable this mapping according to the "NewEnabled" parameter. */
178	if (bEnabled) {
179	    e.match.flags &= ~NETCONF_DISABLED;
180	} else {
181	    e.match.flags |= NETCONF_DISABLED;
182	}
183
184	strncpy(e.desc, Description, sizeof(e.desc));
185
186	mapmgr_add_port_map(&e);
187
188    } while(0);
189
190    if (status)
191	soap_error( uclient, status );
192
193    return (status == 0);
194}
195
196
197int DeletePortMapping( UFILE *uclient, PService psvc, PAction ac, pvar_entry_t args, int nargs)
198/*  {"NewRemoteHost", VAR_RemoteHost, VAR_IN},		*/
199/*  {"NewExternalPort", VAR_ExternalPort, VAR_IN},	*/
200/*  {"NewProtocol", VAR_PortMappingProtocol, VAR_IN},	*/
201{
202    int i, parse_status, status = 0;
203    netconf_nat_t e;
204    mapping_t mapping;
205
206    // bypass port mapping when NAT is disabled
207    if (nvram_invmatch("wan_nat_x", "1")) return 0;
208
209    parse_status = (int) parse_dnat(&e,
210				    ac->params[2].value,	/* NewProtocol */
211				    ac->params[0].value,	/* NewRemoteHost */
212				    ac->params[1].value,	NULL, /* NewExternalPort */
213				    NULL,		/* NewInternalClient */
214				    NULL, NULL 		/* NewInternalPort */ );
215    if (!parse_status) {
216	status = SOAP_INVALID_ARGS;
217    } else {
218	status = SOAP_NOSUCHENTRYINARRAY;
219	for (i = 0; mapmgr_get_port_map(i, &mapping); i++) {
220	    if (SameMatchInfo(&e, (netconf_nat_t*)&mapping)) {
221		mapmgr_delete_port_map(i);
222		status = 0; /* SUCCESS! */
223	    }
224	}
225    }
226
227    if (status)
228	soap_error( uclient, status );
229
230    return (status == 0);
231}
232
233
234
235int GetGenericPortMappingEntry(UFILE *uclient, PService psvc, PAction ac, pvar_entry_t args, int nargs)
236/* {"NewPortMappingIndex", VAR_PortMappingNumberOfEntries, VAR_IN}, 	*/
237/* {"NewRemoteHost", VAR_RemoteHost, VAR_OUT}, 				*/
238/* {"NewExternalPort", VAR_ExternalPort, VAR_OUT}, 			*/
239/* {"NewProtocol", VAR_PortMappingProtocol, VAR_OUT}, 			*/
240/* {"NewInternalPort", VAR_InternalPort, VAR_OUT}, 			*/
241/* {"NewInternalClient", VAR_InternalClient, VAR_OUT}, 			*/
242/* {"NewEnabled", VAR_PortMappingEnabled, VAR_OUT}, 			*/
243/* {"NewPortMappingDescription", VAR_PortMappingDescription, VAR_OUT},	*/
244/* {"NewLeaseDuration", VAR_PortMappingLeaseDuration, VAR_OUT}, 	*/
245{
246    int success = TRUE;
247    char *PortMappingIndex = ac->params[0].value;
248    mapping_t mapping;
249    u_int32 i;
250    const unsigned char *bytep;
251    static char RemoteHost[16];
252    static char ExternalPort[7];
253    static char InternalClient[16];
254    static char InternalPort[7];
255    static char Enabled[2];
256    static char Description[60];
257
258    i = atoi(PortMappingIndex);
259    if (mapmgr_get_port_map(i, &mapping)) {
260	RemoteHost[0] = '\0';
261	if (mapping.match.src.ipaddr.s_addr) {
262	    bytep = (const unsigned char *) &(mapping.match.src.ipaddr);
263	    snprintf(RemoteHost, sizeof(RemoteHost),
264		     "%d.%d.%d.%d", bytep[0], bytep[1], bytep[2], bytep[3]);
265	}
266
267	InternalClient[0] = '\0';
268	if (mapping.ipaddr.s_addr) {
269	    bytep = (const unsigned char *) &(mapping.ipaddr);
270	    snprintf(InternalClient, sizeof(InternalClient),
271		     "%d.%d.%d.%d", bytep[0], bytep[1], bytep[2], bytep[3]);
272	}
273
274	snprintf(ExternalPort, sizeof(ExternalPort), "%d", ntohs(mapping.match.dst.ports[0]));
275	snprintf(InternalPort, sizeof(InternalPort), "%d", ntohs(mapping.ports[0]));
276	snprintf(Enabled, sizeof(Enabled), "%d", ((mapping.match.flags & NETCONF_DISABLED) ? 0 : 1));
277	snprintf(Description, sizeof(Description), "%s", mapping.desc);
278
279	ac->params[1].value = RemoteHost;
280	ac->params[2].value = ExternalPort;
281	ac->params[3].value = (mapping.match.ipproto == IPPROTO_TCP ? "TCP" :  "UDP" );
282	ac->params[4].value = InternalPort;
283	ac->params[5].value = InternalClient;
284	ac->params[6].value = Enabled;
285	ac->params[7].value = Description;
286	ac->params[8].value = "0";
287    } else {
288	soap_error( uclient, SOAP_SPECIFIEDARRAYINDEXINVALID );
289	success = FALSE;
290    }
291
292    return success;
293}
294
295
296int GetSpecificPortMappingEntry(UFILE *uclient, PService psvc, PAction ac, pvar_entry_t args, int nargs)
297/* {"NewRemoteHost", VAR_RemoteHost, VAR_IN},				*/
298/* {"NewExternalPort", VAR_ExternalPort, VAR_IN},			*/
299/* {"NewProtocol", VAR_PortMappingProtocol, VAR_IN},			*/
300/* {"NewInternalPort", VAR_InternalPort, VAR_OUT},			*/
301/* {"NewInternalClient", VAR_InternalClient, VAR_OUT},			*/
302/* {"NewEnabled", VAR_PortMappingEnabled, VAR_OUT},			*/
303/* {"NewPortMappingDescription", VAR_PortMappingDescription, VAR_OUT},	*/
304/* {"NewLeaseDuration", VAR_PortMappingLeaseDuration, VAR_OUT},		*/
305{
306    int i, parse_status, status;
307    netconf_nat_t e;
308    mapping_t mapping;
309    const unsigned char *bytep;
310    static char InternalClient[16];
311    static char InternalPort[7];
312    static char Enabled[2];
313    static char Description[60];
314
315printf("Get Port: [%s]\n", ac->params[0].value);
316
317    parse_status = (int) parse_dnat(&e,
318			       ac->params[2].value,	/* NewProtocol */
319			       ac->params[0].value,	/* NewRemoteHost */
320			       ac->params[1].value, NULL,	/* NewExternalPort */
321			       NULL,			/* NewInternalClient */
322			       NULL, NULL		/* NewInternalPort */ );
323
324    if (!parse_status) {
325	status = SOAP_INVALID_ARGS;
326    } else {
327	status = SOAP_NOSUCHENTRYINARRAY;
328	for (i = 0; mapmgr_get_port_map(i, &mapping); i++) {
329	    if (SameMatchInfo(&e, (netconf_nat_t*)&mapping)) {
330		InternalClient[0] = '\0';
331		if (mapping.ipaddr.s_addr) {
332		    bytep = (const unsigned char *) &(mapping.ipaddr);
333		    snprintf(InternalClient, sizeof(InternalClient),
334			     "%d.%d.%d.%d", bytep[0], bytep[1], bytep[2], bytep[3]);
335		}
336
337		snprintf(InternalPort, sizeof(InternalPort), "%d", ntohs(mapping.ports[0]));
338		snprintf(Enabled, sizeof(Enabled), "%d", ((mapping.match.flags & NETCONF_DISABLED) ? 0 : 1));
339		strncpy(Description, mapping.desc, sizeof(Description));
340
341		ac->params[3].value = InternalPort;
342		ac->params[4].value = InternalClient;
343		ac->params[5].value = Enabled;
344		ac->params[6].value = Description;
345		ac->params[7].value = "0";
346		status = 0; /* SUCCESS! */
347		break;
348	    }
349	}
350    }
351
352    if (status)
353	soap_error( uclient, status );
354
355    return (status == 0);
356}
357
358static bool SameMatchInfo(const netconf_nat_t *e1, const netconf_nat_t *e2)
359{
360    bool matched = FALSE;
361
362    do {
363	if (e1->match.ipproto != e2->match.ipproto) {
364	    break;
365	}
366
367	if (e1->match.src.ipaddr.s_addr &&
368	    ( e1->match.src.netmask.s_addr != e2->match.src.netmask.s_addr
369	      || e1->match.src.ipaddr.s_addr != e2->match.src.ipaddr.s_addr) ) {
370	    break;
371	}
372
373	if (e1->match.dst.ports[0] != 0
374	    && e1->match.dst.ports[0] != e2->match.dst.ports[0]) {
375	    break;
376	}
377	if (e1->match.dst.ports[1]
378	    && (e1->match.dst.ports[1] != e2->match.dst.ports[1])) {
379	    break;
380	}
381	matched = TRUE;
382    } while (0);
383
384    return matched;
385}
386
387
388netconf_nat_t *parse_dnat(netconf_nat_t *entry, const char *Protocol,
389			  const char *RemoteHost, const char *ExternalStartPort, const char *ExternalEndPort,
390			  const char *InternalClient, const char *InternalStartPort, const char *InternalEndPort)
391{
392    // it is always an error to not have these two arguments.
393    if (!Protocol || !RemoteHost || !ExternalStartPort)
394	return NULL;
395
396    memset(entry, 0, sizeof(netconf_nat_t));
397
398    // accept from any port
399    entry->match.src.ports[0] = 0;
400    entry->match.src.ports[1] = htons(0xffff);
401
402    // parse the external ip address
403    // 2004/07/12 by Joey, change to src ip match
404    if (strlen(RemoteHost))
405    {
406	inet_aton("255.255.255.255", &entry->match.dst.netmask);
407	inet_aton(RemoteHost , &entry->match.dst.ipaddr);
408    }
409    else if (nvram_invmatch("wan_ipaddr_t", ""))
410    {
411    	// set the destination ip address
412    	// 2004/07/12, by Joey, set dst ip
413	inet_aton("255.255.255.255", &entry->match.dst.netmask);
414	inet_aton(nvram_safe_get("wan_ipaddr_t"), &entry->match.dst.ipaddr);
415    }
416
417    // parse the external ports
418    if (!ExternalEndPort)
419	ExternalEndPort = ExternalStartPort;
420
421    entry->match.dst.ports[0] = htons(atoi(ExternalStartPort));
422    entry->match.dst.ports[1] = htons(atoi(ExternalEndPort));
423    if (entry->match.dst.ports[0] > entry->match.dst.ports[1])
424	return NULL;
425
426    // parse the specification of the internal NAT client.
427    entry->target = NETCONF_DNAT;
428
429    if (InternalClient && InternalStartPort) {
430
431	// parse the internal ip address.
432	inet_aton(InternalClient, (struct in_addr *)&entry->ipaddr);
433
434	// parse the internal port number
435	if (!InternalEndPort)
436	    InternalEndPort = InternalStartPort;
437	entry->ports[0] = htons(atoi(InternalStartPort));
438	entry->ports[1] = htons(atoi(InternalEndPort));
439
440	/* check that end port >= start port. */
441	if (entry->ports[0] > entry->ports[1])
442	    return NULL;
443
444	/* check that internal port range is the same size as the external port range. */
445	if ((entry->ports[1]-entry->ports[0])
446	    != (entry->match.dst.ports[1]-entry->match.dst.ports[0]))
447	    return NULL;
448    }
449
450    if (strcasecmp(Protocol, "TCP") == 0) {
451	entry->match.ipproto = IPPROTO_TCP;
452    } else if (strcasecmp(Protocol, "UDP") == 0) {
453	entry->match.ipproto = IPPROTO_UDP;
454    }
455
456
457    return entry;
458
459}
460
461