9ff335bd0858004936abdab2090211c16d9ebc0f
[sip-router] / proxy.c
1 /*
2  * $Id$
3  *
4  * proxy list & assoc. functions
5  *
6  *
7  * Copyright (C) 2001-2003 FhG Fokus
8  *
9  * This file is part of ser, a free SIP server.
10  *
11  * ser is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version
15  *
16  * For a license to use the ser software under conditions
17  * other than those described here, or to purchase support for this
18  * software, please contact iptel.org by e-mail at the following addresses:
19  *    info@iptel.org
20  *
21  * ser is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  *
26  * You should have received a copy of the GNU General Public License 
27  * along with this program; if not, write to the Free Software 
28  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
29  */
30  /*
31   * History:
32   * -------
33   *  2003-02-13  all *proxy functions are now proto aware (andrei)
34   *  2003-03-19  replaced all mallocs/frees w/ pkg_malloc/pkg_free (andrei)
35   */
36
37
38
39 #include "config.h"
40 #include "proxy.h"
41 #include "error.h"
42 #include "dprint.h"
43 #include "mem/mem.h"
44 #include "mem/shm_mem.h"
45
46 #include <string.h>
47 #include <stdlib.h>
48 #include <sys/socket.h>
49
50 #ifdef DNS_IP_HACK
51 #include "ut.h"
52 #endif
53
54 #include "resolve.h"
55 #include "ip_addr.h"
56 #include "globals.h"
57
58
59 struct proxy_l* proxies=0;
60
61
62
63 /* searches for the proxy named 'name', on port 'port' with 
64    proto 'proto'; if proto==0 => proto wildcard (will match any proto)
65    returns: pointer to proxy_l on success or 0 if not found */ 
66 static struct proxy_l* find_proxy(str *name, unsigned short port, int proto)
67 {
68         struct proxy_l* t;
69         for(t=proxies; t; t=t->next)
70                 if (((t->name.len == name->len) &&
71                          ((proto==PROTO_NONE)||(t->proto==proto))&&
72                         (strncasecmp(t->name.s, name->s, name->len)==0)) &&
73                                 (t->port==port))
74                         break;
75         return t;
76 }
77
78
79 #define HOSTENT_CPY(dst, src, he_malloc, he_free)                                               \
80         do {                                                                                                                            \
81                 unsigned len,len2;                                                                                              \
82                 int r,i;                                                                                                                \
83                                                                                                                                                 \
84                 /* start copying the host entry.. */                                                    \
85                 /* copy h_name */                                                                                               \
86                 len=strlen(src->h_name)+1;                                                                              \
87                 dst->h_name=(char*)he_malloc(sizeof(char) * len);                               \
88                 if (dst->h_name) strncpy(dst->h_name,src->h_name, len);                 \
89                 else{                                                                                                                   \
90                         ser_error=ret=E_OUT_OF_MEM;                                                                     \
91                         goto error;                                                                                                     \
92                 }                                                                                                                               \
93                                                                                                                                                 \
94                 /* copy h_aliases */                                                                                    \
95                 len=0;                                                                                                                  \
96                 if (src->h_aliases)                                                                                             \
97                         for (;src->h_aliases[len];len++);                                                       \
98                 dst->h_aliases=(char**)he_malloc(sizeof(char*)*(len+1));                \
99                 if (dst->h_aliases==0){                                                                                 \
100                         ser_error=ret=E_OUT_OF_MEM;                                                                     \
101                         he_free(dst->h_name);                                                                           \
102                         goto error;                                                                                                     \
103                 }                                                                                                                               \
104                 memset((void*)dst->h_aliases, 0, sizeof(char*) * (len+1) );             \
105                 for (i=0;i<len;i++){                                                                                    \
106                         len2=strlen(src->h_aliases[i])+1;                                                       \
107                         dst->h_aliases[i]=(char*)he_malloc(sizeof(char)*len2);          \
108                         if (dst->h_aliases==0){                                                                         \
109                                 ser_error=ret=E_OUT_OF_MEM;                                                             \
110                                 he_free(dst->h_name);                                                                   \
111                                 for(r=0; r<i; r++)      he_free(dst->h_aliases[r]);                     \
112                                 he_free(dst->h_aliases);                                                                \
113                                 goto error;                                                                                             \
114                         }                                                                                                                       \
115                         strncpy(dst->h_aliases[i], src->h_aliases[i], len2);            \
116                 }                                                                                                                               \
117                 /* copy h_addr_list */                                                                                  \
118                 len=0;                                                                                                                  \
119                 if (src->h_addr_list)                                                                                   \
120                         for (;src->h_addr_list[len];len++);                                                     \
121                 dst->h_addr_list=(char**)he_malloc(sizeof(char*)*(len+1));              \
122                 if (dst->h_addr_list==0){                                                                               \
123                         ser_error=ret=E_OUT_OF_MEM;                                                                     \
124                         he_free(dst->h_name);                                                                           \
125                         for(r=0; dst->h_aliases[r]; r++)                                                        \
126                                 he_free(dst->h_aliases[r]);                                                             \
127                         he_free(dst->h_aliases[r]);                                                                     \
128                         he_free(dst->h_aliases);                                                                        \
129                         goto error;                                                                                                     \
130                 }                                                                                                                               \
131                 memset((void*)dst->h_addr_list, 0, sizeof(char*) * (len+1) );   \
132                 for (i=0;i<len;i++){                                                                                    \
133                         dst->h_addr_list[i]=                                                                            \
134                                 (char*)he_malloc(sizeof(char)*src->h_length);                   \
135                         if (dst->h_addr_list[i]==0){                                                            \
136                                 ser_error=ret=E_OUT_OF_MEM;                                                             \
137                                 he_free(dst->h_name);                                                                   \
138                                 for(r=0; dst->h_aliases[r]; r++)                                                \
139                                         he_free(dst->h_aliases[r]);                                                     \
140                                 he_free(dst->h_aliases[r]);                                                             \
141                                 he_free(dst->h_aliases);                                                                \
142                                 for (r=0; r<i;r++) he_free(dst->h_addr_list[r]);                \
143                                 he_free(dst->h_addr_list);                                                              \
144                                 goto error;                                                                                             \
145                         }                                                                                                                       \
146                         memcpy(dst->h_addr_list[i], src->h_addr_list[i],                        \
147                                    src->h_length);                                                                              \
148                 }                                                                                                                               \
149                                                                                                                                                 \
150                 /* copy h_addr_type & length */                                                                 \
151                 dst->h_addrtype=src->h_addrtype;                                                                \
152                 dst->h_length=src->h_length;                                                                    \
153                 /*finished hostent copy */                                                                              \
154                                                                                                                                                 \
155                 return 0;                                                                                                               \
156         } while(0)
157
158
159 #define FREE_HOSTENT(dst, he_free)                                              \
160         do {                                                                                            \
161                 int r;                                                                                  \
162                 if (dst->h_name) he_free(dst->h_name);                  \
163                 if (dst->h_aliases){                                                    \
164                         for(r=0; dst->h_aliases[r]; r++) {                      \
165                                 he_free(dst->h_aliases[r]);                             \
166                         }                                                                                       \
167                         he_free(dst->h_aliases);                                        \
168                 }                                                                                               \
169                 if (dst->h_addr_list){                                                  \
170                         for (r=0; dst->h_addr_list[r];r++) {            \
171                                 he_free(dst->h_addr_list[r]);                   \
172                         }                                                                                       \
173                         he_free(dst->h_addr_list);                                      \
174                 }                                                                                               \
175         } while(0)
176
177
178
179 /* copies a hostent structure*, returns 0 on success, <0 on error*/
180 static int hostent_cpy(struct hostent *dst, struct hostent* src)
181 {
182         int ret;
183         HOSTENT_CPY(dst, src, pkg_malloc, pkg_free);
184 error:
185         LOG(L_CRIT, "ERROR: hostent_cpy: memory allocation failure\n");
186         return ret;
187 }
188
189
190 static int hostent_shm_cpy(struct hostent *dst, struct hostent* src)
191 {
192         int ret;
193         HOSTENT_CPY(dst, src, shm_malloc, shm_free);
194 error:
195         LOG(L_CRIT, "ERROR: hostent_shm_cpy: memory allocation failure\n");
196         return ret;
197 }
198
199
200 void free_hostent(struct hostent* dst)
201 {
202         FREE_HOSTENT(dst, pkg_free);
203 }
204
205 void free_shm_hostent(struct hostent* dst)
206 {
207         FREE_HOSTENT(dst, shm_free);
208 }
209
210
211
212 struct proxy_l* add_proxy(str* name, unsigned short port, int proto)
213 {
214         struct proxy_l* p;
215         
216         if ((p=find_proxy(name, port, proto))!=0) return p;
217         if ((p=mk_proxy(name, port, proto))==0) goto error;
218         /* add p to the proxy list */
219         p->next=proxies;
220         proxies=p;
221         return p;
222
223 error:
224         return 0;
225 }
226
227
228 #define MK_PROXY(name, port, protocol, p_malloc, p_free, he_cpy)                \
229         do {                                                                                                                            \
230                 struct proxy_l* p;                                                                                              \
231                 struct hostent* he;                                                                                             \
232                 char proto;                                                                                                             \
233                                                                                                                                                 \
234                 p=(struct proxy_l*) p_malloc(sizeof(struct proxy_l));                   \
235                 if (p==0){                                                                                                              \
236                         ser_error=E_OUT_OF_MEM;                                                                         \
237                         ERR("ERROR: mk_proxy: memory allocation failure\n");            \
238                         goto error;                                                                                                     \
239                 }                                                                                                                               \
240                 memset(p,0,sizeof(struct proxy_l));                                                             \
241                 p->name=*name;                                                                                                  \
242                 p->port=port;                                                                                                   \
243                                                                                                                                                 \
244                 DBG("DEBUG: mk_proxy: doing DNS lookup...\n");                                  \
245                 proto=protocol;                                                                                                 \
246                 he=sip_resolvehost(name, &(p->port), &proto);                                   \
247                 if (he==0){                                                                                                             \
248                         ser_error=E_BAD_ADDRESS;                                                                        \
249                         LOG(L_CRIT, "ERROR: mk_proxy: could not resolve hostname:"      \
250                                 " \"%.*s\"\n", name->len, name->s);                                             \
251                         p_free(p);                                                                                                      \
252                         goto error;                                                                                                     \
253                 }                                                                                                                               \
254                 if (he_cpy(&(p->host), he)!=0){                                                                 \
255                         p_free(p);                                                                                                      \
256                         goto error;                                                                                                     \
257                 }                                                                                                                               \
258                 p->proto=proto;                                                                                                 \
259                 p->ok=1;                                                                                                                \
260                 return p;                                                                                                               \
261         error:                                                                                                                          \
262                 return 0;                                                                                                               \
263                                                                                                                                                 \
264         } while(0)
265
266 /* same as add_proxy, but it doesn't add the proxy to the list
267  * uses also SRV if possible & port==0 (quick hack) */
268
269 struct proxy_l* mk_proxy(str* name, unsigned short port, int protocol)
270 {
271         MK_PROXY(name, port, protocol, pkg_malloc, pkg_free, hostent_cpy);
272 }
273
274
275 struct proxy_l* mk_shm_proxy(str* name, unsigned short port, int protocol)
276 {
277         MK_PROXY(name, port, protocol, shm_malloc, shm_free, hostent_shm_cpy);
278 }
279
280
281
282 /* same as mk_proxy, but get the host as an ip*/
283 struct proxy_l* mk_proxy_from_ip(struct ip_addr* ip, unsigned short port,
284                                                                         int proto)
285 {
286         struct proxy_l* p;
287
288         p=(struct proxy_l*) pkg_malloc(sizeof(struct proxy_l));
289         if (p==0){
290                 LOG(L_CRIT, "ERROR: mk_proxy_from_ip: memory allocation failure\n");
291                 goto error;
292         }
293         memset(p,0,sizeof(struct proxy_l));
294
295         p->port=port;
296         p->proto=proto;
297         p->host.h_addrtype=ip->af;
298         p->host.h_length=ip->len;
299         p->host.h_addr_list=pkg_malloc(2*sizeof(char*));
300         if (p->host.h_addr_list==0) goto error;
301         p->host.h_addr_list[1]=0;
302         p->host.h_addr_list[0]=pkg_malloc(ip->len+1);
303         if (p->host.h_addr_list[0]==0){
304                 pkg_free(p->host.h_addr_list);
305                 goto error;
306         }
307
308         memcpy(p->host.h_addr_list[0], ip->u.addr, ip->len);
309         p->host.h_addr_list[0][ip->len]=0;
310
311         return p;
312
313 error:
314         return 0;
315 }
316
317
318
319
320 void free_proxy(struct proxy_l* p)
321 {
322         if (p) free_hostent(&p->host);
323 }
324
325
326 void free_shm_proxy(struct proxy_l* p)
327 {
328         if (p) free_shm_hostent(&p->host);
329 }