Browse code

- added SRV capable resolver (see get_record) - minimal (read quick hack) SRV support

Andrei Pelinescu-Onciul authored on 12/08/2002 16:33:43
Showing 10 changed files
... ...
@@ -8,7 +8,7 @@
8 8
 VERSION = 0
9 9
 PATCHLEVEL = 8
10 10
 SUBLEVEL = 7
11
-EXTRAVERSION = -6-ipv6
11
+EXTRAVERSION = -7-srv
12 12
 
13 13
 RELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
14 14
 OS = $(shell uname -s)
... ...
@@ -373,7 +373,7 @@ YACC=bison
373 373
 YACC_FLAGS=-d -b cfg
374 374
 # on linux and freebsd keep it empty (e.g. LIBS= )
375 375
 # on solaris add -lxnet (e.g. LIBS= -lxnet)
376
-LIBS=-lfl -ldl
376
+LIBS=-lfl -ldl -lresolv
377 377
 
378 378
 
379 379
 #os specific stuff
... ...
@@ -91,7 +91,7 @@ int do_action(struct action* a, struct sip_msg* msg)
91 91
 											ret=E_BAD_URI;
92 92
 											goto error_fwd_uri;
93 93
 										}
94
-									}else port=SIP_PORT;
94
+									}else port=0;
95 95
 									break;
96 96
 					case NUMBER_ST:
97 97
 									port=a->p2.number;
... ...
@@ -54,9 +54,12 @@
54 54
 #define CRLF "\r\n"
55 55
 #define CRLF_LEN 2
56 56
 
57
-#define RECEIVED ";received="
57
+#define RECEIVED   ";received="
58 58
 #define RECEIVED_LEN 10
59 59
 
60
+#define SRV_PREFIX "_sip._udp."
61
+#define SRV_PREFIX_LEN 10
62
+
60 63
 /*used only if PKG_MALLOC is defined*/
61 64
 #define PKG_MEM_POOL_SIZE 1024*1024
62 65
 
