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