- added cmd line options, help v03
authorAndrei Pelinescu-Onciul <andrei@iptel.org>
Thu, 6 Sep 2001 02:24:00 +0000 (02:24 +0000)
committerAndrei Pelinescu-Onciul <andrei@iptel.org>
Thu, 6 Sep 2001 02:24:00 +0000 (02:24 +0000)
- added check for via (replies) and check for received (requests)
- minor bugfixes

Makefile
config.h
forward.c
forward.h
globals.h [new file with mode: 0644]
main.c
receive.c
receive.h
sip_router.cfg
udp_server.c
udp_server.h

index 1fe596c..bcc6368 100644 (file)
--- a/Makefile
+++ b/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)
index 58ac4d6..7468097 100644 (file)
--- a/config.h
+++ b/config.h
 /* 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
index 02036f6..be2f7c6 100644 (file)
--- a/forward.c
+++ b/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"
 #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;
index b0bc9f6..f993089 100644 (file)
--- a/forward.h
+++ b/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);
diff --git a/globals.h b/globals.h
new file mode 100644 (file)
index 0000000..03df6cb
--- /dev/null
+++ b/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
diff --git a/main.c b/main.c
index 7901ef9..36afcd5 100644 (file)
--- a/main.c
+++ b/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 */
index 445e173..ca5d394 100644 (file)
--- a/receive.c
+++ b/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);
index d600f9d..c4d5367 100644 (file)
--- a/receive.h
+++ b/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
index 8aec362..c12d898 100644 (file)
@@ -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
index 104bf88..269a1c2 100644 (file)
 
 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;
 }
 
index 317e297..69b3fd7 100644 (file)
@@ -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();