forward.c
888ca09d
 /*
  * $Id$
  */
 
 
 #include <string.h>
3e429f5c
 #include <stdio.h>
 #include <stdlib.h>
9a3dc64b
 #include <sys/types.h>
 #include <sys/socket.h>
e60a9728
 #include <netdb.h>
 #include <netinet/in.h>
1b1b19d8
 #include <arpa/inet.h>
888ca09d
 
 #include "forward.h"
e60a9728
 #include "config.h"
888ca09d
 #include "msg_parser.h"
 #include "route.h"
 #include "dprint.h"
e60a9728
 #include "udp_server.h"
1b1b19d8
 #include "globals.h"
888ca09d
 
 #define MAX_VIA_LINE_SIZE      240
 #define MAX_RECEIVED_SIZE  57
 
 
 
1b1b19d8
 /* 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);
3e429f5c
 		for(i=0;he && he->h_addr_list[i];i++){
1b1b19d8
 			if (*(unsigned long*)he->h_addr_list[i]==ip)
 				return 0;
 		}
 	}
 	if (resolver&DO_REV_DNS){
3e429f5c
 	print_ip(ip);
1b1b19d8
 		/* try reverse dns */
cf398313
 		he=gethostbyaddr((char*)&ip, sizeof(ip), AF_INET);
3e429f5c
 		if (he && (strcmp(he->h_name, name)==0))
1b1b19d8
 			return 0;
3e429f5c
 		for (i=0; he && he->h_aliases[i];i++){
1b1b19d8
 			if (strcmp(he->h_aliases[i],name)==0)
 				return 0;
 		}
 	}
 	return -1;
 }
 
 
 
3e429f5c
 int forward_request( struct sip_msg* msg, struct proxy_l * p)
888ca09d
 {
4ac74c03
 	unsigned int len, new_len, via_len, received_len;
888ca09d
 	char line_buf[MAX_VIA_LINE_SIZE];
 	char received_buf[MAX_RECEIVED_SIZE];
 	char* new_buf;
4ac74c03
 	char* orig;
 	char* buf;
3e429f5c
 	unsigned int offset, s_offset, size;
dc862225
 	struct sockaddr_in* to;
3e429f5c
 	unsigned long source_ip;
888ca09d
 
4ac74c03
 	orig=msg->orig;
 	buf=msg->buf;
 	len=msg->len;
3e429f5c
 	source_ip=msg->src_ip;
888ca09d
 	received_len=0;
dc862225
 	new_buf=0;
 	to=0;
 	to=(struct sockaddr_in*)malloc(sizeof(struct sockaddr));
 	if (to==0){
efeaaf53
 		LOG(L_ERR, "ERROR: forward_reply: out of memory\n");
dc862225
 		goto error;
 	}
888ca09d
 
 	via_len=snprintf(line_buf, MAX_VIA_LINE_SIZE, "Via: SIP/2.0/UDP %s:%d\r\n",
1b1b19d8
 						names[0], port_no);
888ca09d
 	/* check if received needs to be added */
1b1b19d8
 	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));
 	}
888ca09d
 	
 	new_len=len+via_len+received_len;
 	new_buf=(char*)malloc(new_len+1);
 	if (new_buf==0){
efeaaf53
 		LOG(L_ERR, "ERROR: forward_request: out of memory\n");
dc862225
 		goto error;
888ca09d
 	}
e60a9728
 /* copy msg till first via */
 	offset=s_offset=0;
 	size=msg->via1.hdr-buf;
 	memcpy(new_buf, orig, size);
888ca09d
 	offset+=size;
 	s_offset+=size;
  /* add our via */
e60a9728
 	memcpy(new_buf+offset, line_buf, via_len);
888ca09d
 	offset+=via_len;
  /* modify original via if neccesarry (received=...)*/
e60a9728
 	if (received_len){
888ca09d
 		if (msg->via1.params){
 				size= msg->via1.params-msg->via1.hdr-1; /*compensate for ';' */
 		}else{
 				size= msg->via1.host-msg->via1.hdr+strlen(msg->via1.host);
 				if (msg->via1.port!=0){
e60a9728
 					size+=strlen(msg->via1.hdr+size+1)+1; /* +1 for ':'*/
888ca09d
 				}
 		}
 		memcpy(new_buf+offset, orig+s_offset, 
 								size);
 		offset+=size;
 		s_offset+=size;
 		memcpy(new_buf+offset, received_buf, received_len);
 		offset+=received_len;
 	}
  	/* copy the rest of the msg */
  	memcpy(new_buf+offset, orig+s_offset, len-s_offset);
 	new_buf[new_len]=0;
 
 	 /* send it! */
efeaaf53
 	DBG("Sending:\n%s.\n", new_buf);
 	DBG("orig. len=%d, new_len=%d, via_len=%d, received_len=%d\n",
e60a9728
 			len, new_len, via_len, received_len);
 
dc862225
 	to->sin_family = AF_INET;
4ac74c03
 	to->sin_port = (p->port)?htons(p->port):htons(SIP_PORT);
