core: Fixes for WSS (secure WebSocket) transport and Via:s
[sip-router] / msg_translator.c
index 154c7fe..0447bfa 100644 (file)
 extern char version[];
 extern int version_len;
 
-/* global flags for build_req_from_sip_req */
-static unsigned int global_req_flags=0;
-
 
 
 /** per process fixup function for global_req_flags.
@@ -198,16 +195,20 @@ static int check_via_address(struct ip_addr* ip, str *name,
        struct hostent* he;
        int i;
        char* s;
+       #ifdef USE_IPV6
        int len;
+       #endif
 
        /* maybe we are lucky and name it's an ip */
        s=ip_addr2a(ip);
        if (s){
                DBG("check_via_address(%s, %.*s, %d)\n",
                        s, name->len, name->s, resolver);
-               len=strlen(s);
 
        #ifdef USE_IPV6
+
+               len=strlen(s);
+
                /* check if name->s is an ipv6 address or an ipv6 address ref. */
                if ((ip->af==AF_INET6) &&
                                (       ((len==name->len)&&(strncasecmp(name->s, s, name->len)==0))
@@ -582,6 +583,9 @@ static inline int lumps_len(struct sip_msg* msg, struct lump* lumps,
        struct lump* r;
        str* send_address_str;
        str* send_port_str;
+       str* recv_address_str = NULL;
+       str* recv_port_str = NULL;
+       int  recv_port_no = 0;
        struct socket_info* send_sock;
        
 
@@ -626,7 +630,7 @@ static inline int lumps_len(struct sip_msg* msg, struct lump* lumps,
                switch((subst_l)->u.subst){ \
                        case SUBST_RCV_IP: \
                                if (msg->rcv.bind_address){ \
-                                       new_len+=msg->rcv.bind_address->address_str.len; \
+                                       new_len+=recv_address_str->len; \
                                        if (msg->rcv.bind_address->address.af!=AF_INET) \
                                                new_len+=2; \
                                }else{ \
@@ -636,7 +640,7 @@ static inline int lumps_len(struct sip_msg* msg, struct lump* lumps,
                                break; \
                        case SUBST_RCV_PORT: \
                                if (msg->rcv.bind_address){ \
-                                       new_len+=msg->rcv.bind_address->port_no_str.len; \
+                                       new_len+=recv_port_str->len; \
                                }else{ \
                                        /* FIXME */ \
                                        LOG(L_CRIT, "FIXME: null bind_address\n"); \
@@ -647,13 +651,23 @@ static inline int lumps_len(struct sip_msg* msg, struct lump* lumps,
                                        switch(msg->rcv.bind_address->proto){ \
                                                case PROTO_NONE: \
                                                case PROTO_UDP: \
+                                                       new_len+=3; \
+                                                       break; \
                                                case PROTO_TCP: \
                                                case PROTO_TLS: \
-                                                               new_len+=3; \
-                                                               break; \
+                                                       switch(msg->rcv.proto){ \
+                                                               case PROTO_WS: \
+                                                               case PROTO_WSS: \
+                                                                       new_len+=2; \
+                                                                       break; \
+                                                               default: \
+                                                                       new_len+=3; \
+                                                                       break; \
+                                                       } \
+                                                       break; \
                                                case PROTO_SCTP: \
-                                                               new_len+=4; \
-                                                               break; \
+                                                       new_len+=4; \
+                                                       break; \
                                                default: \
                                                LOG(L_CRIT, "BUG: lumps_len: unknown proto %d\n", \
                                                                msg->rcv.bind_address->proto); \
@@ -665,25 +679,33 @@ static inline int lumps_len(struct sip_msg* msg, struct lump* lumps,
                                break; \
                        case SUBST_RCV_ALL: \
                                if (msg->rcv.bind_address){ \
-                                       new_len+=msg->rcv.bind_address->address_str.len; \
+                                       new_len+=recv_address_str->len; \
                                        if (msg->rcv.bind_address->address.af!=AF_INET) \
                                                new_len+=2; \
-                                       if (msg->rcv.bind_address->port_no!=SIP_PORT){ \
+                                       if (recv_port_no!=SIP_PORT){ \
                                                /* add :port_no */ \
-                                               new_len+=1+msg->rcv.bind_address->port_no_str.len; \
+                                               new_len+=1+recv_port_str->len; \
                                        }\
                                                /*add;transport=xxx*/ \
                                        switch(msg->rcv.bind_address->proto){ \
                                                case PROTO_NONE: \
                                                case PROTO_UDP: \
-                                                               break; /* udp is the default */ \
+                                                       break; /* udp is the default */ \
                                                case PROTO_TCP: \
                                                case PROTO_TLS: \
-                                                               new_len+=TRANSPORT_PARAM_LEN+3; \
-                                                               break; \
+                                                       switch(msg->rcv.proto){ \
+                                                               case PROTO_WS: \
+                                                               case PROTO_WSS: \
+                                                                       new_len+=TRANSPORT_PARAM_LEN+2; \
+                                                                       break; \
+                                                               default: \
+                                                                       new_len+=TRANSPORT_PARAM_LEN+3; \
+                                                                       break; \
+                                                       } \
+                                                       break; \
                                                case PROTO_SCTP: \
-                                                               new_len+=TRANSPORT_PARAM_LEN+4; \
-                                                               break; \
+                                                       new_len+=TRANSPORT_PARAM_LEN+4; \
+                                                       break; \
                                                default: \
                                                LOG(L_CRIT, "BUG: lumps_len: unknown proto %d\n", \
                                                                msg->rcv.bind_address->proto); \
@@ -718,13 +740,23 @@ static inline int lumps_len(struct sip_msg* msg, struct lump* lumps,
                                        switch(send_sock->proto){ \
                                                case PROTO_NONE: \
                                                case PROTO_UDP: \
+                                                       new_len+=3; \
+                                                       break; \
                                                case PROTO_TCP: \
                                                case PROTO_TLS: \
-                                                               new_len+=3; \
-                                                               break; \
+                                                       switch(send_info->proto){ \
+                                                               case PROTO_WS: \
+                                                               case PROTO_WSS: \
+                                                                       new_len+=2; \
+                                                                       break; \
+                                                               default: \
+                                                                       new_len+=3; \
+                                                                       break; \
+                                                       } \
+                                                       break; \
                                                case PROTO_SCTP: \
-                                                               new_len+=4; \
-                                                               break; \
+                                                       new_len+=4; \
+                                                       break; \
                                                default: \
                                                LOG(L_CRIT, "BUG: lumps_len: unknown proto %d\n", \
                                                                send_sock->proto); \
@@ -749,14 +781,22 @@ static inline int lumps_len(struct sip_msg* msg, struct lump* lumps,
                                        switch(send_sock->proto){ \
                                                case PROTO_NONE: \
                                                case PROTO_UDP: \
-                                                               break; /* udp is the default */ \
+                                                       break; /* udp is the default */ \
                                                case PROTO_TCP: \
                                                case PROTO_TLS: \
-                                                               new_len+=TRANSPORT_PARAM_LEN+3; \
-                                                               break; \
+                                                       switch(send_info->proto){ \
+                                                               case PROTO_WS: \
+                                                               case PROTO_WSS: \
+                                                                       new_len+=TRANSPORT_PARAM_LEN+2; \
+                                                                       break; \
+                                                               default: \
+                                                                       new_len+=TRANSPORT_PARAM_LEN+3; \
+                                                                       break; \
+                                                       } \
+                                                       break; \
                                                case PROTO_SCTP: \
-                                                               new_len+=TRANSPORT_PARAM_LEN+4; \
-                                                               break; \
+                                                       new_len+=TRANSPORT_PARAM_LEN+4; \
+                                                       break; \
                                                default: \
                                                LOG(L_CRIT, "BUG: lumps_len: unknown proto %d\n", \
                                                                send_sock->proto); \
@@ -783,15 +823,32 @@ static inline int lumps_len(struct sip_msg* msg, struct lump* lumps,
        s_offset=0;
        new_len=0;
        /* init send_address_str & send_port_str */
-       if (msg->set_global_address.len)
+       if(send_sock && send_sock->useinfo.name.len>0)
+               send_address_str=&(send_sock->useinfo.name);
+       else if (msg->set_global_address.len)
                send_address_str=&(msg->set_global_address);
        else
                send_address_str=&(send_sock->address_str);
-       if (msg->set_global_port.len)
+       if(send_sock && send_sock->useinfo.port_no>0)
+               send_port_str=&(send_sock->useinfo.port_no_str);
+       else if (msg->set_global_port.len)
                send_port_str=&(msg->set_global_port);
        else
                send_port_str=&(send_sock->port_no_str);
-
+       /* init recv_address_str, recv_port_str & recv_port_no */
+       if(msg->rcv.bind_address) {
+               if(msg->rcv.bind_address->useinfo.name.len>0)
+                       recv_address_str=&(msg->rcv.bind_address->useinfo.name);
+               else
+                       recv_address_str=&(msg->rcv.bind_address->address_str);
+               if(msg->rcv.bind_address->useinfo.port_no>0) {
+                       recv_port_str=&(msg->rcv.bind_address->useinfo.port_no_str);
+                       recv_port_no = msg->rcv.bind_address->useinfo.port_no;
+               } else {
+                       recv_port_str=&(msg->rcv.bind_address->port_no_str);
+                       recv_port_no = msg->rcv.bind_address->port_no;
+               }
+       }
 
        for(t=lumps;t;t=t->next){
                /* skip if this is an OPT lump and the condition is not satisfied */
@@ -901,6 +958,9 @@ static inline void process_lumps(   struct sip_msg* msg,
        int s_offset;
        str* send_address_str;
        str* send_port_str;
+       str* recv_address_str = NULL;
+       str* recv_port_str = NULL;
+       int  recv_port_no = 0;
        struct socket_info* send_sock;
 
 #ifdef USE_COMP
@@ -961,9 +1021,9 @@ static inline void process_lumps(  struct sip_msg* msg,
                                if (msg->rcv.bind_address->address.af!=AF_INET){\
                                        new_buf[offset]='['; offset++; \
                                }\
-                               memcpy(new_buf+offset, msg->rcv.bind_address->address_str.s, \
-                                               msg->rcv.bind_address->address_str.len); \
-                               offset+=msg->rcv.bind_address->address_str.len; \
+                               memcpy(new_buf+offset, recv_address_str->s, \
+                                               recv_address_str->len); \
+                               offset+=recv_address_str->len; \
                                if (msg->rcv.bind_address->address.af!=AF_INET){\
                                        new_buf[offset]=']'; offset++; \
                                }\
@@ -974,9 +1034,9 @@ static inline void process_lumps(  struct sip_msg* msg,
                        break; \
                case SUBST_RCV_PORT: \
                        if (msg->rcv.bind_address){  \
-                               memcpy(new_buf+offset, msg->rcv.bind_address->port_no_str.s, \
-                                               msg->rcv.bind_address->port_no_str.len); \
-                               offset+=msg->rcv.bind_address->port_no_str.len; \
+                               memcpy(new_buf+offset, recv_port_str->s, \
+                                               recv_port_str->len); \
+                               offset+=recv_port_str->len; \
                        }else{  \
                                /*FIXME*/ \
                                LOG(L_CRIT, "FIXME: process_lumps: null bind_address\n"); \
@@ -988,19 +1048,19 @@ static inline void process_lumps(        struct sip_msg* msg,
                                if (msg->rcv.bind_address->address.af!=AF_INET){\
                                        new_buf[offset]='['; offset++; \
                                }\
-                               memcpy(new_buf+offset, msg->rcv.bind_address->address_str.s, \
-                                               msg->rcv.bind_address->address_str.len); \
-                               offset+=msg->rcv.bind_address->address_str.len; \
+                               memcpy(new_buf+offset, recv_address_str->s, \
+                                               recv_address_str->len); \
+                               offset+=recv_address_str->len; \
                                if (msg->rcv.bind_address->address.af!=AF_INET){\
                                        new_buf[offset]=']'; offset++; \
                                }\
                                /* :port */ \
-                               if (msg->rcv.bind_address->port_no!=SIP_PORT){ \
+                               if (recv_port_no!=SIP_PORT){ \
                                        new_buf[offset]=':'; offset++; \
                                        memcpy(new_buf+offset, \
-                                                       msg->rcv.bind_address->port_no_str.s, \
-                                                       msg->rcv.bind_address->port_no_str.len); \
-                                       offset+=msg->rcv.bind_address->port_no_str.len; \
+                                                       recv_port_str->s, \
+                                                       recv_port_str->len); \
+                                       offset+=recv_port_str->len; \
                                }\
                                switch(msg->rcv.bind_address->proto){ \
                                        case PROTO_NONE: \
@@ -1010,15 +1070,25 @@ static inline void process_lumps(       struct sip_msg* msg,
                                                memcpy(new_buf+offset, TRANSPORT_PARAM, \
                                                                TRANSPORT_PARAM_LEN); \
                                                offset+=TRANSPORT_PARAM_LEN; \
-                                               memcpy(new_buf+offset, "tcp", 3); \
-                                               offset+=3; \
+                                               if (msg->rcv.proto == PROTO_WS) { \
+                                                       memcpy(new_buf+offset, "ws", 2); \
+                                                       offset+=2; \
+                                               } else { \
+                                                       memcpy(new_buf+offset, "tcp", 3); \
+                                                       offset+=3; \
+                                               } \
                                                break; \
                                        case PROTO_TLS: \
                                                memcpy(new_buf+offset, TRANSPORT_PARAM, \
                                                                TRANSPORT_PARAM_LEN); \
                                                offset+=TRANSPORT_PARAM_LEN; \
-                                               memcpy(new_buf+offset, "tls", 3); \
-                                               offset+=3; \
+                                               if (msg->rcv.proto == PROTO_WS || msg->rcv.proto == PROTO_WSS) { \
+                                                       memcpy(new_buf+offset, "ws", 2); \
+                                                       offset+=2; \
+                                               } else { \
+                                                       memcpy(new_buf+offset, "tls", 3); \
+                                                       offset+=3; \
+                                               } \
                                                break; \
                                        case PROTO_SCTP: \
                                                memcpy(new_buf+offset, TRANSPORT_PARAM, \
@@ -1097,15 +1167,25 @@ static inline void process_lumps(       struct sip_msg* msg,
                                                memcpy(new_buf+offset, TRANSPORT_PARAM, \
                                                                TRANSPORT_PARAM_LEN); \
                                                offset+=TRANSPORT_PARAM_LEN; \
-                                               memcpy(new_buf+offset, "tcp", 3); \
-                                               offset+=3; \
+                                               if (send_info->proto == PROTO_WS) { \
+                                                       memcpy(new_buf+offset, "ws", 2); \
+                                                       offset+=2; \
+                                               } else { \
+                                                       memcpy(new_buf+offset, "tcp", 3); \
+                                                       offset+=3; \
+                                               } \
                                                break; \
                                        case PROTO_TLS: \
                                                memcpy(new_buf+offset, TRANSPORT_PARAM, \
                                                                TRANSPORT_PARAM_LEN); \
                                                offset+=TRANSPORT_PARAM_LEN; \
-                                               memcpy(new_buf+offset, "tls", 3); \
-                                               offset+=3; \
+                                               if (send_info->proto == PROTO_WS || send_info->proto == PROTO_WSS) { \
+                                                       memcpy(new_buf+offset, "ws", 2); \
+                                                       offset+=2; \
+                                               } else { \
+                                                       memcpy(new_buf+offset, "tls", 3); \
+                                                       offset+=3; \
+                                               } \
                                                break; \
                                        case PROTO_SCTP: \
                                                memcpy(new_buf+offset, TRANSPORT_PARAM, \
@@ -1133,12 +1213,22 @@ static inline void process_lumps(       struct sip_msg* msg,
                                                offset+=3; \
                                                break; \
                                        case PROTO_TCP: \
-                                               memcpy(new_buf+offset, "tcp", 3); \
-                                               offset+=3; \
+                                               if (msg->rcv.proto == PROTO_WS) { \
+                                                       memcpy(new_buf+offset, "ws", 2); \
+                                                       offset+=2; \
+                                               } else { \
+                                                       memcpy(new_buf+offset, "tcp", 3); \
+                                                       offset+=3; \
+                                               } \
                                                break; \
                                        case PROTO_TLS: \
-                                               memcpy(new_buf+offset, "tls", 3); \
-                                               offset+=3; \
+                                               if (msg->rcv.proto == PROTO_WS || msg->rcv.proto == PROTO_WSS) { \
+                                                       memcpy(new_buf+offset, "ws", 2); \
+                                                       offset+=2; \
+                                               } else { \
+                                                       memcpy(new_buf+offset, "tls", 3); \
+                                                       offset+=3; \
+                                               } \
                                                break; \
                                        case PROTO_SCTP: \
                                                memcpy(new_buf+offset, "sctp", 4); \
@@ -1163,12 +1253,22 @@ static inline void process_lumps(       struct sip_msg* msg,
                                                offset+=3; \
                                                break; \
                                        case PROTO_TCP: \
-                                               memcpy(new_buf+offset, "tcp", 3); \
-                                               offset+=3; \
+                                               if (send_info->proto == PROTO_WS) { \
+                                                       memcpy(new_buf+offset, "ws", 2); \
+                                                       offset+=2; \
+                                               } else { \
+                                                       memcpy(new_buf+offset, "tcp", 3); \
+                                                       offset+=3; \
+                                               } \
                                                break; \
                                        case PROTO_TLS: \
-                                               memcpy(new_buf+offset, "tls", 3); \
-                                               offset+=3; \
+                                               if (send_info->proto == PROTO_WS || send_info->proto == PROTO_WSS) { \
+                                                       memcpy(new_buf+offset, "ws", 2); \
+                                                       offset+=2; \
+                                               } else { \
+                                                       memcpy(new_buf+offset, "tls", 3); \
+                                                       offset+=3; \
+                                               } \
                                                break; \
                                        case PROTO_SCTP: \
                                                memcpy(new_buf+offset, "sctp", 4); \
@@ -1203,7 +1303,33 @@ static inline void process_lumps(        struct sip_msg* msg,
                send_port_str=&(msg->set_global_port);
        else
                send_port_str=&(send_sock->port_no_str);
-
+       /* init send_address_str & send_port_str */
+       if(send_sock && send_sock->useinfo.name.len>0)
+               send_address_str=&(send_sock->useinfo.name);
+       else if (msg->set_global_address.len)
+               send_address_str=&(msg->set_global_address);
+       else
+               send_address_str=&(send_sock->address_str);
+       if(send_sock && send_sock->useinfo.port_no>0)
+               send_port_str=&(send_sock->useinfo.port_no_str);
+       else if (msg->set_global_port.len)
+               send_port_str=&(msg->set_global_port);
+       else
+               send_port_str=&(send_sock->port_no_str);
+       /* init recv_address_str, recv_port_str & recv_port_no */
+       if(msg->rcv.bind_address) {
+               if(msg->rcv.bind_address->useinfo.name.len>0)
+                       recv_address_str=&(msg->rcv.bind_address->useinfo.name);
+               else
+                       recv_address_str=&(msg->rcv.bind_address->address_str);
+               if(msg->rcv.bind_address->useinfo.port_no>0) {
+                       recv_port_str=&(msg->rcv.bind_address->useinfo.port_no_str);
+                       recv_port_no = msg->rcv.bind_address->useinfo.port_no;
+               } else {
+                       recv_port_str=&(msg->rcv.bind_address->port_no_str);
+                       recv_port_no = msg->rcv.bind_address->port_no;
+               }
+       }
 
        orig=msg->buf;
        offset=*new_buf_offs;
@@ -1908,7 +2034,7 @@ error:
 }
 
 
-char * build_res_buf_from_sip_req( unsigned int code, char *text ,str *new_tag,
+char * build_res_buf_from_sip_req( unsigned int code, str *text ,str *new_tag,
                struct sip_msg* msg, unsigned int *returned_len, struct bookmark *bmark)
 {
        char              *buf, *p;
@@ -1925,7 +2051,6 @@ char * build_res_buf_from_sip_req( unsigned int code, char *text ,str *new_tag,
        unsigned int      warning_len;
        char*             content_len_buf;
        unsigned int      content_len_len;
-       unsigned int      text_len;
        char *after_body;
        str  to_tag;
        char *totags;
@@ -1935,8 +2060,6 @@ char * build_res_buf_from_sip_req( unsigned int code, char *text ,str *new_tag,
        received_buf=rport_buf=warning_buf=content_len_buf=0;
        received_len=rport_len=warning_len=content_len_len=0;
 
-       text_len=strlen(text);
-
        to_tag.s=0;  /* fixes gcc 4.0 warning */
        to_tag.len=0;
 
@@ -1975,7 +2098,7 @@ char * build_res_buf_from_sip_req( unsigned int code, char *text ,str *new_tag,
 
        /* first line */
        len += msg->first_line.u.request.version.len + 1/*space*/ + 3/*code*/ + 1/*space*/ +
-               text_len + CRLF_LEN/*new line*/;
+               text->len + CRLF_LEN/*new line*/;
        /*headers that will be copied (TO, FROM, CSEQ,CALLID,VIA)*/
        for ( hdr=msg->headers ; hdr ; hdr=hdr->next ) {
                switch (hdr->type) {
@@ -2055,8 +2178,8 @@ char * build_res_buf_from_sip_req( unsigned int code, char *text ,str *new_tag,
                *(p+i) = '0' + foo - ( foo/10 )*10;
        p += 3;
        *(p++) = ' ' ;
-       memcpy( p , text , text_len );
-       p += text_len;
+       memcpy( p , text->s , text->len );
+       p += text->len;
        memcpy( p, CRLF, CRLF_LEN );
        p+=CRLF_LEN;
        /* headers*/
@@ -2277,22 +2400,33 @@ char* via_builder( unsigned int *len,
        str* port_str; /* port no displayed in via */
        struct socket_info* send_sock;
        int comp_len, comp_name_len;
+#ifdef USE_COMP
        char* comp_name;
+#endif /* USE_COMP */
+       int port;
+       struct ip_addr ip;
+       union sockaddr_union *from = NULL;
+       union sockaddr_union local_addr;
+       struct tcp_connection *con = NULL;
 
        send_sock=send_info->send_sock;
-       /* use pre-set address in via or the outbound socket one */
-       if ( hp && hp->host->len)
+       /* use pre-set address in via, the outbound socket alias or address one */
+       if (hp && hp->host->len)
                address_str=hp->host;
+       else if(send_sock->useinfo.name.len>0)
+               address_str=&(send_sock->useinfo.name);
        else
                address_str=&(send_sock->address_str);
        if (hp && hp->port->len)
                port_str=hp->port;
+       else if(send_sock->useinfo.port_no>0)
+               port_str=&(send_sock->useinfo.port_no_str);
        else
                port_str=&(send_sock->port_no_str);
        
        comp_len=comp_name_len=0;
-       comp_name=0;
 #ifdef USE_COMP
+       comp_name=0;
        switch(send_info->comp){
                case COMP_NONE:
                        break;
@@ -2341,6 +2475,41 @@ char* via_builder( unsigned int *len,
                memcpy(line_buf+MY_VIA_LEN-4, "TLS ", 4);
        }else if (send_info->proto==PROTO_SCTP){
                memcpy(line_buf+MY_VIA_LEN-4, "SCTP ", 5);
+       }else if (send_info->proto==PROTO_WS){
+                if (unlikely(send_info->send_flags.f & SND_F_FORCE_SOCKET
+                                && send_info->send_sock)) {
+                        local_addr = send_info->send_sock->su;
+                        su_setport(&local_addr, 0); /* any local port will do */
+                        from = &local_addr;
+                }
+
+                port = su_getport(&send_info->to);
+                if (likely(port)) {
+                        su2ip_addr(&ip, &send_info->to);
+                        con = tcpconn_get(send_info->id, &ip, port, from, 0);
+                }
+                else if (likely(send_info->id))
+                        con = tcpconn_get(send_info->id, 0, 0, 0, 0);
+                else {
+                        LM_CRIT("BUG: via_builder called with null_id & to\n");
+                        return 0;
+                }
+
+                if (con == NULL) {
+                        LM_WARN("TCP/TLS connection for WebSocket could not be found\n");
+                        return 0;
+                }
+
+               if (con->rcv.proto==PROTO_WS) {
+                       memcpy(line_buf+MY_VIA_LEN-4, "WS ", 3);
+               } else if (con->rcv.proto==PROTO_WSS) {
+                       memcpy(line_buf+MY_VIA_LEN-4, "WSS ", 4);
+               } else {
+                       LOG(L_CRIT, "BUG: via_builder: unknown proto %d\n", con->rcv.proto);
+                       return 0;
+               }
+       }else if (send_info->proto==PROTO_WSS){
+               memcpy(line_buf+MY_VIA_LEN-4, "WSS ", 4);
        }else{
                LOG(L_CRIT, "BUG: via_builder: unknown proto %d\n", send_info->proto);
                return 0;