Browse Source

- added preliminary forward request plugin support

Andrei Pelinescu-Onciul 24 years ago
parent
commit
831faabf7c
8 changed files with 459 additions and 83 deletions
  1. 4 0
      TODO
  2. 210 0
      data_lump.c
  3. 76 0
      data_lump.h
  4. 156 29
      forward.c
  5. 0 50
      mod_iface.h
  6. 5 0
      msg_parser.h
  7. 4 0
      receive.c
  8. 4 4
      test/test-throughput.cfg

+ 4 - 0
TODO

@@ -4,9 +4,11 @@ $Id$
 
 - better Via parsing (handle ' ' in uri, eg: foo.bar : 1234 ; received=) and
  ipv6 addresses ([fec0:aa::01]).
+- fix format string vulnerability in log()
 
 High priority:
 x if () {} else {}
+- plugin interface
 - ipv6 support
 - reply ("response line")
 - drop ACKs for our replies
@@ -15,6 +17,7 @@ x if () {} else {}
 - add User-Agent (for the replies)
 
 Low priority:
+- exec improvments (add format strings to it)
 - command line switch for checking the config file syntax
 - config file version (a la sendmail)
 - loop detection
@@ -23,6 +26,7 @@ Low priority:
 
 - handle SIGCHLD, SIGHUP
 - use a  standard lex compatible .lex format (instead of flex)
+- try & use native compiler & ld if possible
 
 - make install
 - init.d scripts (and rc.local? for *BSD or Slackware)

+ 210 - 0
data_lump.c

