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