... ...
@@ -161,7 +161,8 @@ int update_sock_struct_from_via( union sockaddr_union* to,
161 161
 		if (via->host.s[via->host.len]){
162 162
 			host_copy=pkg_malloc( via->host.len+1 );
163 163
 			if (!host_copy) {
164
-				LOG(L_NOTICE, "ERROR: update_sock_struct_from_via: not enough memory\n");
164
+				LOG(L_NOTICE, "ERROR: update_sock_struct_from_via:"
165
+								" not enough memory\n");
165 166
 				return -1;
166 167
 			}
167 168
 			memcpy(host_copy, via->host.s, via->host.len );
... ...
@@ -6,6 +6,7 @@
6 6
  */
7 7
 
8 8
 
9
+#include "config.h"
9 10
 #include "proxy.h"
10 11
 #include "error.h"
11 12
 #include "dprint.h"
... ...
@@ -158,15 +159,21 @@ error:
158 159
 
159 160
 
160 161
 
161
-/* same as add_proxy, but it doesn't add the proxy to the list*/
162
+/* same as add_proxy, but it doesn't add the proxy to the list
163
+ * uses also SRV if possible (quick hack) */
164
+
162 165
 struct proxy_l* mk_proxy(char* name, unsigned short port)
163 166
 {
164 167
 	struct proxy_l* p;
165 168
 	struct hostent* he;
169
+	struct rdata* head;
170
+	struct rdata* l;
171
+	struct srv_rdata* srv;
172
+	static char tmp[MAX_DNS_NAME]; /* tmp buff. for SRV lookups*/
173
+	int len;
166 174
 #ifdef DNS_IP_HACK
167 175
 	int err;
168 176
 	unsigned int ip;
169
-	int len;
170 177
 #endif
171 178
 
172 179
 	p=(struct proxy_l*) malloc(sizeof(struct proxy_l));
... ...
@@ -177,7 +184,7 @@ struct proxy_l* mk_proxy(char* name, unsigned short port)
177 184
 	}
178 185
 	memset(p,0,sizeof(struct proxy_l));
179 186
 	p->name=name;
180
-	p->port=port;
187
+	p->port=port?port:SIP_PORT;
181 188
 #ifdef DNS_IP_HACK
182 189
 	/* fast ipv4 string to address conversion*/
183 190
 	len=strlen(name);
... ...
@@ -219,6 +226,37 @@ struct proxy_l* mk_proxy(char* name, unsigned short port)
219 226
 #endif
220 227
 	/* fail over to normal lookup */
221 228
 
229
+	/* try SRV if no port specified (draft-ietf-sip-srv-06) */
230
+	if (port==0){
231
+		len=strlen(name);
232
+		if ((len+SRV_PREFIX_LEN+1)>MAX_DNS_NAME){
233
+			LOG(L_WARN, "WARNING: domain name too long (%d), unable"
234
+					" to perform SRV lookup\n", len);
235
+		}else{
236
+			memcpy(tmp, SRV_PREFIX, SRV_PREFIX_LEN);
237
+			memcpy(tmp+SRV_PREFIX_LEN, name, len+1); /*include the ending 0*/
238
+			
239
+			head=get_record(tmp, T_SRV);
240
+			for(l=head; l; l=l->next){
241
+				if (l->type!=T_SRV) continue; /*should never happen*/
242
+				srv=(struct srv_rdata*) l->rdata;
243
+				if (srv==0){
244
+					LOG(L_CRIT, "mk_proxy: BUG: null rdata\n");
245
+					free_rdata_list(head);
246
+					break;
247
+				}
248
+				he=resolvehost(srv->name);
249
+				if (he!=0){
250
+					DBG("mk_proxy: SRV(%s) = %s:%d\n",
251
+							tmp, srv->name, srv->port);
252
+					p->port=srv->port;
253
+					free_rdata_list(head); /*clean up*/
254
+					goto copy_he;
255
+				}
256
+			}
257
+			DBG(" not SRV record found for %s\n", name);
258
+		}
259
+	}
222 260
 	he=resolvehost(name);
223 261
 	if (he==0){
224 262
 		ser_error=E_BAD_ADDRESS;
... ...
@@ -227,6 +265,7 @@ struct proxy_l* mk_proxy(char* name, unsigned short port)
227 265
 		free(p);
228 266
 		goto error;
229 267
 	}
268
+copy_he:
230 269
 	if (hostent_cpy(&(p->host), he)!=0){
231 270
 		free(p);
232 271
 		goto error;
233 272
new file mode 100644
... ...
@@ -0,0 +1,306 @@
1
+/* $Id$*/
2
+
3
+/* #include <arpa/nameser.h> -- included from resolve.h*/
4
+#include <netinet/in.h>
5
+#include <resolv.h>
6
+#include <string.h>
7
+
8
+#include "resolve.h"
9
+#include "dprint.h"
10
+#include "mem/mem.h"
11
+
12
+
13
+
14
+/* mallocs for local stuff */
15
+#define local_malloc pkg_malloc
16
+#define local_free   pkg_free
17
+
18
+
19
+
20
+ /*  skips over a domain name in a dns message
21
+ *  (it can be  a sequence of labels ending in \0, a pointer or
22
+ *   a sequence of labels ending in a pointer -- see rfc1035
23
+ *   returns pointer after the domain name or null on error*/
24
+unsigned char* dns_skipname(unsigned char* p, unsigned char* end)
25
+{
26
+	while(p<end){
27
+		/* check if \0 (root label length) */
28
+		if (*p==0){
29
+			p+=1;
30
+			break;
31
+		}
32
+		/* check if we found a pointer */
33
+		if (((*p)&0xc0)==0xc0){
34
+			/* if pointer skip over it (2 bytes) & we found the end */
35
+			p+=2;
36
+			break;
37
+		}
38
+		/* normal label */
39
+		p+=*p+1;
40
+	}
41
+	return (p>end)?0:p;
42
+}
43
+
44
+
45
+
46
+/* parses the srv record into a srv_rdata structure
47
+ *   msg   - pointer to the dns message
48
+ *   end   - pointer to the end of the message
49
+ *   rdata - pointer  to the rdata part of the srv answer
50
+ * returns 0 on error, or a dyn. alloc'ed srv_rdata structure */
51
+/* SRV rdata format:
52
+ *            111111
53
+ *  0123456789012345
54
+ * +----------------+
55
+ * |     priority   |
56
+ * |----------------|
57
+ * |     weight     |
58
+ * |----------------|
59
+ * |   port number  |
60
+ * |----------------|
61
+ * |                |
62
+ * ~      name      ~
63
+ * |                |
64
+ * +----------------+
65
+ */
66
+struct srv_rdata* dns_srv_parser( unsigned char* msg, unsigned char* end,
67
+								  unsigned char* rdata)
68
+{
69
+	struct srv_rdata* srv;
70
+	int len;
71
+	
72
+	srv=0;
73
+	if ((rdata+6)>end) goto error;
74
+	srv=(struct srv_rdata*)local_malloc(sizeof(struct srv_rdata));
75
+	if (srv==0){
76
+		LOG(L_ERR, "ERROR: dns_srv_parser: outof memory\n");
77
+		goto error;
78
+	}
79
+	
80
+	memcpy((void*)&srv->priority, rdata, 2);
81
+	memcpy((void*)&srv->weight,   rdata+2, 2);
82
+	memcpy((void*)&srv->port,     rdata+4, 2);
83
+	rdata+=6;
84
+	srv->priority=ntohs(srv->priority);
85
+	srv->weight=ntohs(srv->weight);
86
+	srv->port=ntohs(srv->port);
87
+	if ((len=dn_expand(msg, end, rdata, srv->name, MAX_DNS_NAME))==-1)
88
+		goto error;
89
+	/* add terminatng 0 ? */
90
+	return srv;
91
+error:
92
+	if (srv) local_free(srv);
93
+	return 0;
94
+}
95
+
96
+
97
+
98
+/* parses an A record rdata into an a_rdata structure
99
+ * returns 0 on error or a dyn. alloc'ed a_rdata struct
100
+ */
101
+struct a_rdata* dns_a_parser(unsigned char* rdata, unsigned char* end)
102
+{
103
+	struct a_rdata* a;
104
+	
105
+	if (rdata+4>end) goto error;
106
+	a=(struct a_rdata*)local_malloc(sizeof(struct a_rdata));
107
+	if (a==0){
108
+		LOG(L_ERR, "ERROR: dns_a_parser: out of memory\n");
109
+		goto error;
110
+	}
111
+	memcpy(a->ip, rdata, 4);
112
+	return a;
113
+error:
114
+	return 0;
115
+}
116
+
117
+
118
+
119
+/* parses an AAAA (ipv6) record rdata into an aaaa_rdata structure
120
+ * returns 0 on error or a dyn. alloc'ed aaaa_rdata struct */
121
+struct aaaa_rdata* dns_aaaa_parser(unsigned char* rdata, unsigned char* end)
122
+{
123
+	struct aaaa_rdata* aaaa;
124
+	
125
+	if (rdata+16>end) goto error;
126
+	aaaa=(struct aaaa_rdata*)local_malloc(sizeof(struct aaaa_rdata));
127
+	if (aaaa==0){
128
+		LOG(L_ERR, "ERROR: dns_aaaa_parser: out of memory\n");
129
+		goto error;
130
+	}
131
+	memcpy(aaaa->ip6, rdata, 16);
132
+	return aaaa;
133
+error:
134
+	return 0;
135
+}
136
+
137
+
138
+
139
+/* frees completely a struct rdata list */
140
+void free_rdata_list(struct rdata* head)
141
+{
142
+	struct rdata* l;
143
+	for(l=head; l; l=l->next){
144
+		/* free the parsed rdata*/
145
+		if (l->rdata) local_free(l->rdata);
146
+		local_free(l);
147
+	}
148
+}
149
+
150
+
151
+
152
+/* gets the DNS records for name:type
153
+ * returns a dyn. alloc'ed struct rdata linked list with the parsed responses
154
+ * or 0 on error
155
+ * see rfc1035 for the query/response format */
156
+struct rdata* get_record(char* name, int type)
157
+{
158
+	int size;
159
+	int qno, answers_no;
160
+	int r,i;
161
+	int ans_len;
162
+	static union dns_query buff;
163
+	unsigned char* p;
164
+	unsigned char* t;
165
+	unsigned char* end;
166
+	static unsigned char answer[ANS_SIZE];
167
+	unsigned short rtype, class, rdlength;
168
+	unsigned int ttl;
169
+	struct rdata* head;
170
+	struct rdata** crt;
171
+	struct rdata* rd;
172
+	struct srv_rdata* srv_rd;
173
+	struct srv_rdata* crt_srv;
174
+	
175
+	
176
+	
177
+	head=rd=0;
178
+	crt=&head;
179
+	size=res_search(name, C_IN, type, buff.buff, sizeof(buff));
180
+	if (size<0) goto error;
181
+	else if (size > sizeof(buff)) size=sizeof(buff);
182
+	
183
+	p=buff.buff+DNS_HDR_SIZE;
184
+	end=buff.buff+size;
185
+	if (p>end) goto error_boundary;
186
+	qno=ntohs((unsigned short)buff.hdr.qdcount);
187
+
188
+	for (r=0; r<qno; r++){
189
+		/* skip the name of the question */
190
+		if ((p=dns_skipname(p, end))==0) goto error;
191
+		p+=2+2; /* skip QCODE & QCLASS */
192
+	#if 0
193
+		for (;(p<end && (*p)); p++);
194
+		p+=1+2+2; /* skip the ending  '\0, QCODE and QCLASS */
195
+	#endif
196
+		if (p>end) goto error;
197
+	};
198
+	answers_no=ntohs((unsigned short)buff.hdr.ancount);
199
+	ans_len=ANS_SIZE;
200
+	t=answer;
201
+	for (r=0; (r<answers_no) && (p<end); r++){
202
+		/*  ignore it the default domain name */
203
+		if ((p=dns_skipname(p, end))==0) goto error;
204
+		/*
205
+		skip=dn_expand(buff.buff, end, p, t, ans_len);
206
+		p+=skip;
207
+		*/
208
+		/* check if enough space is left fot type, class, ttl & size */
209
+		if ((p+2+2+4+2)>end) goto error_boundary;
210
+		/* get type */
211
+		memcpy((void*) &rtype, (void*)p, 2);
212
+		rtype=ntohs(rtype);
213
+		p+=2;
214
+		/* get  class */
215
+		memcpy((void*) &class, (void*)p, 2);
216
+		class=ntohs(class);
217
+		p+=2;
218
+		/* get ttl*/
219
+		memcpy((void*) &ttl, (void*)p, 4);
220
+		ttl=ntohl(ttl);
221
+		p+=4;
222
+		/* get size */
223
+		memcpy((void*)&rdlength, (void*)p, 2);
224
+		rdlength=ntohs(rdlength);
225
+		p+=2;
226
+		/* check for type */
227
+		if (rtype!=type){
228
+			LOG(L_WARN, "WARNING: get_record: wrong type in answer\n");
229
+			p+=rdlength;
230
+			continue;
231
+		}
232
+		/* expand the "type" record  (rdata)*/
233
+		/* print it */
234
+		/*
235
+		printf("\ntype=%d class= %d, ttl= %d, rdlength= %d\n",
236
+				rtype, class, ttl, rdlength);
237
+		for (i=0;i<rdlength;i++){
238
+			printf("%x ", *(p+i));
239
+		}
240
+		printf("\n");
241
+		*/
242
+		rd=(struct rdata*) local_malloc(sizeof(struct rdata));
243
+		if (rd==0){
244
+			LOG(L_ERR, "ERROR: get_record: out of memory\n");
245
+			goto error;
246
+		}
247
+		rd->type=rtype;
248
+		rd->class=class;
249
+		rd->ttl=ttl;
250
+		switch(type){
251
+			case T_SRV:
252
+				srv_rd= dns_srv_parser(buff.buff, end, p);
253
+				rd->rdata=(void*)srv_rd;
254
+				if (srv_rd==0) goto error_parse;
255
+				
256
+				/* insert sorted into the list
257
+				 * crt reused */
258
+				for (crt=&head; *crt; crt= &((*crt)->next)){
259
+					crt_srv=(struct srv_rdata*)(*crt)->rdata;
260
+					if ((srv_rd->priority <  crt_srv->priority) ||
261
+					   ( (srv_rd->priority == crt_srv->priority) && 
262
+							 (srv_rd->weight > crt_srv->weight) ) ){
263
+						/* insert here */
264
+						break;
265
+					}
266
+				}
267
+				/* insert here */
268
+				rd->next=*crt;
269
+				*crt=rd;
270
+				
271
+				break;
272
+			case T_A:
273
+				rd->rdata=(void*) dns_a_parser(p,end);
274
+				if (rd->rdata==0) goto error_parse;
275
+				*crt=rd; /* crt points to the last "next" or the list head*/
276
+				crt=&(rd->next);
277
+				break;
278
+			case T_AAAA:
279
+				rd->rdata=(void*) dns_aaaa_parser(p,end);
280
+				if (rd->rdata==0) goto error_parse;
281
+				*crt=rd;
282
+				crt=&(rd->next);
283
+				break;
284
+			default:
285
+				LOG(L_ERR, "BUG: get_record: unknown type %d\n", type);
286
+				rd->rdata=0;
287
+				goto error;
288
+		}
289
+		
290
+		p+=rdlength;
291
+		
292
+	}
293
+	return head;
294
+error_boundary:
295
+		LOG(L_ERR, "ERROR: get_record: end of query buff reached\n");
296
+		return 0;
297
+error_parse:
298
+		LOG(L_ERR, "ERROR: get_record: rdata parse error \n");
299
+		if (rd) local_free(rd); /* rd->rdata=0 & rd is not linked yet into
300
+								   the list */
301
+error:
302
+		LOG(L_ERR, "ERROR: get_record \n");
303
+		if (head) free_rdata_list(head);
304
+	return 0;
305
+}
306
+
... ...
@@ -9,14 +9,60 @@
9 9
 #define resolve_h
10 10
 
11 11
 #include <netdb.h>
12
+#include <arpa/nameser.h>
12 13
 
13
-#include "ip_addr.h"
14 14
 
15
+#define MAX_QUERY_SIZE 8192
16
+#define ANS_SIZE       8192
17
+#define DNS_HDR_SIZE     12
18
+#define MAX_DNS_NAME 256
15 19
 
16
-/* gethostbyname wrappers
17
- * use this, someday htey will use a local cache */
18 20
 
19 21
 
22
+/* query union*/
23
+union dns_query{
24
+	HEADER hdr;
25
+	unsigned char buff[MAX_QUERY_SIZE];
26
+};
27
+
28
+
29
+/* rdata struct*/
30
+struct rdata {
31
+	unsigned short type;
32
+	unsigned short class;
33
+	unsigned int   ttl;
34
+	void* rdata;
35
+	struct rdata* next;
36
+};
37
+
38
+
39
+/* srv rec. struct*/
40
+struct srv_rdata {
41
+	unsigned short priority;
42
+	unsigned short weight;
43
+	unsigned short port;
44
+	unsigned int name_len;
45
+	char name[MAX_DNS_NAME];
46
+};
47
+
48
+
49
+/* A rec. struct */
50
+struct a_rdata {
51
+	unsigned char ip[4];
52
+};
53
+
54
+struct aaaa_rdata {
55
+	unsigned char ip6[16];
56
+};
57
+
58
+
59
+
60
+struct rdata* get_record(char* name, int type);
61
+void free_rdata_list(struct rdata* head);
62
+
63
+
64
+/* gethostbyname wrappers
65
+ * use this, someday htey will use a local cache */
20 66
 
21 67
 static inline struct hostent* resolvehost(const char* name)
22 68
 {
23 69
new file mode 100644
... ...
@@ -0,0 +1,150 @@
1
+/*
2
+ * $Id$
3
+ *
4
+ * tests for ../resolver.c
5
+ */
6
+
7
+#include <stdio.h>
8
+#include <stdlib.h>
9
+#include <errno.h>
10
+#include <string.h>
11
+#include <unistd.h>
12
+
13
+#include "../resolve.h"
14
+
15
+/* symbols needed by dprint */
16
+int log_stderr=1;
17
+int debug=0;
18
+int pids[1];
19
+int process_no=0;
20
+
21
+
22
+static char* id="$Id$";
23
+static char* version="dns_query 0.1";
24
+static char* help_msg="\
25
+Usage: dns_query  [-t type] [-hV] -n host\n\
26
+Options:\n\
27
+    -n host       host name\n\
28
+    -t type       query type (default A)\n\
29
+    -V            version number\n\
30
+    -h            this help message\n\
31
+";
32
+
33
+
34
+int main(int argc, char** argv)
35
+{
36
+	char c;
37
+	char* name;
38
+	char* type_str;
39
+	int type;
40
+	int r;
41
+	struct rdata* head;
42
+	struct rdata* l;
43
+	struct srv_rdata* srv;
44
+	struct a_rdata* ip;
45
+
46
+	name=type_str=0;
47
+	
48
+	opterr=0;
49
+	while ((c=getopt(argc, argv, "n:t:hV"))!=-1){
50
+		switch(c){
51
+			case 'n':
52
+				name=optarg;
53
+				break;
54
+			case 't':
55
+				type_str=optarg;
56
+				break;
57
+			case 'V':
58
+				printf("version: %s\n", version);
59
+				printf("%s\n", id);
60
+				exit(0);
61
+				break;
62
+			case 'h':
63
+				printf("version: %s\n", version);
64
+				printf("%s", help_msg);
65
+				exit(0);
66
+				break;
67
+			case '?':
68
+				if (isprint(optopt))
69
+					fprintf(stderr, "Unknown option `-%c�\n", optopt);
70
+				else
71
+					fprintf(stderr, "Unknown character `\\x%x�\n", optopt);
72
+				goto error;
73
+			case ':':
74
+				fprintf(stderr, "Option `-%c� requires an argument.\n",
75
+						optopt);
76
+				goto error;
77
+				break;
78
+			default:
79
+				abort();
80
+		}
81
+	}
82
+	
83
+	if (name==0){
84
+		fprintf(stderr, "Missing domain name (-n name)\n");
85
+		goto error;
86
+	}
87
+	type=T_A;
88
+	if (type_str){
89
+		if (strcasecmp(type_str, "A")==0) type=T_A;
90
+		else if (strcasecmp(type_str, "NS")==0) type=T_NS;
91
+		else if (strcasecmp(type_str, "MD")==0) type=T_MD;
92
+		else if (strcasecmp(type_str, "MF")==0) type=T_MF;
93
+		else if (strcasecmp(type_str, "CNAME")==0) type=T_CNAME;
94
+		else if (strcasecmp(type_str, "SOA")==0) type=T_SOA;
95
+		else if (strcasecmp(type_str, "PTR")==0) type=T_PTR;
96
+		else if (strcasecmp(type_str, "HINFO")==0) type=T_HINFO;
97
+		else if (strcasecmp(type_str, "MINFO")==0) type=T_MINFO;
98
+		else if (strcasecmp(type_str, "MX")==0) type=T_MX;
99
+		else if (strcasecmp(type_str, "TXT")==0) type=T_TXT;
100
+		else if (strcasecmp(type_str, "AAAA")==0) type=T_AAAA;
101
+		else if (strcasecmp(type_str, "SRV")==0) type=T_SRV;
102
+		else if (strcasecmp(type_str, "NAPTR")==0) type=T_NAPTR;
103
+		else if (strcasecmp(type_str, "AXFR")==0) type=T_AXFR;
104
+		else{
105
+			fprintf(stderr, "Unknown query type %s\n", type_str);
106
+			goto error;
107
+		}
108
+	}
109
+	printf("calling get_record...\n");
110
+	head=get_record(name, type);
111
+	if (head==0) printf("no answer\n");
112
+	else{
113
+		printf("records:\n");
114
+		for(l=head; l; l=l->next){
115
+			switch(l->type){
116
+				case T_SRV:
117
+					srv=(struct srv_rdata*)l->rdata;
118
+					printf("SRV  type= %d class=%d  ttl=%d\n",
119
+							l->type, l->class, l->ttl);
120
+					printf("     prio= %d weight=%d port=%d\n",
121
+								srv->priority, srv->weight, srv->port);
122
+					printf("     name= [%s]\n", srv->name);
123
+					break;
124
+				case T_A:
125
+					ip=(struct a_rdata*)l->rdata;
126
+					printf("A    type= %d class=%d  ttl=%d\n",
127
+								l->type, l->class, l->ttl);
128
+					printf("     ip= %d.%d.%d.%d\n",
129
+								ip->ip[0], ip->ip[1], ip->ip[2], ip->ip[3]);
130
+					break;
131
+				case T_AAAA:
132
+					printf("AAAA  type= %d class=%d  ttl=%d\n",
133
+							l->type, l->class, l->ttl);
134
+					printf("      ip6= ");
135
+					for(r=0;r<16;r++) 
136
+						printf("%x ", ((struct aaaa_rdata*)l->rdata)->ip6[r]);
137
+					printf("\n");
138
+					break;
139
+				default:
140
+					printf("UNKN  type= %d class=%d  ttl=%d\n",
141
+								l->type, l->class, l->ttl);
142
+					printf("       rdata=%p\n", l->rdata);
143
+			}
144
+		}
145
+	}
146
+	printf("done\n");
147
+	exit(0);
148
+error:
149
+	exit(-1);
150
+}
0 151
new file mode 100644
... ...
@@ -0,0 +1,23 @@
1
+INVITE sip:andrei@iptel.org SIP/2.0
2
+Via: SIP/2.0/UDP dorian.fokus.gmd.de 
3
+From: "GMD FOKUS iptlab" <sip:jiri@iptel.org>;tag=b96b0300ed30f1286-2f5d
4
+Call-ID: b96b0300-88d30f-66da-63aa@195.37.78.190
5
+CSeq: 101 INVITE
6
+Expires: 180
7
+Max-Forwards:  0
8
+User-Agent: Cisco-SIP-IP-Phone/2
9
+Accept: application/sdp
10
+Contact: sip:jiri@195.37.78.190:5060
11
+Content-Type: application/sdp
12
+Content-Length: 225
13
+
14
+
15
+v=0
16
+o=CiscoSystemsSIP-IPPhone-UserAgent 14474 8233 IN IP4 195.37.78.190
17
+s=SIP Call
18
+c=IN IP4 195.37.78.190
19
+t=0 0
20
+m=audio 18456 RTP/AVP 0 8 18 101
21
+a=rtpmap:0 pcmu/8000
22
+a=rtpmap:101 telephone-event/8000
23
+a=fmtp:101 0-11 
... ...
@@ -8,7 +8,7 @@
8 8
 debug=9          # debug level (cmd line: -dddddddddd)
9 9
 #fork=yes          # (cmd. line: -D)
10 10
 fork=yes
11
-#fork=no
11
+fork=no
12 12
 log_stderror=yes # (cmd line: -E)
13 13
 #log_stderror=no	# (cmd line: -E)
14 14
 
... ...
@@ -26,7 +26,6 @@ loop_checks=0
26 26
 # for more info: sip_router -h
27 27
 
28 28
 #modules
29
-loadmodule "modules/tm/tm.so"
30 29
 
31 30
 
32 31
 route{