@@ -0,0 +1,210 @@
+/* $Id$
+ *
+ */
+
+#include "data_lump.h"
+#include "dprint.h"
+
+#include <stdlib.h>
+
+#ifdef DEBUG_DMALLOC
+#include <dmalloc.h>
+#endif
+
+
+
+/* adds a header to the end
+ * returns  pointer on success, 0 on error */
+struct lump* append_new_lump(struct lump** list, char* new_hdr,
+							 int len, int type)
+{
+	struct lump** t;
+	struct lump* tmp;
+	
+	for (t=list;*t;t=&((*t)->next));
+
+	tmp=malloc(sizeof(struct lump));
+	if (tmp==0){
+		LOG(L_ERR, "ERROR: append_new_lump: out of memory\n");
+		return 0;
+	}
+		
+	memset(tmp,0,sizeof(struct lump));
+	tmp->type=type;
+	tmp->op=LUMP_ADD;
+	tmp->u.value=new_hdr;
+	tmp->len=len;
+	*t=tmp;
+	return tmp;
+}
+
+
+
+/* inserts a header to the beginning 
+ * returns pointer if success, 0 on error */
+struct lump* insert_new_lump(struct lump** list, char* new_hdr,
+								int len, int type)
+{
+	struct lump* tmp;
+
+	tmp=malloc(sizeof(struct lump));
+	if (tmp==0){
+		LOG(L_ERR, "ERROR: insert_new_lump: out of memory\n");
+		return 0;
+	}
+	memset(tmp,0,sizeof(struct lump));
+	tmp->next=*list;
+	tmp->type=type;
+	tmp->op=LUMP_ADD;
+	tmp->u.value=new_hdr;
+	tmp->len=len;
+	*list=tmp;
+	return tmp;
+}
+
+
+
+/* inserts a  header/data lump immediately after hdr 
+ * returns pointer on success, 0 on error */
+struct lump* insert_new_lump_after( struct lump* after, char* new_hdr,
+							int len, int type)
+{
+	struct lump* tmp;
+
+	tmp=malloc(sizeof(struct lump));
+	if (tmp==0){
+		LOG(L_ERR, "ERROR: insert_new_lump_after: out of memory\n");
+		return 0;
+	}
+	memset(tmp,0,sizeof(struct lump));
+	tmp->after=after->after;
+	tmp->type=type;
+	tmp->op=LUMP_ADD;
+	tmp->u.value=new_hdr;
+	tmp->len=len;
+	after->after=tmp;
+	return tmp;
+}
+
+
+
+/* inserts a  header/data lump immediately before "before" 
+ * returns pointer on success, 0 on error */
+struct lump* insert_new_lump_before( struct lump* before, char* new_hdr,
+							int len, int type)
+{
+	struct lump* tmp;
+
+	tmp=malloc(sizeof(struct lump));
+	if (tmp==0){
+		LOG(L_ERR,"ERROR: insert_new_lump_before: out of memory\n");
+		return 0;
+	}
+	memset(tmp,0,sizeof(struct lump));
+	tmp->before=before->before;
+	tmp->type=type;
+	tmp->op=LUMP_ADD;
+	tmp->u.value=new_hdr;
+	tmp->len=len;
+	before->before=tmp;
+	return tmp;
+}
+
+
+
+/* removes an already existing header/data lump */
+struct lump* del_lump(struct lump** list, int offset, int len, int type)
+{
+	struct lump* tmp;
+	struct lump* prev, *t;
+
+	tmp=malloc(sizeof(struct lump));
+	if (tmp==0){
+		LOG(L_ERR, "ERROR: insert_new_lump_before: out of memory\n");
+		return 0;
+	}
+	memset(tmp,0,sizeof(struct lump));
+	tmp->op=LUMP_DEL;
+	tmp->type=type;
+	tmp->u.offset=offset;
+	tmp->len=len;
+	prev=0;
+	for (t=*list;t; prev=t, t=t->next){
+		/* insert it sorted after offset */
+		if (((t->op==LUMP_DEL)||(t->op==LUMP_NOP))&&(t->u.offset>offset))
+			break;
+	}
+	tmp->next=t;
+	if (prev) prev->next=tmp;
+	else *list=tmp;
+	return tmp;
+}
+
+
+
+/* add an anhor */
+struct lump* anchor_lump(struct lump** list, int offset, int len, int type)
+{
+	struct lump* tmp;
+	struct lump* prev, *t;
+
+	tmp=malloc(sizeof(struct lump));
+	if (tmp==0){
+		LOG(L_ERR, "ERROR: insert_new_lump_before: out of memory\n");
+		return 0;
+	}
+	memset(tmp,0,sizeof(struct lump));
+	tmp->op=LUMP_NOP;
+	tmp->type=type;
+	tmp->u.offset=offset;
+	tmp->len=len;
+	prev=0;
+	DBG("anchor: new tmp=%x\n", tmp);
+	for (t=*list;t; prev=t, t=t->next){
+		/* insert it sorted after offset */
+		if (((t->op==LUMP_DEL)||(t->op==LUMP_NOP))&&(t->u.offset>offset))
+			break;
+	}
+	DBG("anchor: inserting it between %x and %x (*list=%x)\n", prev, t,*list);
+	tmp->next=t;
+	
+	if (prev) prev->next=tmp;
+	else *list=tmp;
+	return tmp;
+}
+
+
+
+void free_lump(struct lump* lmp)
+{
+	DBG("- free_lump(%x), op=%d\n", lmp, lmp->op);
+	if (lmp && (lmp->op==LUMP_ADD)){
+		if (lmp->u.value) free(lmp->u.value);
+		lmp->u.value=0;
+		lmp->len=0;
+	}
+	DBG("- exiting free_lump(%x)\n", lmp);
+}
+
+
+
+void free_lump_list(struct lump* l)
+{
+	struct lump* t, *crt;
+	t=l;
+	DBG("+ free_lump_list(%x)\n", l);
+	while(t){
+		crt=t;
+		t=t->next;
+		DBG("free_lump_list: freeing %x\n", crt);
+		/* dangerous recursive clean*/
+		if (crt->before) free_lump_list(crt->before);
+		if (crt->after)  free_lump_list(crt->after);
+		DBG("free_lump_list: back from recursive calls (%x) \n", crt);
+		/*clean current elem*/
+		free_lump(crt);
+		free(crt);
+		DBG("after free_lump_list: %x\n", crt);
+	}
+	DBG("+ exiting free_lump_list(%x)\n", l);
+}

+ 76 - 0
data_lump.h

