1 /* $Id: portlistingparse.c,v 1.9 2015/07/15 12:41:13 nanard Exp $ */
2 /* MiniUPnP project
3  * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
4  * (c) 2011-2020 Thomas Bernard
5  * This software is subject to the conditions detailed
6  * in the LICENCE file provided within the distribution */
7 #include <string.h>
8 #include <stdlib.h>
9 #ifdef DEBUG
10 #include <stdio.h>
11 #endif /* DEBUG */
12 #include "portlistingparse.h"
13 #include "minixml.h"
14 
15 #if defined(__HAIKU__)
16 /* rename our private function because Haiku already defines a atoui() function */
17 #define atoui atoui2
18 #endif
19 
20 /* list of the elements */
21 static const struct {
22 	const portMappingElt code;
23 	const char * const str;
24 } elements[] = {
25 	{ PortMappingEntry, "PortMappingEntry"},
26 	{ NewRemoteHost, "NewRemoteHost"},
27 	{ NewExternalPort, "NewExternalPort"},
28 	{ NewProtocol, "NewProtocol"},
29 	{ NewInternalPort, "NewInternalPort"},
30 	{ NewInternalClient, "NewInternalClient"},
31 	{ NewEnabled, "NewEnabled"},
32 	{ NewDescription, "NewDescription"},
33 	{ NewLeaseTime, "NewLeaseTime"},
34 	{ PortMappingEltNone, NULL}
35 };
36 
37 /* Helper function */
38 static UNSIGNED_INTEGER
atoui(const char * p,int l)39 atoui(const char * p, int l)
40 {
41 	UNSIGNED_INTEGER r = 0;
42 	while(l > 0 && *p)
43 	{
44 		if(*p >= '0' && *p <= '9')
45 			r = r*10 + (*p - '0');
46 		else
47 			break;
48 		p++;
49 		l--;
50 	}
51 	return r;
52 }
53 
54 /* Start element handler */
55 static void
startelt(void * d,const char * name,int l)56 startelt(void * d, const char * name, int l)
57 {
58 	int i;
59 	struct PortMappingParserData * pdata = (struct PortMappingParserData *)d;
60 	pdata->curelt = PortMappingEltNone;
61 	for(i = 0; elements[i].str; i++)
62 	{
63 		if(strlen(elements[i].str) == (size_t)l && memcmp(name, elements[i].str, l) == 0)
64 		{
65 			pdata->curelt = elements[i].code;
66 			break;
67 		}
68 	}
69 	if(pdata->curelt == PortMappingEntry)
70 	{
71 		struct PortMapping * pm;
72 		pm = calloc(1, sizeof(struct PortMapping));
73 		if(pm == NULL)
74 		{
75 			/* malloc error */
76 #ifdef DEBUG
77 			fprintf(stderr, "%s: error allocating memory",
78 			        "startelt");
79 #endif /* DEBUG */
80 			return;
81 		}
82 		pm->l_next = pdata->l_head;	/* insert in list */
83 		pdata->l_head = pm;
84 	}
85 }
86 
87 /* End element handler */
88 static void
endelt(void * d,const char * name,int l)89 endelt(void * d, const char * name, int l)
90 {
91 	struct PortMappingParserData * pdata = (struct PortMappingParserData *)d;
92 	(void)name;
93 	(void)l;
94 	pdata->curelt = PortMappingEltNone;
95 }
96 
97 /* Data handler */
98 static void
data(void * d,const char * data,int l)99 data(void * d, const char * data, int l)
100 {
101 	struct PortMapping * pm;
102 	struct PortMappingParserData * pdata = (struct PortMappingParserData *)d;
103 	pm = pdata->l_head;
104 	if(!pm)
105 		return;
106 	if(l > 63)
107 		l = 63;
108 	switch(pdata->curelt)
109 	{
110 	case NewRemoteHost:
111 		memcpy(pm->remoteHost, data, l);
112 		pm->remoteHost[l] = '\0';
113 		break;
114 	case NewExternalPort:
115 		pm->externalPort = (unsigned short)atoui(data, l);
116 		break;
117 	case NewProtocol:
118 		if(l > 3)
119 			l = 3;
120 		memcpy(pm->protocol, data, l);
121 		pm->protocol[l] = '\0';
122 		break;
123 	case NewInternalPort:
124 		pm->internalPort = (unsigned short)atoui(data, l);
125 		break;
126 	case NewInternalClient:
127 		memcpy(pm->internalClient, data, l);
128 		pm->internalClient[l] = '\0';
129 		break;
130 	case NewEnabled:
131 		pm->enabled = (unsigned char)atoui(data, l);
132 		break;
133 	case NewDescription:
134 		memcpy(pm->description, data, l);
135 		pm->description[l] = '\0';
136 		break;
137 	case NewLeaseTime:
138 		pm->leaseTime = atoui(data, l);
139 		break;
140 	default:
141 		break;
142 	}
143 }
144 
145 
146 /* Parse the PortMappingList XML document for IGD version 2
147  */
148 void
ParsePortListing(const char * buffer,int bufsize,struct PortMappingParserData * pdata)149 ParsePortListing(const char * buffer, int bufsize,
150                  struct PortMappingParserData * pdata)
151 {
152 	struct xmlparser parser;
153 
154 	memset(pdata, 0, sizeof(struct PortMappingParserData));
155 	/* init xmlparser */
156 	parser.xmlstart = buffer;
157 	parser.xmlsize = bufsize;
158 	parser.data = pdata;
159 	parser.starteltfunc = startelt;
160 	parser.endeltfunc = endelt;
161 	parser.datafunc = data;
162 	parser.attfunc = 0;
163 	parsexml(&parser);
164 }
165 
166 void
FreePortListing(struct PortMappingParserData * pdata)167 FreePortListing(struct PortMappingParserData * pdata)
168 {
169 	struct PortMapping * pm;
170 	while((pm = pdata->l_head) != NULL)
171 	{
172 		/* remove from list */
173 		pdata->l_head = pm->l_next;
174 		free(pm);
175 	}
176 }
177 
178