Patch for WANIPv6FirewallControl:1 service
[igd2-for-linux:igd2-for-linux.git] / linuxigd2 / src / wanipv6fw.c
1 /** 
2  * This file is part of igd2-for-linux project
3  * Copyright © 2011 France Telecom.
4  * Contact: fabrice.fontaine@orange-ftgroup.com
5  * Developer(s): fabrice.fontaine@orange-ftgroup.com, rmenard.ext@orange-ftgroup.com
6  *  
7  * This program is free software: you can redistribute it and/or modify 
8  * it under the terms of the GNU General Public License as published by 
9  * the Free Software Foundation, either version 2 of the License, or 
10  * (at your option) any later version. 
11  * 
12  * This program is distributed in the hope that it will be useful, 
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of 
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
15  * GNU General Public License for more details. 
16  * 
17  * You should have received a copy of the GNU General Public License 
18  * along with this program, see the /doc directory of this program. If 
19  * not, see http://www.gnu.org/licenses/. 
20  * 
21  */
22
23 #ifdef __cplusplus
24 extern "C" {
25 #endif
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <netinet/in.h>
31 #include <upnp/upnp.h>
32
33
34 #include "gatedevice.h"
35 #include "util.h"
36 #include "globals.h"
37 #include "wanipv6fw.h"
38 #include "pinholev6.h"
39
40
41 /**
42  * -----------------------------------------------------------------------------
43  * PRIVATE FONCTIONS ---
44  * -----------------------------------------------------------------------------
45  */
46
47 /**
48  * check if the IPv6 address given in string is usable
49  *
50  * @param ipv6address the ipv6 address to check in presentation mode (string)
51  * @return 1 if the adress is usable, 0 otherwise
52  */
53 int checkIPv6addressUsable (char* ipv6address) {
54
55     struct in6_addr addr;
56
57     //todo : check if this is a DNS
58
59     if(inet_pton(AF_INET6, ipv6address, &addr)==1)
60     {
61         return 1;
62     }
63
64     trace(1, "checkIPv6addressUsable : %s is NOT usable\n", ipv6address);
65     return 0;
66 }
67
68 /**
69  * check if the Ipv6 address given in parameter is used by the gateway
70  *
71  * @param ipv6address the ipv6 address to check in presentation mode (string)
72  * @return 1 if true, 0 otherwise
73  */
74 int checkGatewayIPv6Addresses(char* ipv6address)
75 {
76     char addr6[8][5];
77     FILE* inet6_procfd;
78     struct in6_addr v6_addr, ICv6addr;
79     char addrStr[INET6_ADDRSTRLEN];
80
81
82
83     if( inet_pton(AF_INET6, ipv6address, &ICv6addr) != 1 ) {
84         trace(1, "checkGatewayIPv6Addresses : cant evaluate ipv6 addresse %s\n",
85                 ipv6address);
86         return 0;
87     }
88
89     inet6_procfd = fopen( "/proc/net/if_inet6", "r" );
90     if( inet6_procfd != NULL ) {
91         while( fscanf(inet6_procfd,
92                 "%4s%4s%4s%4s%4s%4s%4s%4s %*02x %*02x %*02x %*02x %*20s\n",
93                 addr6[0],addr6[1],addr6[2],addr6[3],
94                 addr6[4],addr6[5],addr6[6],addr6[7]) != EOF) {
95
96             snprintf(addrStr, sizeof(addrStr), "%s:%s:%s:%s:%s:%s:%s:%s",
97                     addr6[0],addr6[1],addr6[2],addr6[3],
98                     addr6[4],addr6[5],addr6[6],addr6[7]);
99
100             if( inet_pton(AF_INET6, addrStr, &v6_addr) > 0 ) {
101
102                 if(memcmp(&ICv6addr, &v6_addr, 16) == 0) {
103                     trace(1, "ckeckGatewayIPv6addresses : %s found!!!\n",
104                             ipv6address);
105                     return 1;
106                 }
107             }
108         }
109     }
110     fclose( inet6_procfd );
111     return 0;
112 }
113
114 /*
115  * compare two IPv6 addresses (string and binary)
116  *
117  * @param ipv6address the ipv6 address to check in presentation mode (string)
118  * @param ss the other ipv6 address in binary mode
119  * @return 1 if both address are the same
120  */
121 int ipv6StrAddrCmp(char * ipv6address, struct sockaddr_storage * ss)
122 {
123     struct in6_addr str;
124     struct in6_addr *sock=&(((struct sockaddr_in6 *)ss)->sin6_addr);
125
126     if(ss->ss_family != AF_INET6) return 0;
127     if(inet_pton(AF_INET6, ipv6address, &str)==1)
128     {
129         return IN6_ARE_ADDR_EQUAL(&str,sock);
130     }
131     return 0;
132 }
133
134 /*
135  * compare two IPv6 addresses (binary and binary)
136  *
137  * @param ipv6address the ipv6 address to check in presentation mode (string)
138  * @param ss the other ipv6 address in binary mode
139  * @return 1 if both address are the same
140  */
141 int ipv6BinAddrCmp(struct in6_addr * ipv6address, struct sockaddr_storage * ss)
142 {
143     struct in6_addr *sock=&(((struct sockaddr_in6 *)ss)->sin6_addr);
144     if(ss->ss_family != AF_INET6) return 0;
145     return IN6_ARE_ADDR_EQUAL(ipv6address,sock);
146 }
147
148 /**
149  * error management
150  *
151  * @param error an integer according to upnp specification
152  * @param ca_event the action request which is used to answer to the control point
153  */
154 void errorManagement(int error, struct Upnp_Action_Request *ca_event)
155 {
156
157     ca_event->ActionResult = NULL;
158     ca_event->ErrCode = error;
159
160     switch(error)
161     {
162     case ERR_ACTION_NOT_AUTHORIZED :
163         trace(1, "WANIPv6FW Error : Action not authorized");
164         strcpy(ca_event->ErrStr, "Action not authorized");
165         break;
166     case ERR_PINHOLE_SPACE_EXHAUSTED :
167         trace(1, "WANIPv6FW Error : Pinhole space exhausted");
168         strcpy(ca_event->ErrStr, "PinholeSpaceExhausted");
169         break;
170     case ERR_FIREWALL_DISABLED :
171         trace(1, "WANIPv6FW Error : Firewall disabled");
172         strcpy(ca_event->ErrStr, "FirewallDisabled");
173         break;
174     case ERR_INBOUND_PINHOLE_NOT_ALLOWED :
175         trace(1, "WANIPv6FW Error : Inbound pinhole not allowed");
176         strcpy(ca_event->ErrStr, "InboundPinholeNotAllowed");
177         break;
178     case ERR_NO_SUCH_ENTRY :
179         trace(1, "WANIPv6FW Error : No such entry");
180         strcpy(ca_event->ErrStr, "NoSuchEntry");
181         break;
182     case ERR_PROTOCOL_NOT_SUPPORTED :
183         trace(1, "WANIPv6FW Error : Protocol not supported");
184         strcpy(ca_event->ErrStr, "ProtocolNotSupported");
185         break;
186     case ERR_INTERNAL_PORT_WILDCARD :
187         trace(1, "WANIPv6FW Error : Internal port wildcarding not allowed");
188         strcpy(ca_event->ErrStr, "InternalPortWildcardingNotAllowed");
189         break;
190     case ERR_PROTOCOL_WILDCARD :
191         trace(1, "WANIPv6FW Error : Protocol wildcarding not allowed");
192         strcpy(ca_event->ErrStr, "ProtocolWildcardingNotAllowed");
193         break;
194     case ERR_SRC_ADD_WILDCARD :
195         trace(1, "WANIPv6FW Error : Src IP wildcarding not allowed");
196         strcpy(ca_event->ErrStr, "WildCardNotPermittedInSrcIP");
197         break;
198     case ERR_NO_TRAFFIC :
199         trace(1, "WANIPv6FW Error : No traffic to check pinhole");
200         strcpy(ca_event->ErrStr, "NoTrafficReceived");
201         break;
202     case UPNP_SOAP_E_INVALID_ARGS :
203     default :
204         trace(1, "WANIPv6FW Error : Parsing problem");
205         addErrorData(ca_event, UPNP_SOAP_E_INVALID_ARGS, "Invalid Args"); 
206         break;
207     }
208
209
210 }
211
212 /**
213  * -----------------------------------------------------------------------------
214  * PUBLIC FONCTIONS
215  * -----------------------------------------------------------------------------
216  */
217
218
219 /**
220  * InitFirewallv6
221  *
222  * @return 1 if ok.
223  */
224 int InitFirewallv6(void)
225 {
226     if(g_vars.ipv6firewallEnabled)
227     return phv6_init();
228     return 1;
229
230 }
231 /**
232  * CloseFirewallv6
233  *
234  * @return 1 if ok
235  */
236 int CloseFirewallv6(void)
237 {
238     return phv6_close();
239 }
240
241 /**
242  * this function implements the WANIPv6FirewallControl:getFirewallStatus action
243  *
244  * @param ca_event The UPnP action request from the control point
245  * @return UPnP error code
246  */
247 int upnp_wanipv6_getFirewallStatus(struct Upnp_Action_Request *ca_event)
248 {
249     char resultStr[RESULT_LEN];
250     IXML_Document *result;
251
252     if(GetNbSoapParameters(ca_event->ActionRequest, "u:GetFirewallStatus") == 0) {
253
254         ca_event->ErrCode = UPNP_E_SUCCESS;
255         snprintf(resultStr, RESULT_LEN,
256                 "<u:GetFirewallStatusResponse xmlns:u="
257                 "\"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1\">\n"
258                 "<FirewallEnabled>%i</FirewallEnabled>\n"
259                 "<InboundPinholeAllowed>%i</InboundPinholeAllowed>\n"
260                 "</u:GetFirewallStatusResponse>",
261                 g_vars.ipv6firewallEnabled,
262                 g_vars.ipv6inboundPinholeAllowed);
263
264         // Create a IXML_Document from resultStr and return with ca_event
265         if ((result = ixmlParseBuffer(resultStr)) != NULL)
266         {
267             ca_event->ActionResult = result;
268             ca_event->ErrCode = UPNP_E_SUCCESS;
269         }
270         else
271         {
272             errorManagement(UPNP_SOAP_E_INVALID_ARGS, ca_event);
273         }
274
275     }
276
277     else {
278         trace(1, "GetFirewallStatus invalid number of parameters");
279         errorManagement(UPNP_SOAP_E_INVALID_ARGS, ca_event);
280     }
281
282     return(ca_event->ErrCode);
283
284 }
285
286 /**
287  * this function implements the WANIPv6FirewallControl:getOutboundPinholeTimeOut action
288  *
289  * @param ca_event The UPnP action request from the control point
290  * @return UPnP error code
291  */
292 int upnp_wanipv6_getOutboundPinholeTimeOut(struct Upnp_Action_Request *ca_event)
293 {
294     char *remote_host=NULL;
295     char *remote_port=NULL;
296     char *internal_client=NULL;
297     char *internal_port=NULL;
298     char *protocol=NULL;
299     char resultStr[RESULT_LEN];
300     IXML_Document *result;
301     int error = 0;
302
303     if ( (remote_host = GetFirstDocumentItem(
304             ca_event->ActionRequest, "RemoteHost") )
305             && (remote_port = GetFirstDocumentItem(
306                     ca_event->ActionRequest, "RemotePort") )
307             && (internal_client = GetFirstDocumentItem(
308                     ca_event->ActionRequest, "InternalClient") )
309             && (internal_port = GetFirstDocumentItem(
310                     ca_event->ActionRequest, "InternalPort") )
311             && (protocol = GetFirstDocumentItem(
312                     ca_event->ActionRequest, "Protocol") )
313             && (GetNbSoapParameters(ca_event->ActionRequest,
314                     "u:GetOutboundPinholeTimeout") == 5 ) )
315     {
316
317         if(!(checkForWildCard(internal_client))
318                 && (checkIPv6addressUsable(internal_client)==0))
319         {
320             //invalid args, not IPv6 adresses
321             trace(1, "Failure in GetOutboundPinholeTimeout:Invalid Arguments!");
322             trace(1, " Internal Client: %s \n",internal_client);
323             errorManagement(UPNP_SOAP_E_INVALID_ARGS, ca_event);
324             error = UPNP_SOAP_E_INVALID_ARGS;
325         }
326
327         else if(!checkForWildCard(remote_host)
328                 && (checkIPv6addressUsable(remote_host)==0))
329         {
330             //invalid args, not IPv6 adresses
331             trace(1, "Failure in GetOutboundPinholeTimeout:Invalid Arguments!");
332             trace(1, " RemoteHost: %s \n",remote_host);
333             errorManagement(UPNP_SOAP_E_INVALID_ARGS, ca_event);
334             error = UPNP_SOAP_E_INVALID_ARGS;
335         }
336
337         else if(!checkForWildCard(remote_port)
338                 && (!isStringInteger(remote_port)))
339         {
340             //invalid args, not a port number
341             trace(1, "Failure in GetOutboundPinholeTimeout:Invalid Arguments!");
342             trace(1, " RemotePort: %s \n",remote_port);
343             errorManagement(UPNP_SOAP_E_INVALID_ARGS, ca_event);
344             error = UPNP_SOAP_E_INVALID_ARGS;
345         }
346
347         else if(!checkForWildCard(internal_port)
348                 && (!isStringInteger(internal_port)))
349         {
350             //invalid args, not a port number
351             trace(1, "Failure in GetOutboundPinholeTimeout:Invalid Arguments!");
352             trace(1, " InternalPort: %s \n",internal_port);
353             errorManagement(UPNP_SOAP_E_INVALID_ARGS, ca_event);
354             error = UPNP_SOAP_E_INVALID_ARGS;
355         }
356
357         else if ( atoi(protocol) != 65535
358                 &&(atoi(protocol) != IPPROTO_UDPLITE)
359                 && (atoi(protocol) != IPPROTO_UDP)
360                 && (atoi(protocol) != IPPROTO_TCP))
361         {
362             //error 705 protocol not supported
363             errorManagement(ERR_PROTOCOL_NOT_SUPPORTED, ca_event);
364             error = ERR_PROTOCOL_NOT_SUPPORTED;
365         }
366
367         if(error == 0)
368         {
369             int timeout = 0;
370             FILE* timeout_file = NULL;
371
372             if(atoi(protocol) == IPPROTO_UDPLITE) {
373                 timeout_file = fopen(
374                         "/proc/sys/net/netfilter/nf_conntrack_udplite_timeout",
375                         "r" );
376             }
377             else if(atoi(protocol) == IPPROTO_UDP) {
378                 timeout_file = fopen(
379                         "/proc/sys/net/netfilter/nf_conntrack_udp_timeout",
380                         "r" );
381             }
382             else if(atoi(protocol) == IPPROTO_TCP) {
383                 timeout_file = fopen(
384                         "/proc/sys/net/netfilter/nf_conntrack_tcp_timeout_established",
385                         "r" );
386             }
387
388             if(timeout_file != NULL)
389             {
390                 if(fscanf(timeout_file, "%i",&timeout) != EOF);
391                 fclose(timeout_file);
392             }
393             else
394             {
395                 timeout_file = fopen(
396                         "/proc/sys/net/netfilter/nf_conntrack_generic_timeout",
397                         "r" );
398                 if( timeout_file != NULL ) {
399                     if(fscanf(timeout_file, "%i",&timeout) != EOF);
400                     fclose(timeout_file);
401                 }
402                 else
403                 {
404                     //TODO no nf_conntrack module loaded
405                 }
406             }
407
408             ca_event->ErrCode = UPNP_E_SUCCESS;
409             snprintf(resultStr, RESULT_LEN,
410                     "<u:GetOutboundPinholeTimeoutResponse "
411                     "xmlns:u=\"urn:schemas-upnp-org:service:"
412                     "WANIPv6FirewallControl:1\">\n"
413                     "<OutboundPinholeTimeout>%i</OutboundPinholeTimeout>\n"
414                     "</u:GetOutboundPinholeTimeoutResponse>",timeout);
415
416             // Create a IXML_Document from resultStr and return with ca_event
417             if ((result = ixmlParseBuffer(resultStr)) != NULL)
418             {
419                 ca_event->ActionResult = result;
420                 ca_event->ErrCode = UPNP_E_SUCCESS;
421             }
422             else
423             {
424                 errorManagement(UPNP_SOAP_E_INVALID_ARGS, ca_event);
425             }
426         }
427
428     }
429     else
430     {
431         trace(1, "Failure in GetOutboundPinholeTimeout:"
432                 "Invalid Arguments!");
433         trace(1, "  RemoteHost: %s RemotePort: %s InternalClient: "
434                 "%s InternalPort: %s Protocol: ",
435                 remote_host, remote_port, internal_client,
436                 internal_port, protocol);
437         errorManagement(UPNP_SOAP_E_INVALID_ARGS, ca_event);
438         return UPNP_SOAP_E_INVALID_ARGS;
439     }
440
441     if (remote_host) free(remote_host);
442     if (remote_port) free(remote_port);
443     if (internal_client) free(internal_client);
444     if (internal_port) free(internal_port);
445     if (protocol) free(protocol);
446
447
448
449     return(ca_event->ErrCode);
450 }
451
452 /**
453  * this function implements the WANIPv6FirewallControl:addPinhole action
454  *
455  * @param ca_event The UPnP action request from the control point
456  * @return UPnP error code
457  */
458 int upnp_wanipv6_addPinhole(struct Upnp_Action_Request *ca_event)
459 {
460
461     char *remote_host=NULL;
462     char *remote_port=NULL;
463     char *internal_client=NULL;
464     char *internal_port=NULL;
465     char *protocol=NULL;
466     char *lease_time=NULL;
467     char resultStr[RESULT_LEN];
468     IXML_Document *result;
469     uint32_t UniqueId;
470     int error = 0;
471
472     if ( (remote_host = GetFirstDocumentItem(
473             ca_event->ActionRequest, "RemoteHost") )
474             && (remote_port = GetFirstDocumentItem(
475                     ca_event->ActionRequest, "RemotePort") )
476             && (internal_client = GetFirstDocumentItem(
477                     ca_event->ActionRequest, "InternalClient") )
478             && (internal_port = GetFirstDocumentItem(
479                     ca_event->ActionRequest, "InternalPort") )
480             && (protocol = GetFirstDocumentItem(
481                     ca_event->ActionRequest, "Protocol") )
482             && (lease_time = GetFirstDocumentItem(
483                     ca_event->ActionRequest, "LeaseTime") )
484             && (GetNbSoapParameters(ca_event->ActionRequest,
485                     "u:AddPinhole") == 6 ) )
486     {
487         if(!g_vars.ipv6firewallEnabled)
488         {
489             //error 702 firewall disabled
490             errorManagement(ERR_FIREWALL_DISABLED, ca_event);
491             return(ERR_FIREWALL_DISABLED);
492         }
493
494         if(!g_vars.ipv6inboundPinholeAllowed)
495         {
496             //error 703 not authorized
497             errorManagement(ERR_INBOUND_PINHOLE_NOT_ALLOWED, ca_event);
498             return(ERR_INBOUND_PINHOLE_NOT_ALLOWED);
499         }
500
501         if( (!checkForWildCard(remote_host)
502                 && checkIPv6addressUsable(remote_host)==0) )
503         {
504             //invalid args, not IPv6 adresses
505             trace(1, " RemoteHost: %s \n",remote_host);
506             errorManagement(UPNP_SOAP_E_INVALID_ARGS, ca_event);
507             error = UPNP_SOAP_E_INVALID_ARGS;
508         }
509
510         else if(!checkForWildCard(remote_port)
511                 && (!isStringInteger(remote_port)))
512         {
513             //invalid args, not a port number
514             trace(1, "Failure in AddPinhole:Invalid Arguments!");
515             trace(1, " RemotePort: %s \n",remote_port);
516             errorManagement(UPNP_SOAP_E_INVALID_ARGS, ca_event);
517             error = UPNP_SOAP_E_INVALID_ARGS;
518         }
519
520         else if(checkForWildCard(internal_client))
521         {
522             trace(1, " Internal client is wildcarded");
523             errorManagement(ERR_SRC_ADD_WILDCARD, ca_event);
524             error = ERR_SRC_ADD_WILDCARD;
525         }
526
527         else if(checkIPv6addressUsable(internal_client)==0) {
528             trace(1, " Internal client : %s",internal_client);
529             errorManagement(UPNP_SOAP_E_INVALID_ARGS, ca_event);
530             error = UPNP_SOAP_E_INVALID_ARGS;
531         }
532
533         else if(checkGatewayIPv6Addresses(internal_client))
534         {
535             trace(1, "Can not use the gateway's IP address");
536             errorManagement(ERR_ACTION_NOT_AUTHORIZED, ca_event);
537             error = ERR_ACTION_NOT_AUTHORIZED;
538         }
539
540         else if (!isStringInteger(protocol))
541         {
542             trace(1, "Invalid protocol:%s", protocol);
543             errorManagement(UPNP_SOAP_E_INVALID_ARGS, ca_event);
544             error = UPNP_SOAP_E_INVALID_ARGS;
545         }
546
547         else if (atoi(protocol) == 65535)
548         {
549             trace(1, "Wild cards not permitted in protocol:%s", protocol);
550             errorManagement(ERR_PROTOCOL_WILDCARD, ca_event);
551             error = ERR_PROTOCOL_WILDCARD;
552         }
553
554         else if ( (atoi(protocol) != IPPROTO_UDPLITE)
555                 && (atoi(protocol) != IPPROTO_UDP)
556                 && (atoi(protocol) != IPPROTO_TCP) )
557         {
558             //error 705 protocol not supported
559             errorManagement(ERR_PROTOCOL_NOT_SUPPORTED, ca_event);
560             error = ERR_PROTOCOL_NOT_SUPPORTED;
561         }
562
563         // if Internal port is <1024 and InternalClient is different from control point
564         // control point needs to be authorized
565         else if ( ( (atoi(internal_port) < 1024 && atoi(internal_port) > 0)
566                 || !ipv6StrAddrCmp(internal_client, &ca_event->CtrlPtIPAddr))
567                 && ( AuthorizeControlPoint(ca_event, 0, 1) != CONTROL_POINT_NOT_AUTHORIZED ))
568         {
569             trace(1, "Internal port number must be greater than 1023 "
570                     "and InternalClient must be same as IP of Control point "
571                     "unless control point is authorized. "
572                     "internal_port:%s internal_client:%s",
573                     internal_port, internal_client);
574             errorManagement(ERR_ACTION_NOT_AUTHORIZED, ca_event);
575             error = ERR_ACTION_NOT_AUTHORIZED;
576         }
577
578         // Check InternalPort parameter
579         else if (checkForWildCard(internal_port))
580         {
581             trace(1, "Wild cards not permitted in internal port:%s",
582                     internal_port);
583             errorManagement(ERR_INTERNAL_PORT_WILDCARD, ca_event);
584             error = ERR_INTERNAL_PORT_WILDCARD;
585         }
586
587         else if(!isStringInteger(internal_port))
588         {
589             trace(1, "InternalPort is not a port number:%s",
590                     internal_port);
591             errorManagement(UPNP_SOAP_E_INVALID_ARGS, ca_event);
592             error = UPNP_SOAP_E_INVALID_ARGS;
593         }
594
595         // check that leaseduration is between 1 and 86400
596         else if ((atoi(lease_time) < 1) || (atoi(lease_time) > 86400)
597                 || !isStringInteger(lease_time))
598         {
599             trace(1, "lease time must be between 1 and 86400");
600             errorManagement(UPNP_SOAP_E_INVALID_ARGS, ca_event);
601             error = UPNP_SOAP_E_INVALID_ARGS;
602         }
603
604
605         else if(phv6_existingPinhole(internal_client,
606                 remote_host,
607                 internal_port,
608                 remote_port,
609                 protocol,
610                 &UniqueId))
611         {
612             phv6_updatePinhole(UniqueId,(uint32_t)atoi(lease_time));
613         }
614         //else add the pinhole int the list
615         else if(phv6_addPinhole(internal_client,
616                 remote_host,
617                 internal_port,
618                 remote_port,
619                 protocol,
620                 (uint32_t)atoi(lease_time),
621                 &UniqueId) < 0)
622         {
623             trace(1, "AddPinhole out of memory");
624             errorManagement(ERR_PINHOLE_SPACE_EXHAUSTED, ca_event);
625             error = ERR_PINHOLE_SPACE_EXHAUSTED;
626         }
627
628
629         if(error == 0)
630         {
631
632             ca_event->ErrCode = UPNP_E_SUCCESS;
633             snprintf(resultStr, RESULT_LEN,
634                     "<u:AddPinholeResponse xmlns:u=\"urn:schemas-upnp-org:"
635                     "service:WANIPv6FirewallControl:1\">\n"
636                     "<UniqueID>%i</UniqueID>\n"
637                     "</u:AddPinholeResponse>",UniqueId);
638
639             if ((result = ixmlParseBuffer(resultStr)) != NULL)
640             {
641                 ca_event->ActionResult = result;
642                 ca_event->ErrCode = UPNP_E_SUCCESS;
643             }
644             else
645             {
646                 errorManagement(UPNP_SOAP_E_INVALID_ARGS, ca_event);
647             }
648         }
649
650     }
651
652     else
653     {
654         trace(1, "Failure in AddPinhole: Invalid Arguments!");
655         trace(1, "  RemotePort: %s RemoteHost: %s Protocol: %s "
656                 "InternalPort: %s InternalClient: %s leaseTime: %s",
657                 remote_port, remote_host, protocol,
658                 internal_port, internal_client, lease_time);
659         errorManagement(UPNP_SOAP_E_INVALID_ARGS, ca_event);
660     }
661
662
663     if (remote_host) free(remote_host);
664     if (remote_port) free(remote_port);
665     if (internal_client) free(internal_client);
666     if (internal_port) free(internal_port);
667     if (protocol) free(protocol);
668     if (lease_time) free(lease_time);
669
670
671     return(ca_event->ErrCode);
672
673 }
674
675 /**
676  * this function implements the WANIPv6FirewallControl:updatePinhole action
677  *
678  * @param ca_event The UPnP action request from the control point
679  * @return UPnP error code
680  */
681 int upnp_wanipv6_updatePinhole(struct Upnp_Action_Request *ca_event)
682 {
683     char internal_client[INET6_ADDRSTRLEN];
684     char *lease_time=NULL;
685     char *unique_id=NULL;
686     char resultStr[RESULT_LEN];
687     IXML_Document *result;
688     int error = 0;
689     struct pinholev6 * pinhole;
690
691     if ( (unique_id = GetFirstDocumentItem(
692             ca_event->ActionRequest, "UniqueID") )
693             && (isStringInteger(unique_id) )
694             && (lease_time = GetFirstDocumentItem(
695                     ca_event->ActionRequest, "NewLeaseTime") )
696             && (isStringInteger(lease_time) )
697             && (GetNbSoapParameters(
698                     ca_event->ActionRequest, "u:UpdatePinhole") == 2 ) )
699     {
700         if(!g_vars.ipv6firewallEnabled)
701         {
702             //error 702 firewall disabled
703             errorManagement(ERR_FIREWALL_DISABLED, ca_event);
704             return(ERR_FIREWALL_DISABLED);
705         }
706
707         if(!g_vars.ipv6inboundPinholeAllowed)
708         {
709             errorManagement(ERR_INBOUND_PINHOLE_NOT_ALLOWED, ca_event);
710             return(ERR_INBOUND_PINHOLE_NOT_ALLOWED);
711         }
712
713         if(phv6_findPinhole((uint32_t)atoi(unique_id), &pinhole)) {
714             //pinhole found
715
716             // if Internal port is <1024 and InternalClient is different from control point
717             // control point needs to be authorized
718             if ((( pinhole->internal_port < 1024
719                     && pinhole->internal_port > 0)
720                     || !ipv6BinAddrCmp(pinhole->internal_client,
721                             &ca_event->CtrlPtIPAddr) )
722                     && ( AuthorizeControlPoint(ca_event, 0, 1) != CONTROL_POINT_NOT_AUTHORIZED ))
723             {
724                 trace(1, "Internal port number must be greater than 1023 "
725                         "and InternalClient must be same as IP of Control point \
726                         unless control point is authorized. "
727                         "internal_port:%i internal_client:%s",
728                         pinhole->internal_port, internal_client);
729                 errorManagement(ERR_ACTION_NOT_AUTHORIZED, ca_event);
730                 error = ERR_ACTION_NOT_AUTHORIZED;
731             }
732
733             // check that leaseduration is between 1 and 86400
734             else if ((atoi(lease_time) < 1) || (atoi(lease_time) > 86400))
735             {
736                 trace(1, "lease time must be between 1 and 86400");
737                 errorManagement(UPNP_SOAP_E_INVALID_ARGS, ca_event);
738                 error = UPNP_SOAP_E_INVALID_ARGS;
739             }
740
741
742             if(error == 0)
743             {
744                 phv6_updatePinhole((uint32_t)atoi(unique_id),
745                         (uint32_t)atoi(lease_time));
746
747                 snprintf(resultStr, RESULT_LEN,
748                         "<u:UpdatePinholeResponse xmlns:u=\"urn:schemas-upnp"
749                         "-org:service:WANIPv6FirewallControl:1\">\n"
750                         "</u:UpdatePinholeResponse>");
751
752                 if ((result = ixmlParseBuffer(resultStr)) != NULL)
753                 {
754                     ca_event->ActionResult = result;
755                     ca_event->ErrCode = UPNP_E_SUCCESS;
756                 }
757                 else
758                 {
759                     errorManagement(UPNP_SOAP_E_INVALID_ARGS, ca_event);
760                 }
761             }
762         }
763         else
764         {
765             //pinhole not found
766             errorManagement(ERR_NO_SUCH_ENTRY, ca_event);
767             error = ERR_NO_SUCH_ENTRY;
768         }
769     }
770     else
771     {
772         trace(1, "Failure in UpdatePinhole: Invalid Arguments!");
773         errorManagement(UPNP_SOAP_E_INVALID_ARGS, ca_event);
774     }
775
776     if (lease_time) free(lease_time);
777     if (unique_id) free(unique_id);
778
779     return(ca_event->ErrCode);
780 }
781
782 /**
783  * this function implements the WANIPv6FirewallControl:deletePinhole action
784  *
785  * @param ca_event The UPnP action request from the control point
786  * @return UPnP error code
787  */
788 int upnp_wanipv6_deletePinhole(struct Upnp_Action_Request *ca_event)
789 {
790     char resultStr[RESULT_LEN];
791     char internal_client[INET6_ADDRSTRLEN];
792     char *unique_id = NULL;
793     IXML_Document *result;
794     struct pinholev6 * pinhole;
795     int error = 0;
796
797     if ( (unique_id = GetFirstDocumentItem(
798             ca_event->ActionRequest, "UniqueID"))
799             && (isStringInteger(unique_id) )
800             && (GetNbSoapParameters(
801                     ca_event->ActionRequest,
802                     "u:DeletePinhole") == 1 ) )
803     {
804         if(!g_vars.ipv6firewallEnabled)
805         {
806             errorManagement(ERR_FIREWALL_DISABLED, ca_event);
807             return(ERR_FIREWALL_DISABLED);
808         }
809
810         if(!g_vars.ipv6inboundPinholeAllowed)
811         {
812             errorManagement(ERR_INBOUND_PINHOLE_NOT_ALLOWED, ca_event);
813             return(ERR_INBOUND_PINHOLE_NOT_ALLOWED);
814         }
815
816         if(phv6_findPinhole((uint32_t)atoi(unique_id), &pinhole)) {
817             //pinhole found
818             // if Internal port is <1024 and InternalClient is different from control point
819             // control point needs to be authorized
820             if (((pinhole->internal_port < 1024 && pinhole->internal_port > 0)
821                     || !ipv6BinAddrCmp(pinhole->internal_client,
822                             &ca_event->CtrlPtIPAddr) )
823                     && ( AuthorizeControlPoint(ca_event, 0, 1) != CONTROL_POINT_NOT_AUTHORIZED ))
824             {
825                 trace(1, "Internal port number must be greater than 1023"
826                         " and InternalClient must be same as IP of Control point \
827                         unless control point is authorized. "
828                         "internal_port:%i internal_client:%s",
829                         pinhole->internal_port, internal_client);
830                 errorManagement(ERR_ACTION_NOT_AUTHORIZED, ca_event);
831                 error = ERR_ACTION_NOT_AUTHORIZED;
832             }
833
834             if(error == 0) {
835
836                 phv6_deletePinhole((uint32_t)atoi(unique_id));
837
838                 snprintf(resultStr, RESULT_LEN,
839                         "<u:DeletePinholeResponse xmlns:u=\"urn:schemas-upnp-"
840                         "org:service:WANIPv6FirewallControl:1\">\n"
841                         "</u:DeletePinholeResponse>");
842
843                 // Create a IXML_Document from resultStr and return with ca_event
844                 if ((result = ixmlParseBuffer(resultStr)) != NULL)
845                 {
846                     ca_event->ActionResult = result;
847                     ca_event->ErrCode = UPNP_E_SUCCESS;
848                 }
849                 else
850                 {
851                     errorManagement(UPNP_SOAP_E_INVALID_ARGS, ca_event);
852                 }
853             }
854
855         }
856         else
857         {
858             //pinhole not found
859             errorManagement(ERR_NO_SUCH_ENTRY, ca_event);
860             error = ERR_NO_SUCH_ENTRY;
861         }
862     }
863     else
864     {
865         trace(1, "Failure in DeletePinhole: Invalid Arguments!");
866         errorManagement(UPNP_SOAP_E_INVALID_ARGS, ca_event);
867
868     }
869
870     if(unique_id) free(unique_id);
871
872     return(ca_event->ErrCode);
873
874 }
875
876 /**
877  * this function implements the WANIPv6FirewallControl:getPinholePackets action
878  *
879  * @param ca_event The UPnP action request from the control point
880  * @return UPnP error code
881  */
882 int upnp_wanipv6_getPinholePackets(struct Upnp_Action_Request *ca_event)
883 {
884     char resultStr[RESULT_LEN];
885     char internal_client[INET6_ADDRSTRLEN];
886     char *unique_id = NULL;
887     IXML_Document *result;
888     struct pinholev6 * pinhole;
889     int error = 0;
890     int packets = 0;
891
892     if ( (unique_id = GetFirstDocumentItem(
893             ca_event->ActionRequest, "UniqueID"))
894             && (isStringInteger(unique_id) )
895             && (GetNbSoapParameters(
896                     ca_event->ActionRequest,
897                     "u:GetPinholePackets") == 1 ) )
898     {
899         if(!g_vars.ipv6firewallEnabled)
900         {
901             errorManagement(ERR_FIREWALL_DISABLED, ca_event);
902             return(ERR_FIREWALL_DISABLED);
903         }
904
905         if(!g_vars.ipv6inboundPinholeAllowed)
906         {
907             errorManagement(ERR_INBOUND_PINHOLE_NOT_ALLOWED, ca_event);
908             return(ERR_INBOUND_PINHOLE_NOT_ALLOWED);
909         }
910
911         if(phv6_findPinhole((uint32_t)atoi(unique_id), &pinhole)) {
912             //pinhole found
913             // if Internal port is <1024 and InternalClient is different from control point
914             // control point needs to be authorized
915             if (((pinhole->internal_port < 1024 && pinhole->internal_port > 0)
916                     || !ipv6BinAddrCmp(pinhole->internal_client,
917                             &ca_event->CtrlPtIPAddr) )
918                     && ( AuthorizeControlPoint(ca_event, 0, 1) != CONTROL_POINT_NOT_AUTHORIZED ))
919             {
920                 trace(1, "Internal port number must be greater than 1023 "
921                         "and InternalClient must be same as IP of Control point \
922                         unless control point is authorized. "
923                         "internal_port:%i internal_client:%s",
924                         pinhole->internal_port, internal_client);
925                 errorManagement(ERR_ACTION_NOT_AUTHORIZED, ca_event);
926                 error = ERR_ACTION_NOT_AUTHORIZED;
927             }
928
929             if(error == 0) {
930
931                 phv6_getPinholePackets((uint32_t)atoi(unique_id), &packets);
932
933                 snprintf(resultStr, RESULT_LEN,
934                         "<u:GetPinholePacketsResponse xmlns:u=\"urn:schemas-"
935                         "upnp-org:service:WANIPv6FirewallControl:1\">\n"
936                         "<PinholePackets>%i</PinholePackets>\n"
937                         "</u:GetPinholePacketsResponse>",packets);
938
939                 // Create a IXML_Document from resultStr and return with ca_event
940                 if ((result = ixmlParseBuffer(resultStr)) != NULL)
941                 {
942                     ca_event->ActionResult = result;
943                     ca_event->ErrCode = UPNP_E_SUCCESS;
944                 }
945                 else
946                 {
947                     errorManagement(UPNP_SOAP_E_INVALID_ARGS, ca_event);
948                 }
949             }
950
951         }
952         else
953         {
954             //pinhole not found
955             errorManagement(ERR_NO_SUCH_ENTRY, ca_event);
956             error = ERR_NO_SUCH_ENTRY;
957         }
958     }
959     else
960     {
961         trace(1, "Failure in DeletePinhole: Invalid Arguments!");
962         errorManagement(UPNP_SOAP_E_INVALID_ARGS, ca_event);
963
964     }
965
966     if(unique_id) free(unique_id);
967
968     return(ca_event->ErrCode);
969 }
970
971 /**
972  * this function implements the WANIPv6FirewallControl:checkPinholeWorking action
973  *
974  * @param ca_event The UPnP action request from the control point
975  * @return UPnP error code
976  */
977 int upnp_wanipv6_checkPinholeWorking(struct Upnp_Action_Request *ca_event)
978 {
979
980     char resultStr[RESULT_LEN];
981     char internal_client[INET6_ADDRSTRLEN];
982     char *unique_id = NULL;
983     IXML_Document *result;
984     struct pinholev6 * pinhole;
985     int error = 0;
986
987     if ( (unique_id = GetFirstDocumentItem(
988             ca_event->ActionRequest, "UniqueID") )
989             && (isStringInteger(unique_id) )
990             && (GetNbSoapParameters(
991                     ca_event->ActionRequest,
992                     "u:CheckPinholeWorking") == 1 ) )
993     {
994         if(!g_vars.ipv6firewallEnabled)
995         {
996             errorManagement(ERR_FIREWALL_DISABLED, ca_event);
997             return(ERR_FIREWALL_DISABLED);
998         }
999
1000         if(!g_vars.ipv6inboundPinholeAllowed)
1001         {
1002             errorManagement(ERR_INBOUND_PINHOLE_NOT_ALLOWED, ca_event);
1003             return(ERR_INBOUND_PINHOLE_NOT_ALLOWED);
1004         }
1005
1006         if(phv6_findPinhole((uint32_t)atoi(unique_id), &pinhole)) {
1007             //pinhole found
1008
1009
1010             // if Internal port is <1024 or InternalClient is different from control point
1011             // control point needs to be authorized
1012             if (((pinhole->internal_port < 1024 && pinhole->internal_port > 0)
1013                     || !ipv6BinAddrCmp(pinhole->internal_client,
1014                             &ca_event->CtrlPtIPAddr) )
1015                     && ( AuthorizeControlPoint(ca_event, 0, 1) != CONTROL_POINT_NOT_AUTHORIZED ))
1016             {
1017                 trace(1, "Internal port number must be greater than 1023"
1018                         " and InternalClient must be same as IP of Control point \
1019                         unless control point is authorized. "
1020                         "internal_port:%i internal_client:%s",
1021                         pinhole->internal_port, internal_client);
1022                 errorManagement(ERR_ACTION_NOT_AUTHORIZED, ca_event);
1023                 error = ERR_ACTION_NOT_AUTHORIZED;
1024             }
1025
1026
1027
1028             if(error == 0)
1029             {
1030                 int isWorking = phv6_checkPinholeWorking((uint32_t)atoi(unique_id));
1031
1032                 if(isWorking == -1)
1033                 {
1034                     //no traffic detected
1035                     errorManagement(ERR_NO_TRAFFIC, ca_event);
1036                     error = ERR_NO_TRAFFIC;
1037                 }
1038
1039                 else {
1040
1041                     snprintf(resultStr, RESULT_LEN,
1042                             "<u:CheckPinholeWorkingResponse xmlns:u=\"urn:"
1043                             "schemas-upnp-org:service:WANIPv6FirewallControl:1\">\n"
1044                             "<IsWorking>%i</IsWorking>\n"
1045                             "</u:CheckPinholeWorkingResponse>", isWorking);
1046
1047                     // Create a IXML_Document from resultStr and return with ca_event
1048                     if ((result = ixmlParseBuffer(resultStr)) != NULL)
1049                     {
1050                         ca_event->ActionResult = result;
1051                         ca_event->ErrCode = UPNP_E_SUCCESS;
1052                     }
1053                     else
1054                     {
1055                         errorManagement(UPNP_SOAP_E_INVALID_ARGS, ca_event);
1056                     }
1057                 }
1058             }
1059
1060         }
1061         else
1062         {
1063             //pinhole not found
1064             errorManagement(ERR_NO_SUCH_ENTRY, ca_event);
1065             error = ERR_NO_SUCH_ENTRY;
1066         }
1067     }
1068     else
1069     {
1070         trace(1, "Failure in CheckPinholeWorking: Invalid Arguments!");
1071         errorManagement(UPNP_SOAP_E_INVALID_ARGS, ca_event);
1072
1073     }
1074
1075     if(unique_id) free(unique_id);
1076
1077     return(ca_event->ErrCode);
1078
1079 }
1080
1081 #ifdef __cplusplus
1082 }
1083 #endif