@@ -0,0 +1,76 @@
+/*
+ * $Id$
+ *
+ * adding/removing headers or any other data chunk from a message
+ */
+
+#ifndef data_lump_h
+#define data_lump_h
+
+
+enum { LUMP_NOP=0, LUMP_DEL, LUMP_ADD };
+
+struct lump{
+	int type; /* VIA, OTHER, UNSPEC(=0), ... */
+	int op;   /* DEL, ADD, NOP, UNSPEC(=0) */
+	
+	union{
+		int offset; /* used for DEL, MODIFY */
+		char * value; /* used for ADD */
+	}u;
+	int len; /* length of this header field */
+	
+	
+	struct lump* before; /* list of headers to be inserted in front of the
+								current one */
+	struct lump* after; /* list of headers to be inserted immediately after
+							  the current one */
+	
+	struct lump* next;
+};
+
+/*
+ * hdrs must be kept sorted after their offset (DEL, NOP, UNSPEC)
+ * and/or their position (ADD). E.g.:
+ *  - to delete header Z insert it in to the list according to its offset 
+ *   and with op=DELETE
+ * - if you want to add a new header X after a  header Y, insert Y in the list
+ *   with op NOP and after it X (op ADD).
+ * - if you want X before Y, insert X in Y's before list.
+ * - if you want X to be the first header just put it first in hdr_lst.
+ *  -if you want to replace Y with X, insert Y with op=DELETE and then X with
+ *  op=ADD.
+ * before and after must contain only ADD ops!
+ * 
+ * Difference between "after" & "next" when ADDing:
+ * "after" forces the new header immediately after the current one while
+ * "next" means another header can be inserted between them.
+ * 
+ */
+
+
+
+/* adds a header to the end */
+struct lump* append_new_lump(struct lump** list, char* new_hdr,
+							 int len, int type);
+/* inserts a header to the beginning */
+struct lump* insert_new_lump(struct lump** list, char* new_hdr,
+							  int len, int type);
+struct lump* insert_new_lump_after(struct lump* after,
+									char* new_hdr, int len, int type);
+struct lump* insert_new_lump_before(struct lump* before, char* new_hdr,
+									int len,int type);
+
+
+/* removes an already existing header */
+struct lump* del_lump(struct lump** list, int offset, int len, int type);
+/* set an anchor */
+struct lump* anchor_lump(struct lump** list, int offset, int len, int type);
+
+
+/* frees the content of a lump struct */
+void free_lump(struct lump* l);
+/*frees an entire lump list, recursively */
+void free_lump_list(struct lump* lump_list);
+
+#endif

+ 156 - 29
forward.c

@@ -19,6 +19,7 @@
 #include "dprint.h"
 #include "udp_server.h"
 #include "globals.h"
+#include "data_lump.h"
 
 #ifdef DEBUG_DMALLOC
 #include <dmalloc.h>
@@ -68,14 +69,16 @@ int check_address(unsigned long ip, char *name, int resolver)
 int forward_request( struct sip_msg* msg, struct proxy_l * p)
 {
 	unsigned int len, new_len, via_len, received_len, uri_len;
-	char line_buf[MAX_VIA_LINE_SIZE];
-	char received_buf[MAX_RECEIVED_SIZE];
+	char* line_buf;
+	char* received_buf;
 	char* new_buf;
 	char* orig;
 	char* buf;
 	unsigned int offset, s_offset, size;
 	struct sockaddr_in* to;
 	unsigned long source_ip;
+	struct lump *t,*r;
+	struct lump* anchor;
 
 	orig=msg->orig;
 	buf=msg->buf;
@@ -83,6 +86,8 @@ int forward_request( struct sip_msg* msg, struct proxy_l * p)
 	source_ip=msg->src_ip;
 	received_len=0;
 	new_buf=0;
+	line_buf=0;
+	received_buf=0;
 	to=0;
 	to=(struct sockaddr_in*)malloc(sizeof(struct sockaddr));
 	if (to==0){
@@ -90,20 +95,102 @@ int forward_request( struct sip_msg* msg, struct proxy_l * p)
 		goto error;
 	}
 
+	line_buf=malloc(sizeof(char)*MAX_VIA_LINE_SIZE);
+	if (line_buf==0){
+		LOG(L_ERR, "ERROR: forward_request: out of memory\n");
+		goto error1;
+	}
 	via_len=snprintf(line_buf, MAX_VIA_LINE_SIZE, "Via: SIP/2.0/UDP %s:%d\r\n",
 						names[0], port_no);
 	/* check if received needs to be added */
 	if (check_address(source_ip, msg->via1.host, received_dns)!=0){
+		received_buf=malloc(sizeof(char)*MAX_RECEIVED_SIZE);
+		if (received_buf==0){
+			LOG(L_ERR, "ERROR: forward_request: out of memory\n");
+			goto error1;
+		}
 		received_len=snprintf(received_buf, MAX_RECEIVED_SIZE,
 								";received=%s", 
 								inet_ntoa(*(struct in_addr *)&source_ip));
 	}
 	
-	new_len=len+via_len+received_len;
+	/* add via header to the list */
+	/* try to add it before msg. 1st via */
+	DBG("forward_request: before via\n");
+	/*add first via, as an anchor for second via*/
+	anchor=anchor_lump(&(msg->add_rm), msg->via1.hdr-buf, 0, HDR_VIA);
+	if (anchor==0) goto error;
+	if (insert_new_lump_before(anchor, line_buf, via_len, HDR_VIA)==0)
+		goto error;
+	/* if received needs to be added, add anchor after host and add it */
+	if (received_len){
+	DBG("forward_request: adding received\n");
+		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){
+					size+=strlen(msg->via1.hdr+size+1)+1; /* +1 for ':'*/
+				}
+		}
+		anchor=anchor_lump(&(msg->add_rm), msg->via1.hdr-buf+size, 0, HDR_VIA);
+		if (anchor==0) goto error;
+		if (insert_new_lump_after(anchor, received_buf, received_len, HDR_VIA) 
+				==0 ) goto error;
+	}
+	
+	
+	/* compute new msg len*/
+	new_len=len;
+	DBG("forward_request: computing new_len\n");
+	for(t=msg->add_rm;t;t=t->next){
+		DBG("forward_request: in for t.(%x)..\n", t);
+		for(r=t->before;r;r=r->before){
+		DBG("- forward_request: in for r...\n");
+			switch(r->op){
+				case LUMP_ADD:
+					new_len+=r->len;
+					break;
+				default:
+					/* only ADD allowed for before/after */
+					LOG(L_CRIT, "BUG:forward_request: invalid op for"
+								" data lump (%x)\n", r->op);
+			}
+		}
+		switch(t->op){
+			case LUMP_ADD:
+				new_len+=t->len;
+				break;
+			case LUMP_DEL:
+				new_len-=t->len;
+				break;
+			case LUMP_NOP:
+				/* do nothing */
+				break;
+			debug:
+				LOG(L_CRIT,"BUG:forward_request: invalid" 
+							" op for data lump (%x)\n", r->op);
+		}
+		for (r=t->after;r;r=r->after){
+		DBG("- forward_request: in for2 r...\n");
+			switch(r->op){
+				case LUMP_ADD:
+					new_len+=r->len;
+					break;
+				default:
+					/* only ADD allowed for before/after */
+					LOG(L_CRIT, "BUG:forward_request: invalid"
+								" op for data lump (%x)\n", r->op);
+			}
+		}
+	}
+	
+	
 	if (msg->new_uri){ 
 		uri_len=strlen(msg->new_uri); 
 		new_len=new_len-strlen(msg->first_line.u.request.uri)+uri_len;
 	}