e60a9728
 	/* if error try next ip address if possible */
4ac74c03
 	if (p->ok==0){
 		if (p->host.h_addr_list[p->addr_idx+1])
 			p->addr_idx++;
 		p->ok=1;
e60a9728
 	}
 	/* ? not 64bit clean?*/
4ac74c03
 	to->sin_addr.s_addr=*((long*)p->host.h_addr_list[p->addr_idx]);
e60a9728
 
4ac74c03
 	p->tx++;
 	p->tx_bytes+=new_len;
3e429f5c
 	if (udp_send(new_buf, new_len, (struct sockaddr*) to,
 				sizeof(struct sockaddr_in))==-1){
4ac74c03
 			p->errors++;
 			p->ok=0;
e60a9728
 			goto error;
 	}
 
 	free(new_buf);
dc862225
 	free(to);
888ca09d
 	return 0;
 error:
dc862225
 	if (new_buf) free(new_buf);
 	if (to) free(to);
888ca09d
 	return -1;
 
 }
 
 
 
 /* removes first via & sends msg to the second */
4ac74c03
 int forward_reply(struct sip_msg* msg)
888ca09d
 {
 
 
1b1b19d8
 	unsigned int new_len, via_len,r;
888ca09d
 	char* new_buf;
3e429f5c
 	unsigned offset, s_offset, size;
e60a9728
 	struct hostent* he;
dc862225
 	struct sockaddr_in* to;
4ac74c03
 	char* orig;
 	char* buf;
 	unsigned int len;
 	
888ca09d
 
4ac74c03
 	orig=msg->orig;
 	buf=msg->buf;
 	len=msg->len;
1b1b19d8
 	new_buf=0;
dc862225
 	to=0;
 	to=(struct sockaddr_in*)malloc(sizeof(struct sockaddr));
 	if (to==0){
efeaaf53
 		LOG(L_ERR, "ERROR: forward_reply: out of memory\n");
dc862225
 		goto error;
 	}
888ca09d
 
1b1b19d8
 	/*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){
efeaaf53
 			LOG(L_NOTICE, "ERROR: forward_reply: host in first via!=me : %s\n",
1b1b19d8
 					msg->via1.host);
 			/* send error msg back? */
 			goto error;
 		}
 	}
e60a9728
 	/* we must remove the first via */
888ca09d
 	via_len=msg->via1.size;
 	size=msg->via1.hdr-buf;
efeaaf53
 	DBG("via len: %d, initial size: %d\n", via_len, size);
888ca09d
 	if (msg->via1.next){
e60a9728
 		/* keep hdr =substract hdr size +1 (hdr':') and add
 		 */
 		via_len-=strlen(msg->via1.hdr)+1;
888ca09d
 		size+=strlen(msg->via1.hdr)+1;
efeaaf53
 	    DBG(" adjusted via len: %d, initial size: %d\n",
413d69f1
 				via_len, size);
888ca09d
 	}
413d69f1
 	new_len=len-via_len;
 	
efeaaf53
 	DBG(" old size: %d, new size: %d\n", len, new_len);
413d69f1
 	new_buf=(char*)malloc(new_len+1);/* +1 is for debugging (\0 to print it )*/
888ca09d
 	if (new_buf==0){
efeaaf53
 		LOG(L_ERR, "ERROR: forward_reply: out of memory\n");
888ca09d
 		goto error;
 	}
413d69f1
 	new_buf[new_len]=0; /* debug: print the message */
888ca09d
 	memcpy(new_buf, orig, size);
 	offset=size;
 	s_offset=size+via_len;
 	memcpy(new_buf+offset,orig+s_offset, len-s_offset);
 	 /* send it! */
efeaaf53
 	DBG(" copied size: orig:%d, new: %d, rest: %d\n",
413d69f1
 			s_offset, offset, 
 			len-s_offset );
efeaaf53
 	DBG("Sending: to %s:%d, \n%s.\n",
888ca09d
 			msg->via2.host, 
 			(unsigned short)msg->via2.port,
 			new_buf);
e60a9728
 	/* fork? gethostbyname will probably block... */
 	he=gethostbyname(msg->via2.host);
 	if (he==0){
efeaaf53
 		LOG(L_NOTICE, "ERROR:forward_reply:gethostbyname(%s) failure\n",
 				msg->via2.host);
e60a9728
 		goto error;
 	}
dc862225
 	to->sin_family = AF_INET;
 	to->sin_port = (msg->via2.port)?htons(msg->via2.port):htons(SIP_PORT);
 	to->sin_addr.s_addr=*((long*)he->h_addr_list[0]);
e60a9728
 	
3e429f5c
 	if (udp_send(new_buf,new_len, (struct sockaddr*) to, 
 					sizeof(struct sockaddr_in))==-1)
e60a9728
 		goto error;
888ca09d
 	
e60a9728
 	free(new_buf);
dc862225
 	free(to);
888ca09d
 	return 0;
 
 error:
e60a9728
 	if (new_buf) free(new_buf);
dc862225
 	if (to) free(to);
888ca09d
 	return -1;
 }