/** * Add old IE support (Compatibility View) for POST requests by forcing a 2nd read on the * server socket, to make IE send the POST body. * Tests revealed that this mode does not change the behaviour for recent browser. Therefore, * it can be used all the time. Option -i allows to disable it. * * @return 0 if successful, -1 otherwise */ int ie_compat_read_post_body(sock_t sock, request_t* req, proxenet_ssl_context_t* sslctx) { int nb; size_t old_len, body_len; char *body, *clen; /* to speed-up, disregard requests without body */ if (strcmp(req->http_infos.method, "POST")!=0 && \ strcmp(req->http_infos.method, "PUT")!=0) return 0; /* read Content-Length header */ clen = get_header_by_name(req->data, "Content-Length: "); if (!clen){ xlog(LOG_ERROR, "%s\n", "Extending IE POST: No Content-Length"); return -1; } /* if Content-Length is zero */ body_len = (size_t)atoi(clen); proxenet_xfree(clen); if (body_len==0){ return 0; } /* if everything has already been sent (i.e. end of already received buffer is not CRLF*2) */ if (req->data[ req->size-4 ] != '\r') return 0; if (req->data[ req->size-3 ] != '\n') return 0; if (req->data[ req->size-2 ] != '\r') return 0; if (req->data[ req->size-1 ] != '\n') return 0; /* read data (if any) */ nb = proxenet_read_all(sock, &body, sslctx); if (nb<0){ xlog(LOG_ERROR, "%s\n", "Extending IE POST: failed to read"); return -1; } /* and extend the request buffer */ if (nb>0){ old_len = req->size; req->size = old_len + (size_t)nb; req->data = proxenet_xrealloc(req->data, req->size); memcpy(req->data + old_len, body, (size_t)nb); } proxenet_xfree(body); #ifdef DEBUG xlog(LOG_DEBUG, "Extending request for IE: new_size=%d (content-length=%d)\n", req->size, body_len); #endif return 0; }
/* * Get OSP token from SIP message * param msg SIP message * param token OSP authorization token * param tokensize Size of OSP authorization token * return 0 success, -1 failure */ int ospGetOspHeader( struct sip_msg* msg, unsigned char* token, unsigned int* tokensize) { struct hdr_field* hf; int errorcode; int result = -1; if (parse_headers(msg, HDR_EOH_F, 0) != 0) { LM_ERR("failed to parse all headers\n"); } else { hf = get_header_by_name(msg, OSP_TOKEN_HEADER, OSP_HEADER_SIZE); if (hf) { if ((errorcode = OSPPBase64Decode(hf->body.s, hf->body.len, token, tokensize)) == OSPC_ERR_NO_ERROR) { result = 0; } else { LM_ERR("failed to base64 decode token (%d)\n", errorcode); LM_ERR("header '%.*s' length %d\n", hf->body.len, hf->body.s, hf->body.len); } } } return result; }
/*! \brief */ static int set_sock_hdr(struct sip_msg *msg, ucontact_info_t *ci, unsigned int reg_flags) { struct socket_info *sock; struct hdr_field *hf; str socks; str hosts; int port; int proto; if (!msg || !(reg_flags & REG_SAVE_SOCKET_FLAG)) return 1; if (parse_headers( msg, HDR_EOH_F, 0) == -1) { LM_ERR("failed to parse message\n"); return 1; } hf = get_header_by_name( msg, sock_hdr_name.s, sock_hdr_name.len); if (hf==0) return 1; trim_len( socks.len, socks.s, hf->body ); if (socks.len==0) return 1; if (parse_phostport( socks.s, socks.len, &hosts.s, &hosts.len, &port, &proto)!=0) { LM_ERR("bad socket <%.*s> in \n", socks.len, socks.s); return 1; } set_sip_defaults( port, proto); sock = grep_sock_info(&hosts,(unsigned short)port,(unsigned short)proto); if (sock==0) { LM_ERR("non-local socket <%.*s>\n", socks.len, socks.s); return 1; } LM_DBG("%d:<%.*s>:%d -> p=%p\n", proto,socks.len,socks.s,port,sock ); ci->sock = sock; return 0; }
int tm_has_request_disponsition_no_cancel(struct sip_msg *msg) { str RD_hdr_name = {"Request-Disposition",19}; str opt = {"no-cancel",9}; struct hdr_field *hdr; /* be sure all SIP headers are parsed */ if (parse_headers(msg, HDR_EOH_F, 0) < 0) { LM_ERR("failed to parse SIP headers while looking for " "Request-Disposition\n"); return -1; } hdr = get_header_by_name( msg, RD_hdr_name.s, RD_hdr_name.len); if (hdr==NULL) return -1; return list_hdr_has_option( hdr, &opt); }
/*! \brief */ static struct socket_info *get_sock_hdr(struct sip_msg *msg) { struct socket_info *sock; struct hdr_field *hf; str socks; str hosts; int port; int proto; if (parse_headers( msg, HDR_EOH_F, 0) == -1) { LM_ERR("failed to parse message\n"); return 0; } hf = get_header_by_name( msg, sock_hdr_name.s, sock_hdr_name.len); if (hf==0) return 0; trim_len( socks.len, socks.s, hf->body ); if (socks.len==0) return 0; if (parse_phostport( socks.s, socks.len, &hosts.s, &hosts.len, &port, &proto)!=0) { LM_ERR("bad socket <%.*s> in \n", socks.len, socks.s); return 0; } set_sip_defaults( port, proto); sock = grep_sock_info(&hosts,(unsigned short)port,(unsigned short)proto); if (sock==0) { LM_ERR("non-local socket <%.*s>\n", socks.len, socks.s); return 0; } LM_DBG("%d:<%.*s>:%d -> p=%p\n", proto,socks.len,socks.s,port_no,sock ); return sock; }
static int get_hostname_from_header(request_t *req) { char *ptr, *header; header = get_header_by_name(req->data, "Host:"); if (!header){ return -1; } /* if port number, copy it */ ptr = strchr(header, ':'); if (ptr){ *ptr = '\0'; req->http_infos.hostname = proxenet_xstrdup2(header); req->http_infos.port = (unsigned short)atoi(ptr+1); } else { req->http_infos.hostname = proxenet_xstrdup2(header); } proxenet_xfree(header); return 0; }
/** * This function updates all the fields of the current request_t with the new values found in the * request. Since those values will be useful many times, they are strdup-ed in a specific structure * (http_infos_t). Those values *must* be free-ed later on. * * @return 0 if successful, -1 if any error occurs. */ int parse_http_request(request_t *req) { char *ptr, *buf, c; int offset; buf = req->data; /* method */ ptr = strchr(buf, ' '); if (!ptr){ xlog(LOG_ERROR, "%s\n", "Cannot find HTTP method in request"); if (cfg->verbose) xlog(LOG_ERROR, "Buffer sent:\n%s\n", buf); return -1; } c = *ptr; *ptr = '\0'; req->http_infos.method = proxenet_xstrdup2(buf); if (!req->http_infos.method){ xlog(LOG_ERROR, "%s\n", "strdup(method) failed, cannot pursue..."); return -1; } *ptr = c; req->http_infos.proto_type = HTTP; if (!strcmp(req->http_infos.method, "CONNECT")){ /* * We can receive a CONNECT if * - the connection uses HTTPS * - the client tries to upgrade to WebSocket/Secure WebSocket */ char *upgrade_header = get_header_by_name(buf, "Upgrade:"); if (upgrade_header){ if (strcmp(upgrade_header, "WebSocket")==0){ xlog(LOG_INFO, "%s\n", "Upgrading to WebSocket"); req->http_infos.proto_type = WS; req->is_ssl = false; req->http_infos.proto = WS_STRING; req->http_infos.port = HTTP_DEFAULT_PORT; req->http_infos.proto_type = WS; } proxenet_xfree(upgrade_header); } else { req->is_ssl = true; req->http_infos.proto = HTTPS_STRING; req->http_infos.port = HTTPS_DEFAULT_PORT; req->http_infos.proto_type = HTTPS; } offset = ptr - buf + 1; if( get_hostname_from_uri(req, offset) < 0 ){ xlog(LOG_ERROR, "%s\n", "Failed to get hostname (URI)"); goto failed_hostname; } req->http_infos.path = proxenet_xstrdup2("/"); req->http_infos.version = proxenet_xstrdup2("HTTP/1.0"); req->http_infos.uri = get_request_full_uri(req); if(!req->http_infos.uri){ xlog(LOG_ERROR, "%s\n", "get_request_full_uri() failed"); goto failed_uri; } return 0; } /* hostname and port */ if (req->is_ssl){ req->http_infos.port = HTTPS_DEFAULT_PORT; req->http_infos.proto = HTTPS_STRING; } else { req->http_infos.port = HTTP_DEFAULT_PORT; req->http_infos.proto = HTTP_STRING; } if( get_hostname_from_header(req) < 0 ){ xlog(LOG_ERROR, "%s\n", "Failed to get hostname (Host header)"); goto failed_hostname; } /* path */ buf = ptr+1; if (!strncmp(buf, HTTP_PROTO_STRING, strlen(HTTP_PROTO_STRING))){ buf = strchr(buf + 8, '/'); } ptr = strchr(buf, ' '); if (!ptr){ xlog(LOG_ERROR, "%s\n", "Cannot find HTTP path in request"); goto failed_path; } c = *ptr; *ptr = '\0'; req->http_infos.path = proxenet_xstrdup2(buf); if (!req->http_infos.path){ xlog(LOG_ERROR, "%s\n", "strdup(path) failed, cannot pursue..."); goto failed_path; } *ptr = c; buf = ptr+1; /* version */ ptr = strchr(req->data, '\r'); if (!ptr){ xlog(LOG_ERROR, "%s\n", "Cannot find HTTP version"); goto failed_version; } c = *ptr; *ptr = '\0'; req->http_infos.version = proxenet_xstrdup2(buf); if (!req->http_infos.version){ xlog(LOG_ERROR, "%s\n", "strdup(version) failed, cannot pursue..."); goto failed_version; } *ptr = c; /* refresh uri */ req->http_infos.uri = get_request_full_uri(req); if(!req->http_infos.uri){ xlog(LOG_ERROR, "%s\n", "get_request_full_uri() failed"); goto failed_uri; } if (cfg->verbose) { xlog(LOG_INFO, "New request %d to '%s'\n", req->id, req->http_infos.uri); if (cfg->verbose > 1) { xlog(LOG_INFO, "Request HTTP information:\n" "method=%s\n" "proto=%s\n" "hostname=%s\n" "port=%d\n" "path=%s\n" "version=%s\n" , req->http_infos.method, req->http_infos.proto, req->http_infos.hostname, req->http_infos.port, req->http_infos.path, req->http_infos.version); } } return 0; failed_uri: proxenet_xfree(req->http_infos.version); failed_version: proxenet_xfree(req->http_infos.path); failed_path: proxenet_xfree(req->http_infos.hostname); failed_hostname: proxenet_xfree(req->http_infos.method); return -1; }
/* Take headers to pass on the other side: * Content-Type: * Allow: * Supported: * Require * RSeq * Session-Expires * Min-SE */ int b2b_extra_headers(struct sip_msg* msg, str* b2bl_key, str* custom_hdrs, str* extra_headers) { char* p; struct hdr_field* require_hdr; struct hdr_field* rseq_hdr; struct hdr_field* subscription_state_hdr; struct hdr_field* hdr; struct hdr_field* hdrs[HDR_LST_LEN + HDR_DEFAULT_LEN]; int hdrs_no = 0; int len = 0; int i; int custom_hdrs_len = 0; if(msg->content_type) hdrs[hdrs_no++] = msg->content_type; if(msg->supported) hdrs[hdrs_no++] = msg->supported; if(msg->allow) hdrs[hdrs_no++] = msg->allow; if(msg->proxy_require) hdrs[hdrs_no++] = msg->proxy_require; if(msg->session_expires) hdrs[hdrs_no++] = msg->session_expires; if(msg->min_se) hdrs[hdrs_no++] = msg->min_se; if(msg->maxforwards) hdrs[hdrs_no++] = msg->maxforwards; if(msg->event) hdrs[hdrs_no++] = msg->event; require_hdr = get_header_by_static_name( msg, "Require"); if(require_hdr) hdrs[hdrs_no++] = require_hdr; rseq_hdr = get_header_by_static_name( msg, "RSeq"); if(rseq_hdr) hdrs[hdrs_no++] = rseq_hdr; subscription_state_hdr = get_header_by_static_name( msg, "Subscription-state"); if(subscription_state_hdr) hdrs[hdrs_no++] = subscription_state_hdr; /* add also the custom headers */ for(i = 0; i< custom_headers_lst_len; i++) { hdr = get_header_by_name( msg, custom_headers_lst[i].s, custom_headers_lst[i].len); if(hdr) { hdrs[hdrs_no++] = hdr; } } /* calculate the length*/ for(i = 0; i< hdrs_no; i++) len += hdrs[i]->len; if(init_callid_hdr.len && msg && msg->callid) len+= init_callid_hdr.len + msg->callid->len; if(len == 0) return 0; if(custom_hdrs && custom_hdrs->s && custom_hdrs->len) { custom_hdrs_len = custom_hdrs->len; len += custom_hdrs_len; } extra_headers->s = (char*)pkg_malloc(len); if(extra_headers->s == NULL) { LM_ERR("No more memory\n"); return -1; } p = extra_headers->s; /* construct the headers string */ for(i = 0; i< hdrs_no; i++) { memcpy(p, hdrs[i]->name.s, hdrs[i]->len); p += hdrs[i]->len; } if(custom_hdrs_len) { memcpy(p, custom_hdrs->s, custom_hdrs_len); p += custom_hdrs_len; } if(init_callid_hdr.s && msg && msg->callid) { memcpy(p, init_callid_hdr.s, init_callid_hdr.len); p += init_callid_hdr.len; len = sprintf(p, ": %.*s", (int)(msg->callid->name.s +msg->callid->len -msg->callid->body.s), msg->callid->body.s); p += len; } extra_headers->len = p - extra_headers->s; return 0; }
int b2b_extra_headers(struct sip_msg* msg, str* b2bl_key, str* custom_hdrs, str* extra_headers) { char* p; struct hdr_field* require_hdr; struct hdr_field* rseq_hdr; struct hdr_field* subscription_state_hdr; struct hdr_field* hdr; struct hdr_field* hdrs[HDR_LST_LEN + HDR_DEFAULT_LEN]; regmatch_t pmatch; int hdrs_no = 0; int len = 0; int i; int custom_hdrs_len = 0; char tmp; if(msg->content_type) hdrs[hdrs_no++] = msg->content_type; if(msg->supported) hdrs[hdrs_no++] = msg->supported; if(msg->allow) hdrs[hdrs_no++] = msg->allow; if(msg->proxy_require) hdrs[hdrs_no++] = msg->proxy_require; if(msg->session_expires) hdrs[hdrs_no++] = msg->session_expires; if(msg->min_se) hdrs[hdrs_no++] = msg->min_se; if(msg->event) hdrs[hdrs_no++] = msg->event; require_hdr = get_header_by_static_name( msg, "Require"); if(require_hdr) hdrs[hdrs_no++] = require_hdr; rseq_hdr = get_header_by_static_name( msg, "RSeq"); if(rseq_hdr) hdrs[hdrs_no++] = rseq_hdr; subscription_state_hdr = get_header_by_static_name( msg, "Subscription-state"); if(subscription_state_hdr) hdrs[hdrs_no++] = subscription_state_hdr; /* add also the custom headers */ for(i = 0; i< custom_headers_lst_len; i++) { hdr = get_header_by_name( msg, custom_headers_lst[i].s, custom_headers_lst[i].len); if(hdr) { hdrs[hdrs_no++] = hdr; } } if (custom_headers_re) { for (hdr=msg->headers; hdr; hdr=hdr->next) { tmp = hdr->name.s[hdr->name.len]; hdr->name.s[hdr->name.len] = '\0'; i = regexec(custom_headers_re, hdr->name.s, 1, &pmatch, 0); hdr->name.s[hdr->name.len] = tmp; if (i == 0) { /* check if added twice */ for(i = 0; i < hdrs_no; i++) { if ( hdrs[i]->name.len == hdr->name.len && strncmp(hdrs[i]->name.s, hdr->name.s, hdr->name.len)==0 ) break; } if (i == hdrs_no) /* Doubles not found -> add it */ hdrs[hdrs_no++] = hdr; } } } /* calculate the length*/ for(i = 0; i< hdrs_no; i++) len += hdrs[i]->len; if(init_callid_hdr.len && msg && msg->callid) len+= init_callid_hdr.len + msg->callid->len; if(custom_hdrs && custom_hdrs->s && custom_hdrs->len) { custom_hdrs_len = custom_hdrs->len; len += custom_hdrs_len; } if(len == 0) return 0; extra_headers->s = (char*)pkg_malloc(len); if(extra_headers->s == NULL) { LM_ERR("No more memory\n"); return -1; } p = extra_headers->s; /* construct the headers string */ for(i = 0; i< hdrs_no; i++) { memcpy(p, hdrs[i]->name.s, hdrs[i]->len); p += hdrs[i]->len; } if(custom_hdrs_len) { memcpy(p, custom_hdrs->s, custom_hdrs_len); p += custom_hdrs_len; } if(init_callid_hdr.s && msg && msg->callid) { memcpy(p, init_callid_hdr.s, init_callid_hdr.len); p += init_callid_hdr.len; len = sprintf(p, ": %.*s", (int)(msg->callid->name.s +msg->callid->len -msg->callid->body.s), msg->callid->body.s); p += len; } extra_headers->len = p - extra_headers->s; return 0; }