+	DBG("forward_request: new_len=%d\n",new_len);
 	new_buf=(char*)malloc(new_len+1);
 	if (new_buf==0){
 		LOG(L_ERR, "ERROR: forward_request: out of memory\n");
@@ -122,33 +209,71 @@ int forward_request( struct sip_msg* msg, struct proxy_l * p)
 		offset+=uri_len;
 		s_offset+=strlen(msg->first_line.u.request.uri); /* skip original uri */
 	}
-/* copy msg till first via */
-	size=msg->via1.hdr-(buf+s_offset);
-	memcpy(new_buf+offset, orig+s_offset, size);
-	offset+=size;
-	s_offset+=size;
- /* add our via */
-	memcpy(new_buf+offset, line_buf, via_len);
-	offset+=via_len;
- /* modify original via if neccesarry (received=...)*/
-	if (received_len){
-		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){
-					size+=strlen(msg->via1.hdr+size+1)+1; /* +1 for ':'*/
+/* copy msg adding/removing lumps */
+	for (t=msg->add_rm;t;t=t->next){
+		DBG("adding/rming %x, op=%x, offset=%d\n", t, t->op, t->u.offset);
+		switch(t->op){
+			case LUMP_ADD:
+				/* just add it here! */
+				memcpy(new_buf+offset, t->u.value, t->len);
+				offset+=t->len;
+				break;
+			case LUMP_NOP:
+			case LUMP_DEL:
+				/* copy till offset */
+				if (s_offset>t->u.offset){
+					LOG(L_CRIT, "BUG: invalid offset in lump (%d)\n",
+								t->u.offset);
+					goto error;
+				}
+				size=t->u.offset-s_offset;
+				if (size){
+					memcpy(new_buf+offset, orig+s_offset,size);
+					offset+=size;
+					s_offset+=size;
+				}
+				/* process before  */
+				for(r=t->before;r;r=r->before){
+					switch (r->op){
+						case LUMP_ADD:
+							/*just add it here*/
+							memcpy(new_buf+offset, r->u.value, r->len);
+							offset+=r->len;
+							break;
+						defaut:
+							/* only ADD allowed for before/after */
+							LOG(L_CRIT, "BUG:forward_request: invalid op for"
+									" data lump (%x)\n", r->op);
+								
+					}
+				}
+				/* process main (del only) */
+				if (t->op==LUMP_DEL){
+					/* skip len bytes from orig msg */
+					s_offset+=t->len;
+				}
+				/* process after */
+				for(r=t->after;r;r=r->after){
+					switch (r->op){
+						case LUMP_ADD:
+							/*just add it here*/
+							memcpy(new_buf+offset, r->u.value, r->len);
+							offset+=r->len;
+							break;
+						default:
+							/* only ADD allowed for before/after */
+							LOG(L_CRIT, "BUG:forward_request: invalid op for"
+									" data lump (%x)\n", r->op);
+					}
 				}
+				break;
+			default:
+					LOG(L_CRIT, "BUG: forward_request: unknown op (%x)\n",
+							t->op);
 		}
-		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);
+	/* copy the rest of the message */
+	memcpy(new_buf+offset, orig+s_offset, len-s_offset);
 	new_buf[new_len]=0;
 
 	 /* send it! */
@@ -178,12 +303,15 @@ int forward_request( struct sip_msg* msg, struct proxy_l * p)
 
 	free(new_buf);
 	free(to);
+	/* received_buf & line_buf will be freed in receiv_msg by free_lump_list*/
 	return 0;
+error1:
+	if (line_buf) free(line_buf);
+	if (received_buf) free(received_buf);
 error:
 	if (new_buf) free(new_buf);
 	if (to) free(to);
 	return -1;
-
 }
 
 
