Browse Source

- added cmd line options, help
- added check for via (replies) and check for received (requests)
- minor bugfixes

Andrei Pelinescu-Onciul 24 years ago
parent
commit
1b1b19d885
11 changed files with 294 additions and 52 deletions
  1. 8 3
      Makefile
  2. 6 0
      config.h
  3. 58 6
      forward.c
  4. 5 1
      forward.h
  5. 30 0
      globals.h
  6. 171 21
      main.c
  7. 7 7
      receive.c
  8. 1 1
      receive.h
  9. 2 1
      sip_router.cfg
  10. 6 8
      udp_server.c
  11. 0 4
      udp_server.h

+ 8 - 3
Makefile

@@ -2,6 +2,8 @@
 #
 # sip_router makefile
 #
+# WARNING: requires gmake (GNU Make)
+#
 
 sources= $(wildcard *.c)
 objs= $(sources:.c=.o)
@@ -10,7 +12,10 @@ depends= $(sources:.c=.d)
 NAME=sip_router
 
 CC=gcc
-COPTS=-O2
+CFLAGS=-O2
+# on linux and freebsd keep it empty (e.g. LIBS= )
+# on solaris add -lxnet (e.g. LIBS= -lxnet)
+LIBS=
 ALLDEP=Makefile
 
 MKDEP=gcc -M
@@ -19,13 +24,13 @@ MKDEP=gcc -M
 #implicit rules
 
 %.o:%.c $(ALLDEP)
-	$(CC) $(COPTS) -c $< -o $@
+	$(CC) $(CFLAGS) -c $< -o $@
 
 %.d: %.c
 	$(MKDEP) $< >$@
 
 $(NAME): $(objs)
-	$(CC) $(COPTS) $(objs) -o $(NAME)
+	$(CC) $(CFLAGS) $(LIBS) $(objs) -o $(NAME)
 
 .PHONY: all
 all: $(NAME)

+ 6 - 0
config.h

@@ -15,4 +15,10 @@
 /* receive buffer size */
 #define BUF_SIZE 65507
 
+/* maximum number of addresses on which we will listen */
+#define MAX_LISTEN 16
+
+/* default number of child processes started */
+#define CHILD_NO    8
+
 #endif

+ 58 - 6
forward.c

@@ -8,6 +8,7 @@
 #include <sys/socket.h>
 #include <netdb.h>
 #include <netinet/in.h>
+#include <arpa/inet.h>
 
 #include "forward.h"
 #include "config.h"
@@ -15,16 +16,53 @@
 #include "route.h"
 #include "dprint.h"
 #include "udp_server.h"
+#include "globals.h"
 
 #define MAX_VIA_LINE_SIZE      240
 #define MAX_RECEIVED_SIZE  57
 
 
 
