1 /*
2     Copyright (C) 2009  Thomas Ries <tries@gmx.net>
3 
4     This file is part of Siproxd.
5 
6     Siproxd is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     Siproxd is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warrantry of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with Siproxd; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20 
21 /* must be defined before including <plugin.h> */
22 #define PLUGIN_NAME	plugin_stun
23 
24 #include "config.h"
25 
26 #include <string.h>
27 
28 #include <sys/types.h>
29 #include <netinet/in.h>
30 #include <arpa/inet.h>
31 #include <time.h>
32 
33 #include <osipparser2/osip_parser.h>
34 #include <osipparser2/osip_md5.h>
35 
36 #include "siproxd.h"
37 #include "digcalc.h"
38 #include "plugins.h"
39 #include "log.h"
40 
41 static char const ident[]="$Id: plugin_stun.c 479 2011-06-11 21:51:40Z hb9xar $";
42 
43 /* Plug-in identification */
44 static char name[]="plugin_stun";
45 static char desc[]="Use an external STUN server to determine my public IP";
46 
47 /* global configuration storage - required for config file location */
48 extern struct siproxd_config configuration;
49 
50 /* plugin configuration storage */
51 static struct plugin_config {
52    char *server;
53    int  port;
54    int period;
55 } plugin_cfg;
56 
57 /* Instructions for config parser */
58 static cfgopts_t plugin_cfg_opts[] = {
59    { "plugin_stun_server",      TYP_STRING, &plugin_cfg.server,	{0, NULL} },
60    { "plugin_stun_port",        TYP_INT4, &plugin_cfg.port,	{3478, NULL} },
61    { "plugin_stun_period",      TYP_INT4, &plugin_cfg.period,	{300, NULL} },
62    {0, 0, 0}
63 };
64 
65 /*
66  * module-local function prototypes
67  */
68 static int stun_validate_response(char *buffer, int len, char *tid);
69 static int stun_send_request(char *tid);
70 static int stun_new_transaction_id(char *tid);
71 
72 /*
73  * constants used in this module
74  */
75 #define STUN_TID_SIZE	16	/* STUN transaction ID size: 16 bytes */
76 
77 
78 /*
79  * Initialization.
80  * Called once suring siproxd startup.
81  */
PLUGIN_INIT(plugin_def_t * plugin_def)82 int  PLUGIN_INIT(plugin_def_t *plugin_def) {
83    /* API version number of siproxd that this plugin is built against.
84     * This constant will change whenever changes to the API are made
85     * that require adaptions in the plugin. */
86    plugin_def->api_version=SIPROXD_API_VERSION;
87 
88    /* Name and descriptive text of the plugin */
89    plugin_def->name=name;
90    plugin_def->desc=desc;
91 
92    /* Execution mask - during what stages of SIP processing shall
93     * the plugin be called. */
94    plugin_def->exe_mask=PLUGIN_PROCESS_RAW|PLUGIN_TIMER;
95 
96    /* read the config file */
97    if (read_config(configuration.configfile,
98                    configuration.config_search,
99                    plugin_cfg_opts, name) == STS_FAILURE) {
100       ERROR("Plugin '%s': could not load config file", name);
101       return STS_FAILURE;
102    }
103 
104 /*&&& resolve STUN server
105 store IP
106 */
107 
108    INFO("plugin_stun is initialized, using %s:%i as STUN server",
109         plugin_cfg.server, plugin_cfg.port);
110    return STS_SUCCESS;
111 }
112 
113 /*
114  * Processing.
115  *
116  */
PLUGIN_PROCESS(int stage,sip_ticket_t * ticket)117 int  PLUGIN_PROCESS(int stage, sip_ticket_t *ticket){
118    static time_t next_stun_send=0;
119    static int rq_pending=0; /* !=0 if waiting for response (ongoing dialog) */
120 
121    static union {
122       char stun_transaction_id[STUN_TID_SIZE];
123       uint16_t  port;
124    } u;
125 
126    time_t now;
127    int sts;
128 
129    /* stage contains the PLUGIN_* value - the stage of SIP processing. */
130    DEBUGC(DBCLASS_BABBLE, "called in stage %i, rq_pending=%i",
131           stage, rq_pending);
132 
133    time(&now);
134 
135    switch (stage) {
136       case PLUGIN_TIMER:
137          if (next_stun_send <= now) {
138             /* compose and send new STUN request */
139             DEBUGC(DBCLASS_BABBLE, "preparing to send STUN request");
140 
141             /* allocate transaction ID if a new STUN transaction */
142             if (rq_pending == 0) {
143                sts = stun_new_transaction_id(u.stun_transaction_id);
144             }
145 
146             /* send STUN BIND request */
147             sts = stun_send_request(u.stun_transaction_id);
148 
149             rq_pending=1;
150             /* 10 seconds T/O to receive answer until retrying */
151             next_stun_send = now + 10;
152          }
153          break;
154 
155       case PLUGIN_PROCESS_RAW:
156          /* raw UDP packet: ticket->raw_buffer, len: ticket->raw_buffer_len */
157          sts = stun_validate_response(ticket->raw_buffer,
158                                       ticket->raw_buffer_len,
159                                       u.stun_transaction_id);
160          if (sts == STS_SUCCESS) {
161             /* is a valid response to our last STUN request */
162             /* This is about what we get:
163             +-----------------+-----------------+
164             |........�..type..|........�...len..|   [0]..[4]
165             +-----------------+-----------------+
166             |      Transaction ID               |   [5]..
167             |                                   |
168             |                                   |
169             |                                   |      ..[19]
170             +-----------------+-----------------+
171             |........�.type...|........�...len..|  [20]..     Attribute
172             +-----------------+-----------------+
173             |  len bytes                        |
174             |                                   |
175             +-----------------+-----------------+
176             |........�.type...|........�...len..|            Attribute
177             +-----------------+-----------------+
178             |                                   |
179             ...
180             */
181 { /* clean up & move to function! */
182             int i, j;
183             int len=ticket->raw_buffer_len;
184             char *buffer=ticket->raw_buffer;
185             int iptype;
186             uint16_t port;
187             unsigned char ip[4];
188             char ipstring[IPSTRING_SIZE];
189             int got_address=0;
190 
191             i=20;		// 1st attribute position
192 
193             while (i+4 <= len) {
194                int attr_typ = ntohs(*((int *)&buffer[i]) & 0x0000ffff);
195                int attr_len = ntohs(*((int *)&buffer[i+2]) & 0x0000ffff);
196 
197                DEBUGC(DBCLASS_BABBLE,"STUN response: i=%i, type=%i, len=%i",
198                       i, attr_typ, attr_len);
199 
200                /* check if attribute is fully contained in message */
201                if ((i+4+attr_len) > len) {
202                   DEBUGC(DBCLASS_BABBLE,"corrupt STUN response");
203                   break;
204                }
205 
206                /* advance to start of attribute */
207                i = i+4;
208 
209                switch (attr_typ) {
210                   /* 0x0001 Mapped Address */
211                   case 0x0001:
212                      DEBUGC(DBCLASS_BABBLE,"Mapped Addr, len=%i", attr_len);
213                      iptype=*((int*)&buffer[i+1]) & 0x000000ff;
214                      if (iptype != 0x0001) {
215                         DEBUGC(DBCLASS_BABBLE,
216                                "Mapped Addr, wrong proto family [%i]", iptype);
217                         break;
218                      }
219 
220                      port=htons(*((int*)&buffer[i+2]) & 0x0000ffff);
221                      memcpy(ip,&buffer[i+4], 4);
222 
223                      DEBUGC(DBCLASS_BABBLE,"STUN: public IP %u.%u.%u.%u:%i",
224                             ip[0], ip[1], ip[2], ip[3], port);
225                      /* remember normal IP address only if not yet known */
226                      if (got_address == 0) {
227                         snprintf(ipstring, IPSTRING_SIZE-1, "%u.%u.%u.%u",
228                                  ip[0], ip[1], ip[2], ip[3]);
229                         ipstring[IPSTRING_SIZE-1]='\0';
230                         got_address=1;
231                      }
232                      break;
233 
234                   /* 0x8020 XOR Mapped Address */
235                   case 0x8020:
236                      DEBUGC(DBCLASS_BABBLE,"XOR Mapped Addr, len=%i", attr_len);
237                      iptype=*((int*)&buffer[i+1]) & 0x000000ff;
238 
239                      if (iptype != 0x0001) {
240                         DEBUGC(DBCLASS_BABBLE,
241                                "Mapped Addr, wrong proto family [%i]", iptype);
242                         break;
243                      }
244 
245                      port=*((int*)&buffer[i+2]) & 0x0000ffff;
246                      /* XOR the port with start of TID */
247 //                     port = port ^ *((short int*)stun_transaction_id);
248                      port = port ^ u.port;
249                      port = htons(port);
250                      memcpy(ip,&buffer[i+4], 4);
251                      /* XOR the IP with start of TID */
252                      for (j=0; j<4; j++) {
253                         ip[j]=ip[j] ^ u.stun_transaction_id[j];
254                      }
255                      DEBUGC(DBCLASS_BABBLE,"STUN: public IP %u.%u.%u.%u:%i",
256                             ip[0], ip[1], ip[2], ip[3], port);
257 
258                      /* remember XORed IP address always (preferred) */
259                      snprintf(ipstring, IPSTRING_SIZE-1, "%u.%u.%u.%u",
260                               ip[0], ip[1], ip[2], ip[3]);
261                      ipstring[IPSTRING_SIZE-1]='\0';
262                      got_address=1;
263                      break;
264 
265                   default:
266                      /* don't care... */
267                      break;
268                }
269                /* advance to next attribute */
270                i=i+attr_len;
271             }
272 
273             if (got_address && (
274                 (configuration.outbound_host == NULL) ||
275                 (strcmp(configuration.outbound_host, ipstring) != 0) ) ) {
276 
277                INFO("STUN: public IP has changed %s -> %s",
278                     (configuration.outbound_host) ?
279                     configuration.outbound_host:"NULL" ,
280                     ipstring);
281 
282                if (configuration.outbound_host) {
283                   free(configuration.outbound_host);
284                }
285                configuration.outbound_host=malloc(IPSTRING_SIZE);
286 
287                strcpy(configuration.outbound_host, ipstring);
288             }
289 
290 }
291 
292 /*&&&
293 if XOR address and normal address do not match I may have a
294 serious problem (IP provider not passing public IPs to clients).
295 Some linksys routers seem to alter the "normal" IP to be
296 the WAN IP, that may make such a situation visible.
297 
298 How can we deal with such a thing? We cannot change the NAT on
299 the provider side, can we? This will be WAY out os scope of siproxds
300 capabilities.
301 
302 I should issue an WARNING on such a detected situation.
303 */
304 
305 
306             rq_pending=0; /* received answer, good */
307             next_stun_send = now + plugin_cfg.period;
308 
309             DEBUGC(DBCLASS_BABBLE,"next STUN request in %i sec at %i",
310                    plugin_cfg.period, (int)next_stun_send);
311 
312             return STS_FAILURE; /* done, do not further process as SIP */
313          }
314          break;
315 
316       default:
317          break;
318    }
319 
320    return STS_SUCCESS;
321 }
322 
323 /*
324  * De-Initialization.
325  * Called during shutdown of siproxd. Gives the plugin the chance
326  * to clean up its mess (e.g. dynamic memory allocation, database
327  * connections, whatever the plugin messes around with)
328  */
PLUGIN_END(plugin_def_t * plugin_def)329 int  PLUGIN_END(plugin_def_t *plugin_def){
330    return STS_SUCCESS;
331 }
332 
333 
334 /*
335  * module-local functions
336  */
stun_validate_response(char * buffer,int len,char * tid)337 static int stun_validate_response(char *buffer, int len, char *tid){
338 
339    /* expect min. STUN header + 1 attribute */
340    if (len < 24) {
341       DEBUGC(DBCLASS_BABBLE,"stun_validate_response: no STUN response (too short)");
342       return STS_FAILURE;
343    }
344 
345    if (ntohs(*((int*)&buffer[0]) & 0x0000ffff) != 0x0101) {
346       DEBUGC(DBCLASS_BABBLE,"stun_validate_response: no STUN response (type)");
347       return STS_FAILURE;
348    }
349 
350    if (memcmp(&buffer[4], tid, STUN_TID_SIZE) != 0) {
351       DEBUGC(DBCLASS_BABBLE,"stun_validate_response: wrong STUN response (TID)");
352       return STS_FAILURE;
353    }
354 
355    DEBUGC(DBCLASS_BABBLE,"valid STUN response");
356    return STS_SUCCESS;
357 }
358 
stun_send_request(char * tid)359 static int stun_send_request(char *tid){
360    struct in_addr addr;
361    int sts;
362    char stun_rq[28];	/*&&& testing */
363    size_t size=28;
364 
365    /* name resolution */
366    if (utils_inet_aton(plugin_cfg.server, &addr) == 0)
367    {
368       /* need name resolution */
369       DEBUGC(DBCLASS_DNS,"resolving name:%s", plugin_cfg.server);
370       sts = get_ip_by_host(plugin_cfg.server, &addr);
371       if (sts == STS_FAILURE) {
372          DEBUGC(DBCLASS_DNS, "stun_send_request: cannot resolve STUN server [%s]",
373                 plugin_cfg.server);
374          return STS_FAILURE;
375       }
376    }
377 
378    /* compose STUN BIND request - poor mans way */
379    stun_rq[0]=0x00;	// type
380    stun_rq[1]=0x01;
381    stun_rq[2]=0x00;	// length
382    stun_rq[3]=0x08;
383    memcpy (&stun_rq[4], tid, STUN_TID_SIZE);
384    stun_rq[20]=0x00;	// ATTR change request
385    stun_rq[21]=0x03;
386    stun_rq[22]=0x00;	// ATTR len 4
387    stun_rq[23]=0x04;
388    stun_rq[24]=0x00;	// Change IP not set, Change port not set
389    stun_rq[25]=0x00;
390    stun_rq[26]=0x00;
391    stun_rq[27]=0x00;
392 
393    /* and send via the SIP UDP port */
394    sts = sipsock_send(addr, plugin_cfg.port, PROTO_UDP, stun_rq, size);
395 
396    return STS_SUCCESS;
397 }
398 
stun_new_transaction_id(char * tid)399 static int stun_new_transaction_id(char *tid) {
400    time_t now;
401    /* OSIP MD5 hash lenght is 16 bytes (32 hex digits),
402     * so this does fit for STUN transaction ID... */
403    osip_MD5_CTX Md5Ctx;
404    HASH HA1;
405 
406    time(&now);
407 
408    /* calc MD5 from servername + timestamp */
409    osip_MD5Init(&Md5Ctx);
410    if (plugin_cfg.server) osip_MD5Update(&Md5Ctx,
411                                          (unsigned char*)plugin_cfg.server,
412                                          strlen(plugin_cfg.server));
413    osip_MD5Update(&Md5Ctx, (unsigned char*)&now, sizeof(now));
414    osip_MD5Final(HA1, &Md5Ctx);
415 
416    memcpy(tid, HA1, (STUN_TID_SIZE<HASHLEN)? STUN_TID_SIZE:HASHLEN);
417 
418    return STS_SUCCESS;
419 }
420