@@ -276,7 +404,6 @@ int forward_reply(struct sip_msg* msg)
 	free(new_buf);
 	free(to);
 	return 0;
-
 error:
 	if (new_buf) free(new_buf);
 	if (to) free(to);

+ 0 - 50
mod_iface.h

@@ -1,50 +0,0 @@
-/*
- * $Id$
- *
- * interface for modules
- */
-
-#ifndef mod_iface_h
-#define mod_iface_h
-
-
-struct hdr_lst{
-	int type; /* VIA, OTHER, UNSPEC(=0), ... */
-	int op;   /* DEL, ADD, NOP, UNSPEC(=0) */
-	
-	union{
-		int offset; /* used for DEL, MODIFY */
-		char * value; /* used for ADD */
-	}u;
-	int len; /* length of this header field */
-	
-	
-	struct hdr_lst* before; /* list of headers to be inserted in front of the
-								current one */
-	struct hdr_lst* after; /* list of headers to be inserted immediately after
-							  the current one */
-	
-	struct hdr_lst* next;
-};
-
-/*
- * hdrs must be kept sorted after their offset (DEL, NOP, UNSPEC)
- * and/or their position (ADD). E.g.:
- *  - to delete header Z insert it in to the list according to its offset 
- *   and with op=DELETE
- * - if you want to add a new header X after a  header Y, insert Y in the list
- *   with op NOP and after it X (op ADD).
- * - if you want X before Y, insert X in Y's before list.
- * - if you want X to be the first header just put it first in hdr_lst.
- *  -if you want to replace Y with X, insert Y with op=DELETE and then X with
- *  op=ADD.
- * before and after must contain only ADD ops!
- * 
- * Difference between "after" & "next" when ADDing:
- * "after" forces the new header immediately after the current one while
- * "next" means another header can be inserted between them.
- * 
- */
-
-
-#endif

+ 5 - 0
msg_parser.h

@@ -6,6 +6,8 @@
 #define msg_parser_h
 
 
+#include "data_lump.h"
+
 #define SIP_REQUEST 1
 #define SIP_REPLY   2
 #define SIP_INVALID 0
@@ -75,6 +77,9 @@ struct sip_msg{
 
 	/* modifications */
 	char* new_uri; /* changed first line uri*/
+
+	struct lump* add_rm;      /* used for all the forwarded messages */
+	struct lump* repl_add_rm; /* only for localy generated replies !!!*/
 	
 };
 

+ 4 - 0
receive.c

@@ -72,10 +72,14 @@ int receive_msg(char* buf, unsigned int len, unsigned long src_ip)
 	}
 skip:
 	if (msg.new_uri) free(msg.new_uri);
+	if (msg.add_rm) free_lump_list(msg.add_rm);
+	if (msg.repl_add_rm) free_lump_list(msg.repl_add_rm);
 	free(msg.orig);
 	return 0;
 error:
 	if (msg.new_uri) free(msg.new_uri);
+	if (msg.add_rm) free_lump_list(msg.add_rm);
+	if (msg.repl_add_rm) free_lump_list(msg.repl_add_rm);
 	free(msg.orig);
 error1:
 	return -1;

+ 4 - 4
test/test-throughput.cfg

@@ -1,10 +1,10 @@
-debug=1			# for speed
+debug=9			# for speed
 check_via=0
 dns=off
 rev_dns=off
-fork=yes
-log_stderror=no
-children=64
+fork=no
+log_stderror=yes
+children=8
 
 route{