... | ... |
@@ -2,6 +2,8 @@ |
2 | 2 |
# |
3 | 3 |
# sip_router makefile |
4 | 4 |
# |
5 |
+# WARNING: requires gmake (GNU Make) |
|
6 |
+# |
|
5 | 7 |
|
6 | 8 |
sources= $(wildcard *.c) |
7 | 9 |
objs= $(sources:.c=.o) |
... | ... |
@@ -10,7 +12,10 @@ depends= $(sources:.c=.d) |
10 | 12 |
NAME=sip_router |
11 | 13 |
|
12 | 14 |
CC=gcc |
13 |
-COPTS=-O2 |
|
15 |
+CFLAGS=-O2 |
|
16 |
+# on linux and freebsd keep it empty (e.g. LIBS= ) |
|
17 |
+# on solaris add -lxnet (e.g. LIBS= -lxnet) |
|
18 |
+LIBS= |
|
14 | 19 |
ALLDEP=Makefile |
15 | 20 |
|
16 | 21 |
MKDEP=gcc -M |
... | ... |
@@ -19,13 +24,13 @@ MKDEP=gcc -M |
19 | 24 |
#implicit rules |
20 | 25 |
|
21 | 26 |
%.o:%.c $(ALLDEP) |
22 |
- $(CC) $(COPTS) -c $< -o $@ |
|
27 |
+ $(CC) $(CFLAGS) -c $< -o $@ |
|
23 | 28 |
|
24 | 29 |
%.d: %.c |
25 | 30 |
$(MKDEP) $< >$@ |
26 | 31 |
|
27 | 32 |
$(NAME): $(objs) |
28 |
- $(CC) $(COPTS) $(objs) -o $(NAME) |
|
33 |
+ $(CC) $(CFLAGS) $(LIBS) $(objs) -o $(NAME) |
|
29 | 34 |
|
30 | 35 |
.PHONY: all |
31 | 36 |
all: $(NAME) |
... | ... |
@@ -8,6 +8,7 @@ |
8 | 8 |
#include <sys/socket.h> |
9 | 9 |
#include <netdb.h> |
10 | 10 |
#include <netinet/in.h> |
11 |
+#include <arpa/inet.h> |
|
11 | 12 |
|
12 | 13 |
#include "forward.h" |
13 | 14 |
#include "config.h" |
... | ... |
@@ -15,16 +16,53 @@ |
15 | 16 |
#include "route.h" |
16 | 17 |
#include "dprint.h" |
17 | 18 |
#include "udp_server.h" |
19 |
+#include "globals.h" |
|
18 | 20 |
|
19 | 21 |
#define MAX_VIA_LINE_SIZE 240 |
20 | 22 |
#define MAX_RECEIVED_SIZE 57 |
21 | 23 |
|
22 | 24 |
|
23 | 25 |
|
26 |
+/* checks if ip is in host(name) and ?host(ip)=name? |
|
27 |
+ * ip must be in network byte order! |
|
28 |
+ * resolver = DO_DNS | DO_REV_DNS; if 0 no dns check is made |
|
29 |
+ * return 0 if equal */ |
|
30 |
+int check_address(unsigned long ip, char *name, int resolver) |
|
31 |
+{ |
|
32 |
+ struct hostent* he; |
|
33 |
+ int i; |
|
34 |
+ |
|
35 |
+ /* maybe we are lucky and name it's an ip */ |
|
36 |
+ if (strcmp(name, inet_ntoa( *(struct in_addr *)&ip ))==0) |
|
37 |
+ return 0; |
|
38 |
+ if (resolver&DO_DNS){ |
|
39 |
+ /* try all names ips */ |
|
40 |
+ he=gethostbyname(name); |
|
41 |
+ for(i=0; he->h_addr_list[i];i++){ |
|
42 |
+ if (*(unsigned long*)he->h_addr_list[i]==ip) |
|
43 |
+ return 0; |
|
44 |
+ } |
|
45 |
+ } |
|
46 |
+ if (resolver&DO_REV_DNS){ |
|
47 |
+ /* try reverse dns */ |
|
48 |
+ he=gethostbyaddr(&ip, sizeof(ip), AF_INET); |
|
49 |
+ if (strcmp(he->h_name, name)==0) |
|
50 |
+ return 0; |
|
51 |
+ for (i=0; he->h_aliases[i];i++){ |
|
52 |
+ if (strcmp(he->h_aliases[i],name)==0) |
|
53 |
+ return 0; |
|
54 |
+ } |
|
55 |
+ } |
|
56 |
+ return -1; |
|
57 |
+} |
|
58 |
+ |
|
59 |
+ |
|
60 |
+ |
|
24 | 61 |
int forward_request(char * orig, char* buf, |
25 | 62 |
unsigned int len, |
26 | 63 |
struct sip_msg* msg, |
27 |
- struct route_elem* re) |
|
64 |
+ struct route_elem* re, |
|
65 |
+ unsigned long source_ip) |
|
28 | 66 |
{ |
29 | 67 |
unsigned int new_len, via_len, received_len; |
30 | 68 |
char line_buf[MAX_VIA_LINE_SIZE]; |
... | ... |
@@ -36,11 +74,13 @@ int forward_request(char * orig, char* buf, |
36 | 74 |
received_len=0; |
37 | 75 |
|
38 | 76 |
via_len=snprintf(line_buf, MAX_VIA_LINE_SIZE, "Via: SIP/2.0/UDP %s:%d\r\n", |
39 |
- our_name, our_port); |
|
77 |
+ names[0], port_no); |
|
40 | 78 |
/* check if received needs to be added */ |
41 |
- /* if check_address(source_ip, msg->via1.host) */ |
|
42 |
- received_len=snprintf(received_buf, MAX_RECEIVED_SIZE, ";received=%s", |
|
43 |
- "10.11.12.13"); |
|
79 |
+ if (check_address(source_ip, msg->via1.host, received_dns)!=0){ |
|
80 |
+ received_len=snprintf(received_buf, MAX_RECEIVED_SIZE, |
|
81 |
+ ";received=%s", |
|
82 |
+ inet_ntoa(*(struct in_addr *)&source_ip)); |
|
83 |
+ } |
|
44 | 84 |
|
45 | 85 |
new_len=len+via_len+received_len; |
46 | 86 |
new_buf=(char*)malloc(new_len+1); |
... | ... |
@@ -120,13 +160,25 @@ int forward_reply(char * orig, char* buf, |
120 | 160 |
{ |
121 | 161 |
|
122 | 162 |
|
123 |
- unsigned int new_len, via_len; |
|
163 |
+ unsigned int new_len, via_len,r; |
|
124 | 164 |
char* new_buf; |
125 | 165 |
int offset, s_offset, size; |
126 | 166 |
struct hostent* he; |
127 | 167 |
struct sockaddr_in to; |
128 | 168 |
|
169 |
+ new_buf=0; |
|
129 | 170 |
|
171 |
+ /*check if first via host = us */ |
|
172 |
+ if (check_via){ |
|
173 |
+ for (r=0; r<addresses_no; r++) |
|
174 |
+ if(strcmp(msg->via1.host, names[r])==0) break; |
|
175 |
+ if (r==addresses_no){ |
|
176 |
+ DPrint("ERROR: forward_reply: host in first via != me : %s\n", |
|
177 |
+ msg->via1.host); |
|
178 |
+ /* send error msg back? */ |
|
179 |
+ goto error; |
|
180 |
+ } |
|
181 |
+ } |
|
130 | 182 |
/* we must remove the first via */ |
131 | 183 |
via_len=msg->via1.size; |
132 | 184 |
size=msg->via1.hdr-buf; |
... | ... |
@@ -9,8 +9,12 @@ |
9 | 9 |
#include "msg_parser.h" |
10 | 10 |
#include "route.h" |
11 | 11 |
|
12 |
+ |
|
13 |
+int check_address(unsigned long ip, char *name, int resolver); |
|
14 |
+ |
|
12 | 15 |
int forward_request(char * orig, char* buf, unsigned int len, |
13 |
- struct sip_msg* msg, struct route_elem* re); |
|
16 |
+ struct sip_msg* msg, struct route_elem* re, |
|
17 |
+ unsigned long source_ip); |
|
14 | 18 |
|
15 | 19 |
int forward_reply(char * orig, char* buf, unsigned int len, |
16 | 20 |
struct sip_msg* msg); |
17 | 21 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,30 @@ |
1 |
+/* |
|
2 |
+ * $Id* |
|
3 |
+ * |
|
4 |
+ * global variables |
|
5 |
+ * |
|
6 |
+ */ |
|
7 |
+ |
|
8 |
+ |
|
9 |
+#ifndef globals_h |
|
10 |
+#define globals_h |
|
11 |
+ |
|
12 |
+#define NO_DNS 0 |
|
13 |
+#define DO_DNS 1 |
|
14 |
+#define DO_REV_DNS 2 |
|
15 |
+ |
|
16 |
+ |
|
17 |
+extern char * cfg_file; |
|
18 |
+extern unsigned short port_no; |
|
19 |
+extern char * names[]; |
|
20 |
+extern unsigned long addresses[]; |
|
21 |
+extern int addresses_no; |
|
22 |
+extern int child_no; |
|
23 |
+extern int debug; |
|
24 |
+extern int dont_fork; |
|
25 |
+extern int log_stderr; |
|
26 |
+extern int check_via; |
|
27 |
+extern int received_dns; |
|
28 |
+ |
|
29 |
+ |
|
30 |
+#endif |
... | ... |
@@ -6,12 +6,45 @@ |
6 | 6 |
#include <errno.h> |
7 | 7 |
#include <string.h> |
8 | 8 |
#include <netdb.h> |
9 |
+#include <unistd.h> |
|
10 |
+#include <sys/socket.h> |
|
11 |
+#include <netinet/in.h> |
|
12 |
+#include <arpa/inet.h> |
|
13 |
+#include <sys/utsname.h> |
|
9 | 14 |
|
10 | 15 |
#include "config.h" |
11 | 16 |
#include "dprint.h" |
12 | 17 |
#include "route.h" |
13 | 18 |
#include "udp_server.h" |
14 |
- |
|
19 |
+#include "globals.h" |
|
20 |
+ |
|
21 |
+ |
|
22 |
+static char id[]="@(#) $Id$"; |
|
23 |
+static char version[]="sip_router 0.3"; |
|
24 |
+static char help_msg[]= "\ |
|
25 |
+Usage: sip_router -l address [-l address] [options]\n\ |
|
26 |
+Options:\n\ |
|
27 |
+ -f file Configuration file (default " CFG_FILE ")\n\ |
|
28 |
+ -p port Listen on the specified port (default: 5060)\n\ |
|
29 |
+ -l address Listen on the specified address (multiple -l mean\n\ |
|
30 |
+ listening on more addresses). The default behaviour\n\ |
|
31 |
+ is to listen on the addresses returned by uname(2)\n\ |
|
32 |
+\n\ |
|
33 |
+ -n processes Number of child processes to fork per interface\n\ |
|
34 |
+ (default: 8)\n\ |
|
35 |
+\n\ |
|
36 |
+ -r Use dns to check if is necessary to add a \"received=\"\n\ |
|
37 |
+ field to a via\n\ |
|
38 |
+ -R Same as `-r� but use reverse dns;\n\ |
|
39 |
+ (to use both use `-rR�)\n\ |
|
40 |
+\n\ |
|
41 |
+ -v Turn on \"via:\" host checking when forwarding replies\n\ |
|
42 |
+ -d Debugging mode (multiple -d increase the level)\n\ |
|
43 |
+ -D Do not fork into daemon mode\n\ |
|
44 |
+ -E Log to stderr\n\ |
|
45 |
+ -V Version number\n\ |
|
46 |
+ -h This help message\n\ |
|
47 |
+"; |
|
15 | 48 |
|
16 | 49 |
|
17 | 50 |
/* debuging function */ |
... | ... |
@@ -31,41 +64,156 @@ void receive_stdin_loop() |
31 | 64 |
} |
32 | 65 |
*/ |
33 | 66 |
|
34 |
-#define NAME "0.0.0.0" |
|
67 |
+/* global vars */ |
|
68 |
+ |
|
69 |
+char* cfg_file = 0; |
|
70 |
+unsigned short port_no = 0; /* port on which we listen */ |
|
71 |
+int child_no = 0; /* number of children processing requests */ |
|
72 |
+int debug = 0; |
|
73 |
+int dont_fork = 0; |
|
74 |
+int log_stderr = 0; |
|
75 |
+int check_via = 0; /* check if reply first via host==us */ |
|
76 |
+int received_dns = 0; /* use dns and/or rdns or to see if we need to |
|
77 |
+ add a ;received=x.x.x.x to via: */ |
|
78 |
+ |
|
79 |
+char* names[MAX_LISTEN]; /* our names */ |
|
80 |
+unsigned long addresses[MAX_LISTEN]; /* our ips */ |
|
81 |
+int addresses_no=0; /* number of names/ips */ |
|
82 |
+ |
|
35 | 83 |
|
36 | 84 |
|
37 | 85 |
int main(int argc, char** argv) |
38 | 86 |
{ |
39 | 87 |
|
40 |
- char * cfg_file; |
|
41 | 88 |
FILE* cfg_stream; |
42 | 89 |
struct hostent* he; |
90 |
+ int c,r; |
|
91 |
+ char *tmp; |
|
92 |
+ struct utsname myname; |
|
43 | 93 |
|
44 |
- cfg_file=CFG_FILE; |
|
45 |
- |
|
46 | 94 |
/* process command line (get port no, cfg. file path etc) */ |
47 |
- /* ...*/ |
|
48 |
- |
|
49 |
- our_port=SIP_PORT; |
|
50 |
- our_name=NAME; |
|
51 |
- /* get ip */ |
|
52 |
- he=gethostbyname(our_name); |
|
53 |
- if (he==0){ |
|
54 |
- DPrint("ERROR: could not resolve %s\n", our_name); |
|
55 |
- goto error; |
|
95 |
+ opterr=0; |
|
96 |
+ while((c=getopt(argc,argv,"f:p:l:n:rRvdDEVh"))!=-1){ |
|
97 |
+ switch(c){ |
|
98 |
+ case 'f': |
|
99 |
+ cfg_file=optarg; |
|
100 |
+ break; |
|
101 |
+ case 'p': |
|
102 |
+ port_no=strtol(optarg, &tmp, 10); |
|
103 |
+ if (tmp &&(*tmp)){ |
|
104 |
+ fprintf(stderr, "bad port number: -p %s\n", optarg); |
|
105 |
+ goto error; |
|
106 |
+ } |
|
107 |
+ break; |
|
108 |
+ case 'l': |
|
109 |
+ /* add a new addr. to out address list */ |
|
110 |
+ if (addresses_no < MAX_LISTEN){ |
|
111 |
+ names[addresses_no]=(char*)malloc(strlen(optarg)+1); |
|
112 |
+ if (names[addresses_no]==0){ |
|
113 |
+ fprintf(stderr, "Out of memory.\n"); |
|
114 |
+ goto error; |
|
115 |
+ } |
|
116 |
+ strncpy(names[addresses_no], optarg, strlen(optarg)+1); |
|
117 |
+ addresses_no++; |
|
118 |
+ }else{ |
|
119 |
+ fprintf(stderr, |
|
120 |
+ "Too many addresses (max. %d).\n", |
|
121 |
+ MAX_LISTEN); |
|
122 |
+ goto error; |
|
123 |
+ } |
|
124 |
+ break; |
|
125 |
+ case 'n': |
|
126 |
+ child_no=strtol(optarg, tmp, 10); |
|
127 |
+ if (tmp &&(*tmp)){ |
|
128 |
+ fprintf(stderr, "bad process number: -n %s\n", optarg); |
|
129 |
+ goto error; |
|
130 |
+ } |
|
131 |
+ break; |
|
132 |
+ case 'v': |
|
133 |
+ check_via=1; |
|
134 |
+ break; |
|
135 |
+ case 'r': |
|
136 |
+ received_dns|=DO_DNS; |
|
137 |
+ break; |
|
138 |
+ case 'R': |
|
139 |
+ received_dns|=DO_REV_DNS; |
|
140 |
+ case 'd': |
|
141 |
+ debug++; |
|
142 |
+ break; |
|
143 |
+ case 'D': |
|
144 |
+ dont_fork=1; |
|
145 |
+ break; |
|
146 |
+ case 'E': |
|
147 |
+ log_stderr=1; |
|
148 |
+ break; |
|
149 |
+ case 'V': |
|
150 |
+ printf("version: %s\n", version); |
|
151 |
+ exit(0); |
|
152 |
+ break; |
|
153 |
+ case 'h': |
|
154 |
+ printf("version: %s\n", version); |
|
155 |
+ printf("%s",help_msg); |
|
156 |
+ exit(0); |
|
157 |
+ break; |
|
158 |
+ case '?': |
|
159 |
+ if (isprint(optopt)) |
|
160 |
+ fprintf(stderr, "Unknown option `-%c'.\n", optopt); |
|
161 |
+ else |
|
162 |
+ fprintf(stderr, |
|
163 |
+ "Unknown option character `\\x%x�.\n", |
|
164 |
+ optopt); |
|
165 |
+ goto error; |
|
166 |
+ case ':': |
|
167 |
+ fprintf(stderr, |
|
168 |
+ "Option `-%c� requires an argument.\n", |
|
169 |
+ optopt); |
|
170 |
+ goto error; |
|
171 |
+ default: |
|
172 |
+ abort(); |
|
173 |
+ } |
|
174 |
+ } |
|
175 |
+ |
|
176 |
+ /* fill missing arguments with the default values*/ |
|
177 |
+ if (cfg_file==0) cfg_file=CFG_FILE; |
|
178 |
+ if (port_no==0) port_no=SIP_PORT; |
|
179 |
+ if (child_no==0) child_no=CHILD_NO; |
|
180 |
+ if (addresses_no==0) { |
|
181 |
+ /* get our address, only the first one */ |
|
182 |
+ if (uname (&myname) <0){ |
|
183 |
+ fprintf(stderr, "cannot determine hostname, try -l address\n"); |
|
184 |
+ goto error; |
|
185 |
+ } |
|
186 |
+ names[addresses_no]=(char*)malloc(strlen(myname.nodename)+1); |
|
187 |
+ if (names[addresses_no]==0){ |
|
188 |
+ fprintf(stderr, "Out of memory.\n"); |
|
189 |
+ goto error; |
|
190 |
+ } |
|
191 |
+ strncpy(names[addresses_no], myname.nodename, |
|
192 |
+ strlen(myname.nodename)+1); |
|
193 |
+ addresses_no++; |
|
194 |
+ } |
|
195 |
+ |
|
196 |
+ /* get ips */ |
|
197 |
+ printf("Listening on "); |
|
198 |
+ for (r=0; r<addresses_no;r++){ |
|
199 |
+ he=gethostbyname(names[r]); |
|
200 |
+ if (he==0){ |
|
201 |
+ DPrint("ERROR: could not resolve %s\n", names[r]); |
|
202 |
+ goto error; |
|
203 |
+ } |
|
204 |
+ addresses[r]=*((long*)he->h_addr_list[0]); |
|
205 |
+ printf("%s [%s] : %d\n",names[r], |
|
206 |
+ inet_ntoa(*(struct in_addr*)&addresses[r]), |
|
207 |
+ (unsigned short)port_no); |
|
56 | 208 |
} |
57 |
- our_address=*((long*)he->h_addr_list[0]); |
|
58 |
- printf("Listening on %s[%x]:%d\n",our_name, |
|
59 |
- (unsigned long)our_address, |
|
60 |
- (unsigned short)our_port); |
|
61 |
- |
|
62 | 209 |
|
63 | 210 |
|
64 | 211 |
|
65 | 212 |
/* load config file or die */ |
66 | 213 |
cfg_stream=fopen (cfg_file, "r"); |
67 | 214 |
if (cfg_stream==0){ |
68 |
- DPrint("ERROR: could not load config file: %s\n", strerror(errno)); |
|
215 |
+ DPrint("ERROR: loading config file(%s): %s\n", cfg_file, |
|
216 |
+ strerror(errno)); |
|
69 | 217 |
goto error; |
70 | 218 |
} |
71 | 219 |
|
... | ... |
@@ -79,7 +227,9 @@ int main(int argc, char** argv) |
79 | 227 |
|
80 | 228 |
|
81 | 229 |
/* init_daemon? */ |
82 |
- if (udp_init(our_address,our_port)==-1) goto error; |
|
230 |
+ |
|
231 |
+ /* only one address for now */ |
|
232 |
+ if (udp_init(addresses[0],port_no)==-1) goto error; |
|
83 | 233 |
/* start/init other processes/threads ? */ |
84 | 234 |
|
85 | 235 |
/* receive loop */ |
... | ... |
@@ -11,7 +11,7 @@ |
11 | 11 |
#include "forward.h" |
12 | 12 |
|
13 | 13 |
|
14 |
-int receive_msg(char* buf, unsigned int len) |
|
14 |
+int receive_msg(char* buf, unsigned int len, unsigned long src_ip) |
|
15 | 15 |
{ |
16 | 16 |
struct sip_msg msg; |
17 | 17 |
struct route_elem *re; |
... | ... |
@@ -49,8 +49,8 @@ int receive_msg(char* buf, unsigned int len) |
49 | 49 |
} |
50 | 50 |
re->tx++; |
51 | 51 |
/* send msg */ |
52 |
- forward_request(orig, buf, len, &msg, re); |
|
53 | 52 |
DPrint(" found route to: %s\n", re->host.h_name); |
53 |
+ forward_request(orig, buf, len, &msg, re, src_ip); |
|
54 | 54 |
}else if (msg.first_line.type==SIP_REPLY){ |
55 | 55 |
/* sanity checks */ |
56 | 56 |
if (msg.via1.error!=VIA_PARSE_OK){ |
... | ... |
@@ -64,11 +64,11 @@ int receive_msg(char* buf, unsigned int len) |
64 | 64 |
/* check if via1 == us */ |
65 | 65 |
|
66 | 66 |
/* send the msg */ |
67 |
- forward_reply(orig, buf, len, &msg); |
|
68 |
- DPrint(" reply forwarded to %s:%d\n", |
|
69 |
- msg.via2.host, |
|
70 |
- (unsigned short) msg.via2.port |
|
71 |
- ); |
|
67 |
+ if (forward_reply(orig, buf, len, &msg)==0){ |
|
68 |
+ DPrint(" reply forwarded to %s:%d\n", |
|
69 |
+ msg.via2.host, |
|
70 |
+ (unsigned short) msg.via2.port); |
|
71 |
+ } |
|
72 | 72 |
} |
73 | 73 |
skip: |
74 | 74 |
free(orig); |
... | ... |
@@ -15,10 +15,6 @@ |
15 | 15 |
|
16 | 16 |
int udp_sock; |
17 | 17 |
|
18 |
-char* our_name; |
|
19 |
-unsigned long our_address; |
|
20 |
-unsigned short our_port; |
|
21 |
- |
|
22 | 18 |
|
23 | 19 |
|
24 | 20 |
int udp_init(unsigned long ip, unsigned short port) |
... | ... |
@@ -37,7 +33,7 @@ int udp_init(unsigned long ip, unsigned short port) |
37 | 33 |
} |
38 | 34 |
/* set sock opts? */ |
39 | 35 |
optval=1; |
40 |
- if (setsockopt(udp_sock, SOL_SOCKET, SO_REUSEPORT, |
|
36 |
+ if (setsockopt(udp_sock, SOL_SOCKET, SO_REUSEADDR, |
|
41 | 37 |
&optval, sizeof(optval)) ==-1) |
42 | 38 |
{ |
43 | 39 |
DPrint("ERROR: udp_init: setsockopt: %s\n", strerror()); |
... | ... |
@@ -82,15 +78,17 @@ int udp_rcv_loop() |
82 | 78 |
/*debugging, make print* msg work */ |
83 | 79 |
buf[len+1]=0; |
84 | 80 |
|
85 |
- receive_msg(buf, len, from, fromlen); |
|
86 |
- |
|
81 |
+ receive_msg(buf, len, ((struct sockaddr_in*)from)->sin_addr.s_addr); |
|
82 |
+ |
|
87 | 83 |
skip: /* do other stuff */ |
88 | 84 |
|
89 | 85 |
} |
90 |
- |
|
86 |
+ |
|
87 |
+ if (from) free(from); |
|
91 | 88 |
return 0; |
92 | 89 |
|
93 | 90 |
error: |
91 |
+ if (from) free(from); |
|
94 | 92 |
return -1; |
95 | 93 |
} |
96 | 94 |
|