+/* checks if ip is in host(name) and ?host(ip)=name? 
+ * ip must be in network byte order!
+ *  resolver = DO_DNS | DO_REV_DNS; if 0 no dns check is made
+ * return 0 if equal */
+int check_address(unsigned long ip, char *name, int resolver)
+{
+	struct hostent* he;
+	int i;
+	
+	/* maybe we are lucky and name it's an ip */
+	if (strcmp(name, inet_ntoa( *(struct in_addr *)&ip ))==0)
+		return 0;
+	if (resolver&DO_DNS){ 
+		/* try all names ips */
+		he=gethostbyname(name);
+		for(i=0; he->h_addr_list[i];i++){
+			if (*(unsigned long*)he->h_addr_list[i]==ip)
+				return 0;
+		}
+	}
+	if (resolver&DO_REV_DNS){
+		/* try reverse dns */
+		he=gethostbyaddr(&ip, sizeof(ip), AF_INET);
+		if (strcmp(he->h_name, name)==0)
+			return 0;
+		for (i=0; he->h_aliases[i];i++){
+			if (strcmp(he->h_aliases[i],name)==0)
+				return 0;
+		}
+	}
+	return -1;
+}
+
+
+
 int forward_request(char * orig, char* buf, 
 					 unsigned int len,
 					 struct sip_msg* msg,
-					 struct route_elem* re)
+					 struct route_elem* re,
+					 unsigned long source_ip)
 {
 	unsigned int new_len, via_len, received_len;
 	char line_buf[MAX_VIA_LINE_SIZE];
@@ -36,11 +74,13 @@ int forward_request(char * orig, char* buf,
 	received_len=0;
 
 	via_len=snprintf(line_buf, MAX_VIA_LINE_SIZE, "Via: SIP/2.0/UDP %s:%d\r\n",
-						our_name, our_port);
+						names[0], port_no);
 	/* check if received needs to be added */
-	/* if check_address(source_ip, msg->via1.host) */
-	received_len=snprintf(received_buf, MAX_RECEIVED_SIZE, ";received=%s",
-							"10.11.12.13");
+	if (check_address(source_ip, msg->via1.host, received_dns)!=0){
+		received_len=snprintf(received_buf, MAX_RECEIVED_SIZE,
+								";received=%s", 
+								inet_ntoa(*(struct in_addr *)&source_ip));
+	}
 	
 	new_len=len+via_len+received_len;
 	new_buf=(char*)malloc(new_len+1);
@@ -120,13 +160,25 @@ int forward_reply(char * orig, char* buf,
 {
 
 
-	unsigned int new_len, via_len;
+	unsigned int new_len, via_len,r;
 	char* new_buf;
 	int offset, s_offset, size;
 	struct hostent* he;
 	struct sockaddr_in to;
 
+	new_buf=0;
 
+	/*check if first via host = us */
+	if (check_via){
+		for (r=0; r<addresses_no; r++)
+			if(strcmp(msg->via1.host, names[r])==0) break;
+		if (r==addresses_no){
+			DPrint("ERROR: forward_reply: host in first via != me : %s\n",
+					msg->via1.host);
+			/* send error msg back? */
+			goto error;
+		}
+	}
 	/* we must remove the first via */
 	via_len=msg->via1.size;
 	size=msg->via1.hdr-buf;

+ 5 - 1
forward.h

@@ -9,8 +9,12 @@
 #include "msg_parser.h"
 #include "route.h"
 
+
+int check_address(unsigned long ip, char *name, int resolver);
+
 int forward_request(char * orig, char* buf, unsigned int len,
-					 struct sip_msg* msg,  struct route_elem* re);
+					 struct sip_msg* msg,  struct route_elem* re,
+					 unsigned long source_ip);
 
 int forward_reply(char * orig, char* buf, unsigned int len, 
 					struct sip_msg* msg);

+ 30 - 0
globals.h

@@ -0,0 +1,30 @@
+/*
+ * $Id*
+ *
+ * global variables
+ *
+ */
+
+
+#ifndef globals_h
+#define globals_h
+
+#define NO_DNS     0
+#define DO_DNS     1
+#define DO_REV_DNS 2
+
+
+extern char * cfg_file;
+extern unsigned short port_no;
+extern char * names[];
+extern unsigned long addresses[];
+extern int addresses_no;
+extern int child_no;
+extern int debug;
+extern int dont_fork;
+extern int log_stderr;
+extern int check_via;
+extern int received_dns;
+
+
+#endif

+ 171 - 21
main.c

@@ -6,12 +6,45 @@
 #include <errno.h>
 #include <string.h>
 #include <netdb.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/utsname.h>
 
 #include "config.h"
 #include "dprint.h"
 #include "route.h"
 #include "udp_server.h"
-
+#include "globals.h"
+
+
+static char id[]="@(#) $Id$";
+static char version[]="sip_router 0.3";
+static char help_msg[]= "\
+Usage: sip_router -l address [-l address] [options]\n\
+Options:\n\
+    -f file      Configuration file (default " CFG_FILE ")\n\
+    -p port      Listen on the specified port (default: 5060)\n\
+    -l address   Listen on the specified address (multiple -l mean\n\
+                 listening on more addresses). The default behaviour\n\
+                 is to listen on the addresses returned by uname(2)\n\
+\n\
+    -n processes Number of child processes to fork per interface\n\
+                 (default: 8)\n\
+\n\
+    -r           Use dns to check if is necessary to add a \"received=\"\n\
+                 field to a via\n\
+    -R           Same as `-r´ but use reverse dns;\n\
+                 (to use both use `-rR´)\n\
+\n\
+    -v           Turn on \"via:\" host checking when forwarding replies\n\
+    -d           Debugging mode (multiple -d increase the level)\n\
+    -D           Do not fork into daemon mode\n\
+    -E           Log to stderr\n\
+    -V           Version number\n\
+    -h           This help message\n\
+";
 
 
 /* debuging function */
@@ -31,41 +64,156 @@ void receive_stdin_loop()
 }
 */
 
-#define NAME "0.0.0.0"
+/* global vars */
+
+char* cfg_file = 0;
+unsigned short port_no = 0; /* port on which we listen */
+int child_no = 0;           /* number of children processing requests */
+int debug = 0;
+int dont_fork = 0;
+int log_stderr = 0;
+int check_via =  0;        /* check if reply first via host==us */
+int received_dns = 0;      /* use dns and/or rdns or to see if we need to 
+                              add a ;received=x.x.x.x to via: */
+
+char* names[MAX_LISTEN];               /* our names */
+unsigned long addresses[MAX_LISTEN];   /* our ips */
+int addresses_no=0;                    /* number of names/ips */
+
 
 
 int main(int argc, char** argv)
 {
 
-	char * cfg_file;
 	FILE* cfg_stream;
 	struct hostent* he;
+	int c,r;
+	char *tmp;
+	struct utsname myname;
 
-	cfg_file=CFG_FILE;
-	
 	/* process command line (get port no, cfg. file path etc) */
-	/* ...*/
-
-	our_port=SIP_PORT;
-	our_name=NAME;
-	/* get ip */
-	he=gethostbyname(our_name);
-	if (he==0){
-		DPrint("ERROR: could not resolve %s\n", our_name);
-		goto error;
+	opterr=0;
+	while((c=getopt(argc,argv,"f:p:l:n:rRvdDEVh"))!=-1){
+		switch(c){
+			case 'f':
+					cfg_file=optarg;
+					break;
+			case 'p':
+					port_no=strtol(optarg, &tmp, 10);
+					if (tmp &&(*tmp)){
+						fprintf(stderr, "bad port number: -p %s\n", optarg);
+						goto error;
+					}
+					break;
+			case 'l':
+					/* add a new addr. to out address list */
+					if (addresses_no < MAX_LISTEN){
+						names[addresses_no]=(char*)malloc(strlen(optarg)+1);
+						if (names[addresses_no]==0){
+							fprintf(stderr, "Out of memory.\n");
+							goto error;
+						}
+						strncpy(names[addresses_no], optarg, strlen(optarg)+1);
+						addresses_no++;
+					}else{
+						fprintf(stderr, 
+									"Too many addresses (max. %d).\n",
+									MAX_LISTEN);
+						goto error;
+					}
+					break;
+			case 'n':
+					child_no=strtol(optarg, tmp, 10);
+					if (tmp &&(*tmp)){
+						fprintf(stderr, "bad process number: -n %s\n", optarg);
+						goto error;
+					}
+					break;
+			case 'v':
+					check_via=1;
+					break;
+			case 'r':
+					received_dns|=DO_DNS;
+					break;
+			case 'R':
+					received_dns|=DO_REV_DNS;
+			case 'd':
+					debug++;
+					break;
+			case 'D':
+					dont_fork=1;
+					break;
+			case 'E':
+					log_stderr=1;
+					break;
+			case 'V':
+					printf("version: %s\n", version);
+					exit(0);
+					break;
+			case 'h':
+					printf("version: %s\n", version);
+					printf("%s",help_msg);
+					exit(0);
+					break;
+			case '?':
+					if (isprint(optopt))
+						fprintf(stderr, "Unknown option `-%c'.\n", optopt);
+					else
+						fprintf(stderr, 
+								"Unknown option character `\\x%x´.\n",
+								optopt);
+					goto error;
+			case ':':
+					fprintf(stderr, 
+								"Option `-%c´ requires an argument.\n",
+								optopt);
+					goto error;
+			default:
+					abort();
+		}
+	}
+	
+	/* fill missing arguments with the default values*/
+	if (cfg_file==0) cfg_file=CFG_FILE;
+	if (port_no==0) port_no=SIP_PORT;
+	if (child_no==0) child_no=CHILD_NO;
+	if (addresses_no==0) {
+		/* get our address, only the first one */
+		if (uname (&myname) <0){
+			fprintf(stderr, "cannot determine hostname, try -l address\n");
+			goto error;
+		}
+		names[addresses_no]=(char*)malloc(strlen(myname.nodename)+1);
+		if (names[addresses_no]==0){
+			fprintf(stderr, "Out of memory.\n");
+			goto error;
+		}
+		strncpy(names[addresses_no], myname.nodename,
+				strlen(myname.nodename)+1);
+		addresses_no++;
+	}
+	
+	/* get ips */
+	printf("Listening on ");
+	for (r=0; r<addresses_no;r++){
+		he=gethostbyname(names[r]);
+		if (he==0){
+			DPrint("ERROR: could not resolve %s\n", names[r]);
+			goto error;
+		}
+		addresses[r]=*((long*)he->h_addr_list[0]);
+		printf("%s [%s] : %d\n",names[r],
+				inet_ntoa(*(struct in_addr*)&addresses[r]),
+				(unsigned short)port_no);
 	}
-	our_address=*((long*)he->h_addr_list[0]);
-	printf("Listening on %s[%x]:%d\n",our_name,
-				(unsigned long)our_address,
-				(unsigned short)our_port);
-		
 	
 	
 
 	/* load config file or die */
 	cfg_stream=fopen (cfg_file, "r");
 	if (cfg_stream==0){
-		DPrint("ERROR: could not load config file: %s\n", strerror(errno));
+		DPrint("ERROR: loading config file(%s): %s\n", cfg_file,
+				strerror(errno));
 		goto error;
 	}
 
@@ -79,7 +227,9 @@ int main(int argc, char** argv)
 
 
 	/* init_daemon? */
-	if (udp_init(our_address,our_port)==-1) goto error;
+
+	/* only one address for now */
+	if (udp_init(addresses[0],port_no)==-1) goto error;
 	/* start/init other processes/threads ? */
 
 	/* receive loop */

+ 7 - 7
receive.c

@@ -11,7 +11,7 @@
 #include "forward.h"
 
 
-int receive_msg(char* buf, unsigned int len)
+int receive_msg(char* buf, unsigned int len, unsigned long src_ip)
 {
 	struct sip_msg msg;
 	struct route_elem *re;
@@ -49,8 +49,8 @@ int receive_msg(char* buf, unsigned int len)
 		}
 		re->tx++;
 		/* send msg */
-		forward_request(orig, buf, len, &msg, re);
 		DPrint(" found route to: %s\n", re->host.h_name);
+		forward_request(orig, buf, len, &msg, re, src_ip);
 	}else if (msg.first_line.type==SIP_REPLY){
 		/* sanity checks */
 		if (msg.via1.error!=VIA_PARSE_OK){
@@ -64,11 +64,11 @@ int receive_msg(char* buf, unsigned int len)
 		/* check if via1 == us */
 		
 		/* send the msg */
-		forward_reply(orig, buf, len, &msg);
-		DPrint(" reply forwarded to %s:%d\n", 
-					msg.via2.host,
-					(unsigned short) msg.via2.port
-				);
+		if (forward_reply(orig, buf, len, &msg)==0){
+			DPrint(" reply forwarded to %s:%d\n", 
+						msg.via2.host,
+						(unsigned short) msg.via2.port);
+		}
 	}
 skip:
 	free(orig);

+ 1 - 1
receive.h

@@ -6,7 +6,7 @@
 #ifndef receive_h
 #define receive_h
 
-int receive_msg(char* buf, unsigned int len);
+int receive_msg(char* buf, unsigned int len, unsigned long src_ip);
 
 
 #endif

+ 2 - 1
sip_router.cfg

@@ -4,7 +4,8 @@
 #  method_re   sip_uri_re      dest_host
 # (warning: re cannot contain space)
 
-.*			.*				   fox.iptel.org
+#.*			.*				   centauri.fokus.gmd.de 
+.			.				   fox.iptel.org
 ^R.*        ^sip:.*@dorian.*   ekina.fokus.gmd.de        
 ^INVITE     .*                 ape:5061             # my laptop
 .           .                  192.168.46.55

+ 6 - 8
udp_server.c

@@ -15,10 +15,6 @@
 
 int udp_sock;
 
-char* our_name;
-unsigned long our_address;
-unsigned short our_port;
-
 
 
 int udp_init(unsigned long ip, unsigned short port)
@@ -37,7 +33,7 @@ int udp_init(unsigned long ip, unsigned short port)
 	}
 	/* set sock opts? */
 	optval=1;
-	if (setsockopt(udp_sock, SOL_SOCKET, SO_REUSEPORT,
+	if (setsockopt(udp_sock, SOL_SOCKET, SO_REUSEADDR,
 					&optval, sizeof(optval)) ==-1)
 	{
 		DPrint("ERROR: udp_init: setsockopt: %s\n", strerror());
@@ -82,15 +78,17 @@ int udp_rcv_loop()
 		/*debugging, make print* msg work */
 		buf[len+1]=0;
 
-		receive_msg(buf, len, from, fromlen);
-
+		receive_msg(buf, len, ((struct sockaddr_in*)from)->sin_addr.s_addr);
+		
 	skip: /* do other stuff */
 		
 	}
-
+	
+	if (from) free(from);
 	return 0;
 	
 error:
+	if (from) free(from);
 	return -1;
 }
 

+ 0 - 4
udp_server.h

@@ -9,10 +9,6 @@
 
 extern int udp_sock;
 
-extern char* our_name;
-extern unsigned long  our_address;
-extern unsigned short our_port;
-
 int udp_init(unsigned long ip, unsigned short port);
 int udp_rcv_loop();