- added cmd line options, help
[sip-router] / forward.c
1 /*
2  * $Id$
3  */
4
5
6 #include <string.h>
7 #include <sys/types.h>
8 #include <sys/socket.h>
9 #include <netdb.h>
10 #include <netinet/in.h>
11 #include <arpa/inet.h>
12
13 #include "forward.h"
14 #include "config.h"
15 #include "msg_parser.h"
16 #include "route.h"
17 #include "dprint.h"
18 #include "udp_server.h"
19 #include "globals.h"
20
21 #define MAX_VIA_LINE_SIZE      240
22 #define MAX_RECEIVED_SIZE  57
23
24
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
61 int forward_request(char * orig, char* buf, 
62                                          unsigned int len,
63                                          struct sip_msg* msg,
64                                          struct route_elem* re,
65                                          unsigned long source_ip)
66 {
67         unsigned int new_len, via_len, received_len;
68         char line_buf[MAX_VIA_LINE_SIZE];
69         char received_buf[MAX_RECEIVED_SIZE];
70         char* new_buf;
71         int offset, s_offset, size;
72         struct sockaddr_in to;
73
74         received_len=0;
75
76         via_len=snprintf(line_buf, MAX_VIA_LINE_SIZE, "Via: SIP/2.0/UDP %s:%d\r\n",
77                                                 names[0], port_no);
78         /* check if received needs to be added */
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         }
84         
85         new_len=len+via_len+received_len;
86         new_buf=(char*)malloc(new_len+1);
87         if (new_buf==0){
88                 DPrint("ERROR: forward_request: out of memory\n");
89                 goto error1;
90         }
91 /* copy msg till first via */
92         offset=s_offset=0;
93         size=msg->via1.hdr-buf;
94         memcpy(new_buf, orig, size);
95         offset+=size;
96         s_offset+=size;
97  /* add our via */
98         memcpy(new_buf+offset, line_buf, via_len);
99         offset+=via_len;
100  /* modify original via if neccesarry (received=...)*/
101         if (received_len){
102                 if (msg->via1.params){
103                                 size= msg->via1.params-msg->via1.hdr-1; /*compensate for ';' */
104                 }else{
105                                 size= msg->via1.host-msg->via1.hdr+strlen(msg->via1.host);
106                                 if (msg->via1.port!=0){
107                                         size+=strlen(msg->via1.hdr+size+1)+1; /* +1 for ':'*/
108                                 }
109                 }
110                 memcpy(new_buf+offset, orig+s_offset, 
111                                                                 size);
112                 offset+=size;
113                 s_offset+=size;
114                 memcpy(new_buf+offset, received_buf, received_len);
115                 offset+=received_len;
116         }
117         /* copy the rest of the msg */
118         memcpy(new_buf+offset, orig+s_offset, len-s_offset);
119         new_buf[new_len]=0;
120
121          /* send it! */
122         printf("Sending:\n%s.\n", new_buf);
123         printf("orig. len=%d, new_len=%d, via_len=%d, received_len=%d\n",
124                         len, new_len, via_len, received_len);
125
126         to.sin_family = AF_INET;
127         to.sin_port = (re->port)?htons(re->port):htons(SIP_PORT);
128         /* if error try next ip address if possible */
129         if (re->ok==0){
130                 if (re->host.h_addr_list[re->current_addr_idx+1])
131                         re->current_addr_idx++;
132                 re->ok=1;
133         }
134         /* ? not 64bit clean?*/
135         to.sin_addr.s_addr=*((long*)re->host.h_addr_list[re->current_addr_idx]);
136
137         re->tx++;
138         re->tx_bytes+=new_len;
139         if (udp_send(new_buf, new_len, &to, sizeof(to))==-1){
140                         re->errors++;
141                         re->ok=0;
142                         goto error;
143         }
144
145         free(new_buf);
146         return 0;
147 error:
148         free(new_buf);
149 error1:
150         return -1;
151
152 }
153
154
155
156 /* removes first via & sends msg to the second */
157 int forward_reply(char * orig, char* buf, 
158                                          unsigned int len,
159                                          struct sip_msg* msg)
160 {
161
162
163         unsigned int new_len, via_len,r;
164         char* new_buf;
165         int offset, s_offset, size;
166         struct hostent* he;
167         struct sockaddr_in to;
168
169         new_buf=0;
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         }
182         /* we must remove the first via */
183         via_len=msg->via1.size;
184         size=msg->via1.hdr-buf;
185         if (msg->via1.next){
186                 /* keep hdr =substract hdr size +1 (hdr':') and add
187                  */
188                 via_len-=strlen(msg->via1.hdr)+1;
189                 size+=strlen(msg->via1.hdr)+1;
190         }
191         new_len=len-size;
192         new_buf=(char*)malloc(new_len);
193         if (new_buf==0){
194                 DPrint("ERROR: forward_reply: out of memory\n");
195                 goto error;
196         }
197         memcpy(new_buf, orig, size);
198         offset=size;
199         s_offset=size+via_len;
200         memcpy(new_buf+offset,orig+s_offset, len-s_offset);
201          /* send it! */
202         printf("Sending: to %s:%d, \n%s.\n",
203                         msg->via2.host, 
204                         (unsigned short)msg->via2.port,
205                         new_buf);
206         /* fork? gethostbyname will probably block... */
207         he=gethostbyname(msg->via2.host);
208         if (he==0){
209                 DPrint("ERROR:forward_reply:gethostbyname failure\n");
210                 goto error;
211         }
212         to.sin_family = AF_INET;
213         to.sin_port = (msg->via2.port)?htons(msg->via2.port):htons(SIP_PORT);
214         to.sin_addr.s_addr=*((long*)he->h_addr_list[0]);
215         
216         if (udp_send(new_buf,new_len, &to, sizeof(to))==-1)
217                 goto error;
218         
219         free(new_buf);
220         return 0;
221
222 error:
223         if (new_buf) free(new_buf);
224         return -1;
225 }