2 * $Id: parse_via.c,v 1.23.2.2 2005/07/20 17:11:52 andrei Exp $
4 * via parsing automaton
7 * Copyright (C) 2001-2003 FhG Fokus
9 * This file is part of ser, a free SIP server.
11 * ser is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version
16 * For a license to use the ser software under conditions
17 * other than those described here, or to purchase support for this
18 * software, please contact iptel.org by e-mail at the following addresses:
21 * ser is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
34 * 2003-01-21 added rport parsing code, contributed by
35 * Maxim Sobolev <sobomax@FreeBSD.org>
36 * 2003-01-23 added extra via param parsing code (i=...), used
37 * by tcp to identify the sending socket, by andrei
38 * 2003-01-23 fixed rport parsing code to accept rport w/o any value,
40 * 2003-01-27 modified parse_via to set new via_param->start member and
41 * via->params.s (andrei)
42 * 2003-01-28 zero-terminations replaced with VIA_ZT (jiri)
43 * 2003-02-28 scratchpad compatibility abandoned (jiri)
44 * 2003-04-26 ZSW (jiri)
45 * 2003-06-23 fixed parse_via_param [op].* param. parsing bug (andrei)
46 * 2003-07-02 added support for TLS parsing in via (andrei)
47 * 2003-10-27 added support for alias via param parsing [see
48 * draft-ietf-sip-connect-reuse-00.txt.] (andrei)
49 * 2004-03-31 fixed rport set instead of i bug (andrei)
50 * 2005-03-02 if via has multiple bodies, and one of them is bad set
51 * also the first one as bad (andrei)
56 #include "../comp_defs.h"
59 #include "../dprint.h"
61 #include "../mem/mem.h"
62 #include "../ip_addr.h"
63 #include "parse_via.h"
64 #include "parse_def.h"
68 /* main via states (uri:port ...) */
71 L_PORT, F_PORT, P_PORT,
72 L_PARAM, F_PARAM, P_PARAM,
83 /* first via part state */
90 TCP_TLS1, TCP2, FIN_TCP,
96 /* param related states
97 * WARNING: keep in sync with parse_via.h, PARAM_HIDDEN, ...
100 L_VALUE = 200, F_VALUE, P_VALUE, P_STRING,
101 HIDDEN1, HIDDEN2, HIDDEN3, HIDDEN4, HIDDEN5,
103 BRANCH1, BRANCH2, BRANCH3, BRANCH4, BRANCH5,
104 MADDR1, MADDR2, MADDR3, MADDR4,
105 RECEIVED1, RECEIVED2, RECEIVED3, RECEIVED4, RECEIVED5, RECEIVED6,
107 RPORT1, RPORT2, RPORT3,
108 ALIAS1, ALIAS2, ALIAS3, ALIAS4,
109 /* fin states (227-...)*/
110 FIN_HIDDEN = 230, FIN_TTL, FIN_BRANCH,
111 FIN_MADDR, FIN_RECEIVED, FIN_RPORT, FIN_I, FIN_ALIAS
113 PARAM_ERROR*/ /* declared in msg_parser.h*/
117 /* entry state must be F_PARAM, or saved_state=F_PARAM and
118 * state=F_{LF,CR,CRLF}!
119 * output state = L_PARAM or F_PARAM or END_OF_HEADER
120 * (and saved_state= last state); everything else => error
121 * WARNING: param->start must be filled before, it's used in param->size
124 static /*inline*/ char* parse_via_param(char* p, char* end,
125 unsigned char* pstate,
126 unsigned char* psaved_state,
127 struct via_param* param)
130 register unsigned char state;
131 unsigned char saved_state;
134 saved_state=*psaved_state;
135 param->type=PARAM_ERROR;
137 for (tmp=p;tmp<end;tmp++){
145 param->name.len=tmp-param->name.s;
155 param->name.len=tmp-param->name.s;
167 param->type=GEN_PARAM;
168 param->name.len=tmp-param->name.s;
179 param->name.len=tmp-param->name.s;
180 param->size=tmp-param->start;
191 param->name.len=tmp-param->name.s;
192 param->size=tmp-param->start;
209 param->type=GEN_PARAM;
211 param->name.len=tmp-param->name.s;
212 param->size=tmp-param->start;
222 param->name.len=tmp-param->name.s;
223 param->size=tmp-param->start;
234 param->name.len=tmp-param->name.s;
235 param->size=tmp-param->start;
249 param->type=GEN_PARAM;
250 param->name.len=tmp-param->name.s;
251 param->size=tmp-param->start;
267 param->name.len=tmp-param->name.s;
273 LOG(L_ERR, "ERROR: parse_via: invalid char <%c> in"
274 " state %d\n", *tmp, state);
283 param->type=GEN_PARAM;
284 param->name.len=tmp-param->name.s;
292 case FIN_RPORT: /* rport can appear w/o a value */
295 param->name.len=tmp-param->name.s;
303 LOG(L_ERR, "ERROR: parse_via: invalid char <%c> in"
304 " state %d\n", *tmp, state);
313 param->type=GEN_PARAM;
314 param->name.len=tmp-param->name.s;
325 param->name.len=tmp-param->name.s;
333 LOG(L_ERR, "ERROR: parse_via_param: new via found"
334 "(',') when '=' expected (state %d=)\n",
336 goto error; /* or we could ignore this bad param*/
344 param->type=GEN_PARAM;
345 param->name.len=tmp-param->name.s;
746 /* end of packet? => error, no cr/lf,',' found!!!*/
759 case F_VALUE: /*eat space*/
763 param->value.len=tmp-param->value.s;
773 LOG(L_ERR, "ERROR: parse_via: invalid char <%c>"
774 " in state %d\n", *tmp, state);
781 case F_VALUE: /*eat space*/
784 param->size=tmp-param->start;
790 param->value.len=tmp-param->value.s;
800 LOG(L_ERR, "ERROR: parse_via: invalid char <%c>"
801 " in state %d\n", *tmp, state);
808 case F_VALUE: /*eat space*/
811 param->size=tmp-param->start;
815 param->value.len=tmp-param->value.s;
825 LOG(L_ERR, "ERROR: parse_via: invalid char <%c>"
826 " in state %d\n", *tmp, state);
844 LOG(L_ERR, "ERROR: parse_via: invalid char <%c>"
845 " in state %d\n", *tmp, state);
852 param->value.len=tmp-param->value.s;
860 break; /* what to do? */
867 if (param->type==FIN_RPORT){
869 param->value.s=0; /* null value */
875 LOG(L_ERR, "ERROR: parse_via: invalid char <%c>"
876 " in state %d\n", *tmp, state);
883 param->value.len=tmp-param->value.s;
893 if (param->type==FIN_RPORT){
895 param->value.s=0; /* null value */
901 LOG(L_ERR, "ERROR: parse_via: invalid char <%c>"
902 " in state %d\n", *tmp, state);
905 break; /* what to do? */
910 param->value.s=tmp+1;
914 param->value.len=tmp-param->value.s;
922 LOG(L_ERR, "ERROR: parse_via: invalid char <%c>"
923 " in state %d\n", *tmp, state);
942 LOG(L_ERR, "ERROR: parse_via: invalid char <%c>"
943 " in state %d\n", *tmp, state);
949 /* end of buff and no CR/LF =>error*/
956 param->size=tmp-param->start;
959 *psaved_state=saved_state;
960 DBG("Found param type %d, <%.*s> = <%.*s>; state=%d\n", param->type,
961 param->name.len, ZSW(param->name.s),
962 (param->value.len?param->value.len:3),
963 (param->value.len?param->value.s:"n/a"), state);
967 /* if we are here we found an "unexpected" end of via
968 * (cr/lf). This is valid only if the param type is GEN_PARAM or
969 * RPORT (the only ones which can miss the value; HIDDEN is a
971 if ((param->type==GEN_PARAM)||(param->type==PARAM_RPORT)){
972 saved_state=L_PARAM; /* change the saved_state, we have an unknown
973 param. w/o a value */
974 /* param->size should be computed before */
978 *psaved_state=saved_state;
979 DBG("Error on param type %d, <%.*s>, state=%d, saved_state=%d\n",
980 param->type, param->name.len, ZSW(param->name.s), state, saved_state);
983 LOG(L_ERR, "error: parse_via_param\n");
984 param->type=PARAM_ERROR;
993 * call it with a vb initialized to 0
994 * returns: pointer after the parsed parts and sets vb->error
995 * WARNING: don't forget to cleanup on error with free_via_list(vb)!
997 char* parse_via(char* buffer, char* end, struct via_body *vbody)
1001 unsigned char state;
1002 unsigned char saved_state;
1005 struct via_body* vb;
1006 struct via_param* param;
1008 vb=vbody; /* keep orignal vbody value, needed to set the error member
1009 in case of multiple via bodies in the same header */
1011 vb->error=PARSE_ERROR;
1012 /* parse start of via ( SIP/2.0/UDP )*/
1014 saved_state=F_SIP; /* fixes gcc 4.0 warning */
1016 for(tmp=buffer;tmp<end;tmp++){
1021 case L_VER: /* eat space */
1028 vb->transport.len=tmp-vb->transport.s;
1029 vb->proto=PROTO_UDP;
1030 state=F_HOST; /* start looking for host*/
1033 /* finished proto parsing */
1034 vb->transport.len=tmp-vb->transport.s;
1035 vb->proto=PROTO_TCP;
1036 state=F_HOST; /* start looking for host*/
1039 /* finished proto parsing */
1040 vb->transport.len=tmp-vb->transport.s;
1041 vb->proto=PROTO_TLS;
1042 state=F_HOST; /* start looking for host*/
1045 vb->name.len=tmp-vb->name.s;
1049 vb->version.len=tmp-vb->version.s;
1054 case F_CR: /* header continues on this line */
1058 LOG(L_ERR, "ERROR: parse_via: bad char <%c> on"
1059 " state %d\n", *tmp, state);
1074 vb->transport.len=tmp-vb->transport.s;
1075 vb->proto=PROTO_UDP;
1077 saved_state=F_HOST; /* start looking for host*/
1080 vb->transport.len=tmp-vb->transport.s;
1081 vb->proto=PROTO_TCP;
1083 saved_state=F_HOST; /* start looking for host*/
1086 vb->transport.len=tmp-vb->transport.s;
1087 vb->proto=PROTO_TLS;
1089 saved_state=F_HOST; /* start looking for host*/
1092 vb->name.len=tmp-vb->name.s;
1097 vb->version.len=tmp-vb->version.s;
1099 saved_state=L_PROTO;
1109 LOG(L_ERR, "ERROR: parse_via: bad char <%c> on"
1110 " state %d\n", *tmp, state);
1125 vb->transport.len=tmp-vb->transport.s;
1126 vb->proto=PROTO_UDP;
1131 vb->transport.len=tmp-vb->transport.s;
1132 vb->proto=PROTO_TCP;
1137 vb->transport.len=tmp-vb->transport.s;
1138 vb->proto=PROTO_TLS;
1143 vb->name.len=tmp-vb->name.s;
1148 vb->version.len=tmp-vb->version.s;
1150 saved_state=L_PROTO;
1152 case F_LF: /*end of line ?next header?*/
1158 LOG(L_ERR, "ERROR: parse_via: bad char <%c> on"
1159 " state %d\n", *tmp, state);
1167 vb->name.len=tmp-vb->name.s;
1171 vb->version.len=tmp-vb->version.s;
1181 LOG(L_ERR, "ERROR: parse_via: bad char <%c> on"
1182 " state %d\n", *tmp, state);
1198 LOG(L_ERR, "ERROR: parse_via: bad char <%c> on"
1199 " state %d\n", *tmp, state);
1210 LOG(L_ERR, "ERROR: parse_via: bad char <%c> on"
1211 " state %d\n", *tmp, state);
1221 /* allow p in PROTO */
1229 LOG(L_ERR, "ERROR: parse_via: bad char <%c> on"
1230 " state %d\n", *tmp, state);
1239 vb->transport.s=tmp;
1242 LOG(L_ERR, "ERROR: parse_via: bad char <%c> on"
1243 " state %d\n", *tmp, state);
1254 LOG(L_ERR, "ERROR: parse_via: bad char <%c> on"
1255 " state %d\n", *tmp, state);
1264 vb->transport.s=tmp;
1267 LOG(L_ERR, "ERROR: parse_via: bad char <%c> on"
1268 " state %d\n", *tmp, state);
1279 LOG(L_ERR, "ERROR: parse_via: bad char <%c> on"
1280 " state %d\n", *tmp, state);
1291 LOG(L_ERR, "ERROR: parse_via: bad char <%c> on"
1292 " state %d\n", *tmp, state);
1304 LOG(L_ERR, "ERROR: parse_via: bad char <%c> on"
1305 " state %d\n", *tmp, state);
1315 LOG(L_ERR, "ERROR: parse_via: bad char <%c> on"
1316 " state %d\n", *tmp, state);
1326 LOG(L_ERR, "ERROR: parse_via: bad char <%c> on"
1327 " state %d\n", *tmp, state);
1333 LOG(L_ERR, "ERROR: parse_via: bad char <%c> on"
1334 " state %d\n", *tmp, state);
1340 /* we should not be here! if everything is ok > main_via*/
1341 LOG(L_ERR, "ERROR: parse_via: bad via: end of packet on state=%d\n",
1346 /* inc tmp to point to the next char*/
1349 /*state should always be F_HOST here*/;
1355 case F_HOST:/*eat the spaces*/
1358 /*mark end of host*/
1359 vb->host.len=tmp-vb->host.s;
1362 case L_PORT: /*eat the spaces*/
1367 vb->port_str.len=tmp-vb->port_str.s;
1370 case L_PARAM: /* eat the space */
1374 /* *tmp=0;*/ /*!?end of param*/
1378 case F_VIA: /* eat the space */
1383 case F_IP6HOST: /*no spaces allowed*/
1385 LOG(L_ERR, "ERROR:parse_via: bad ipv6 reference\n");
1390 /*previous=crlf and now =' '*/
1394 LOG(L_CRIT,"BUG: parse_via"
1395 " on <%c>, state=%d\n",*tmp, state);
1401 case F_HOST:/*eat the spaces*/
1402 case L_PORT: /*eat the spaces*/
1404 case L_PARAM: /* eat the space */
1406 case F_VIA: /* eat the space */
1416 /*mark end of host*/
1417 vb->host.len=tmp-vb->host.s;
1423 vb->port_str.len=tmp-vb->port_str.s;
1424 saved_state=L_PARAM;
1428 /* *tmp=0;*/ /*!?end of param*/
1429 saved_state=L_PARAM;
1440 LOG(L_CRIT,"BUG: parse_via"
1447 case F_HOST:/*eat the spaces*/
1448 case L_PORT: /*eat the spaces*/
1450 case L_PARAM: /* eat the space */
1452 case F_VIA: /* eat the space */
1462 /*mark end of host*/
1463 vb->host.len=tmp-vb->host.s;
1469 vb->port_str.len=tmp-vb->port_str.s;
1470 saved_state=L_PARAM;
1474 /* *tmp=0;*/ /*!?end of param*/
1475 saved_state=L_PARAM;
1484 LOG(L_CRIT,"BUG: parse_via"
1499 /*mark end of host*/
1500 vb->host.len=tmp-vb->host.s;
1507 LOG(L_ERR, "ERROR:parse_via:"
1513 LOG(L_ERR, "ERROR:parse_via:"
1514 " bad char <%c> in state %d\n",
1519 LOG(L_ERR, "ERROR:parse_via:"
1520 " bad char in compact via\n");
1525 /*previous=crlf and now !=' '*/
1527 case F_COMMENT:/*everything is allowed in a comment*/
1531 case P_COMMENT: /*everything is allowed in a comment*/
1534 LOG(L_CRIT,"BUG: parse_via"
1535 " on <%c> state %d\n",
1544 LOG(L_ERR,"ERROR:parse_via:"
1545 " no host found\n");
1548 LOG(L_ERR, "ERROR:parse_via: bad ipv6 reference\n");
1551 vb->host.len=tmp-vb->host.s;
1557 vb->port_str.len=tmp-vb->port_str.s;
1564 LOG(L_ERR, "ERROR:parse_via:"
1565 " bad char <%c> in state %d\n",
1569 LOG(L_ERR, "ERROR:parse_via:"
1573 /*hmm next, param?*/
1579 LOG(L_ERR, "ERROR:parse_via:"
1580 " bad char <%c> in next via\n",
1586 /*previous=crlf and now !=' '*/
1588 case F_COMMENT:/*everything is allowed in a comment*/
1592 case P_COMMENT: /*everything is allowed in a comment*/
1596 LOG(L_CRIT,"BUG: parse_via"
1597 " on <%c> state %d\n",
1606 LOG(L_ERR,"ERROR:parse_via:"
1607 " no host found\n");
1610 LOG(L_ERR, "ERROR:parse_via: bad ipv6 reference\n");
1614 vb->host.len=tmp-vb->host.s;
1619 vb->port_str.len=tmp-vb->port_str.s;
1630 LOG(L_ERR, "ERROR:parse_via:"
1631 " invalid char <%c> in state"
1632 " %d\n", *tmp,state);
1635 /* do nothing, eat ","*/
1640 /*previous=crlf and now !=' '*/
1642 case F_COMMENT:/*everything is allowed in a comment*/
1646 case P_COMMENT: /*everything is allowed in a comment*/
1649 LOG(L_CRIT,"BUG: parse_via"
1650 " on <%c> state %d\n",
1662 case P_IP6HOST: /*must be terminated in ']'*/
1663 LOG(L_ERR,"ERROR:parse_via"
1664 " on <%c> state %d\n",
1669 vb->host.len=tmp-vb->host.s;
1675 vb->port_str.len=tmp-vb->port_str.s;
1681 vb->params.len=tmp-vb->params.s;
1689 vb->params.len=tmp-vb->params.s;
1699 /*previous=crlf and now !=' '*/
1702 LOG(L_CRIT,"BUG: parse_via"
1703 " on <%c> state %d\n",
1716 vb->comment.len=tmp-vb->comment.s;
1740 LOG(L_ERR,"ERROR:parse_via"
1741 " on <%c> state %d\n",
1747 /*previous=crlf and now !=' '*/
1750 LOG(L_CRIT,"BUG: parse_via"
1751 " on <%c> state %d\n",
1759 vb->host.s=tmp; /* mark start here (include [])*/
1762 case F_COMMENT:/*everything is allowed in a comment*/
1771 /*previous=crlf and now !=' '*/
1774 LOG(L_ERR,"ERROR:parse_via"
1775 " on <%c> state %d\n",
1784 vb->host.len=(tmp-vb->host.s)+1; /* include "]" */
1790 /*previous=crlf and now !=' '*/
1792 case F_COMMENT:/*everything is allowed in a comment*/
1799 LOG(L_ERR,"ERROR:parse_via"
1800 " on <%c> state %d\n",
1819 /*check if number?*/
1823 if(vb->params.s==0) vb->params.s=param_start;
1824 param=pkg_malloc(sizeof(struct via_param));
1826 LOG(L_ERR, "ERROR:parse_via: mem. allocation"
1830 memset(param,0, sizeof(struct via_param));
1831 param->start=param_start;
1832 tmp=parse_via_param(tmp, end, &state, &saved_state,
1843 vb->params.len=param->start+param->size
1847 vb->params.len=param->start+param->size
1855 LOG(L_ERR, "ERROR: parse_via after"
1856 " parse_via_param: invalid"
1857 " char <%c> on state %d\n",
1861 /*add param to the list*/
1862 if (vb->last_param) vb->last_param->next=param;
1863 else vb->param_lst=param;
1864 vb->last_param=param;
1865 /* update param. shortcuts */
1866 switch(param->type){
1870 case PARAM_RECEIVED:
1884 if (state==END_OF_HEADER){
1892 /*vb->next=tmp;*/ /*???*/
1897 LOG(L_ERR,"ERROR:parse_via"
1898 " on <%c> state %d (default)\n",
1915 /*previous=crlf and now !=' '*/
1918 LOG(L_ERR, "BUG:parse_via:"
1919 " invalid char <%c>"
1929 DBG("end of packet reached, state=%d\n", state);
1930 goto endofpacket; /*end of packet, probably should be goto error*/
1934 DBG("end of header reached, state=%d\n", state);
1949 LOG(L_ERR, "ERROR: parse_via: invalid via - end of header in"
1950 " state %d\n", state);
1956 if (proto) printf("<SIP/2.0/%s>\n", proto);
1957 if (host) printf("host= <%s>\n", host);
1958 if (port_str) printf("port= <%s>\n", port_str);
1959 if (param) printf("params= <%s>\n", param);
1960 if (comment) printf("comment= <%s>\n", comment);
1961 if(next_via) printf("next_via= <%s>\n", next_via);
1963 /*DBG("parse_via: rest=<%s>\n", tmp);*/
1966 vb->bsize=tmp-buffer;
1967 if (vb->port_str.s){
1968 vb->port=str2s(vb->port_str.s, vb->port_str.len, &err);
1970 LOG(L_ERR, "ERROR: parse_via: invalid port number <%.*s>\n",
1971 vb->port_str.len, ZSW(vb->port_str.s));
1977 DBG("parse_via: next_via\n");
1979 vb->bsize=tmp-buffer;
1980 if (vb->port_str.s){
1981 vb->port=str2s(vb->port_str.s, vb->port_str.len, &err);
1983 LOG(L_ERR, "ERROR: parse_via: invalid port number <%.*s>\n",
1984 vb->port_str.len, ZSW(vb->port_str.s));
1988 vb->next=pkg_malloc(sizeof(struct via_body));
1990 LOG(L_ERR, "ERROR: parse_via: out of memory\n");
1994 memset(vb, 0, sizeof(struct via_body));
2000 LOG(L_ERR, "ERROR: parse_via on: <%.*s>\n", (int)(end-buffer), ZSW(buffer));
2002 if ((tmp>buffer)&&(tmp<end)){
2003 LOG(L_ERR, "ERROR: parse_via parse error, parsed so far:<%.*s>\n",
2004 (int)(tmp-buffer), ZSW(buffer) );
2006 LOG(L_ERR, "ERROR: parse_via: via parse error\n");
2008 vb->error=PARSE_ERROR;
2009 vbody->error=PARSE_ERROR; /* make sure the first via body is marked
2015 static inline void free_via_param_list(struct via_param* vp)
2017 struct via_param* foo;
2026 void free_via_list(struct via_body* vb)
2028 struct via_body* foo;
2032 if (foo->param_lst) free_via_param_list(foo->param_lst);