/*! * \brief checks precondition, switch, filter and forwards msg if necessary * \param msg the message to be forwarded * \param id use configuration with this ID when checking switch, filter, proxy. * \param proto protocol to be used. Should be PROTO_UDP. * \return 0 on success, -1 otherwise */ int utils_forward(struct sip_msg *msg, int id, int proto) { int ret = -1; struct dest_info dst; init_dest_info(&dst); dst.proto = proto; // critical section start: // avoids dirty reads when updating configuration. lock_get(conf_lock); struct proxy_l *proxy = conf_needs_forward(msg, id); if (proxy != NULL) { proxy2su(&dst.to, proxy); if (forward_request(msg, NULL, 0, &dst) < 0){ LM_ERR("could not forward message\n"); } ret = 0; } // critical section end lock_release(conf_lock); return ret; }
void *request_handler(void *ptr) { #ifdef DEBUG printf("enter request_handler\n"); #endif int client_fd = ((Thread_Input*)ptr)->client_fd; Request request; Response response; parse_request_header(client_fd, &request); modify_request_header(&request); if (check_cache(&request, &response)) { send_client(client_fd, &response); } else { if (forward_request(client_fd, &request, &response) < 0) { Close(client_fd); return NULL; } else { if (response.content_size <= MAX_OBJECT_SIZE) save_to_cache(&request, &response); } } free(ptr); Close(client_fd); #ifdef DEBUG printf("connection close\n\n"); printf("leave request_handler\n"); #endif return NULL; }
/*proxy executation routine*/ int run_proxy(int connfd) { char hostname[MAXLINE]; char req_buf[MAX_OBJECT_SIZE]; char resp_buf[MAX_OBJECT_SIZE]; char uri[MAXLINE]; int port = 80; int clientfd; rio_t rio; memset(hostname, 0, MAXLINE); memset(req_buf, 0, MAX_OBJECT_SIZE); memset(resp_buf, 0 , MAX_OBJECT_SIZE); /* read request */ if(read_request(connfd, req_buf, uri, hostname, &port) < 0) { //printf("close fd: %d, tid: %d\n", connfd, gettid()); Close(connfd); return -1; } /* open connection to server */ if((clientfd = open_clientfd_r(hostname, port)) < 0) { //printf("connfd: %d, clientfd: %d, host: %s, tid: %d\n", connfd, clientfd, hostname, gettid()); printf("Open_clientfd error\n"); fprintf(stderr, "Error: connection refused: %s !\n", hostname); Close(connfd); return -1; } if(forward_request(&rio, req_buf, clientfd) < 0) { printf("forward_request error\n"); fprintf(stderr, "Error: Send request to server failed !\n"); Close(clientfd); Close(connfd); return -1; } if(forward_response(&rio, uri, resp_buf, connfd) < 0) { printf("forward_response\n"); fprintf(stderr, "Error: Send response to client failed !\n"); Close(clientfd); Close(connfd); return -1; } Close(clientfd); Close(connfd); return 0; }
/* Consumes connection file descriptors from the shared buffer and * processes them. */ void *thread(void *vargp){ // avoid memory leak Pthread_detach(pthread_self()); req_t request; int result; while(1){ int connfd = sbuf_remove(&sbuf); if((result = process_request(connfd, &request)) == -1){ fprintf(stderr,"process_request failed\n"); bad_request(connfd); free_req(request); Close(connfd); continue; } forward_request(connfd, request); Close(connfd); } }
/* * request_handler - general function to handler each client request */ void *request_handler(int client_fd) { #ifdef DEBUG printf("enter request_handler\n"); #endif Request request; Response response; parse_request_header(client_fd, &request); modify_request_header(&request); if (check_cache(&request, &response)) { #ifdef DEBUG printf("in cache ! \n"); #endif send_client(client_fd, &response); } else { #ifdef DEBUG printf("not in cache !\n"); #endif if (forward_request(client_fd, &request, &response) < 0) { close(client_fd); return NULL; } else { /* save to cache if status code 2XX and < max size */ if (response.content_size <= MAX_OBJECT_SIZE && response.header[state_ofs] == '2') save_to_cache(&request, &response); } } close(client_fd); #ifdef DEBUG printf("connection close\n"); printf("leave request_handler\n"); #endif return NULL; }
bool key_changed_h(connection_t *c) { char name[MAX_STRING_SIZE]; node_t *n; if(sscanf(c->buffer, "%*d %*x " MAX_STRING, name) != 1) { logger(LOG_ERR, "Got bad %s from %s (%s)", "KEY_CHANGED", c->name, c->hostname); return false; } if(!check_id(name)) { logger(LOG_ERR, "Got bad %s from %s (%s): %s", "KEY_CHANGED", c->name, c->hostname, "invalid name"); return false; } if(seen_request(c->buffer)) return true; n = lookup_node(name); if(!n) { logger(LOG_ERR, "Got %s from %s (%s) origin %s which does not exist", "KEY_CHANGED", c->name, c->hostname, name); return true; } n->status.validkey = false; n->last_req_key = 0; /* Tell the others */ if(!tunnelserver) forward_request(c); return true; }
/// Retry the request to an alternate S-CSCF if possible. bool ICSCFProxy::UASTsx::retry_to_alternate_scscf(int rsp_status) { bool retry = false; if (_case == SessionCase::REGISTER) { // Check whether conditions are satisfied for retrying a REGISTER (see // 5.3.1.3/TS24.229). LOG_DEBUG("Check retry conditions for REGISTER request, status code = %d", rsp_status); if (((rsp_status >= 300) && (rsp_status <= 399)) || (rsp_status == PJSIP_SC_REQUEST_TIMEOUT) || (rsp_status == PJSIP_SC_TEMPORARILY_UNAVAILABLE)) { // Can do a retry (we support service restoration, so integrity-protected // settings in Authorization header are immaterial). LOG_DEBUG("Attempt retry to alternate S-CSCF for REGISTER request"); retry = true; std::string st_code = std::to_string(rsp_status); SAS::Event event(trail(), SASEvent::SCSCF_RETRY, 0); std::string method = "REGISTER"; event.add_var_param(method); event.add_var_param(st_code); SAS::report_event(event); } } else { // Check whether conditions are satisfied for retrying a Non-REGISTER. LOG_DEBUG("Check retry conditions for Non-REGISTER request, status code = %d", rsp_status); if (rsp_status == PJSIP_SC_REQUEST_TIMEOUT) { LOG_DEBUG("Attempt retry to alternate S-CSCF for non-REGISTER request"); retry = true; std::string st_code = std::to_string(rsp_status); SAS::Event event(trail(), SASEvent::SCSCF_RETRY, 0); std::string method = "NON-REGISTER"; event.add_var_param(method); event.add_var_param(st_code); SAS::report_event(event); } } if (retry) { // Retry conditions are satisfied, so try to calculate a new target. int status_code = calculate_targets(); if (status_code == PJSIP_SC_OK) { // We found a suitable alternate S-CSCF and have programmed it as a // target, so action the retry. forward_request(); } else { // Failed to find another S-CSCF for the request. LOG_DEBUG("Failed to find alternate S-CSCF for retry"); retry = false; if (_case == SessionCase::REGISTER) { // In the register case the spec's are quite particular about how // failures are reported. if (status_code == PJSIP_SC_FORBIDDEN) { // The HSS has returned a negative response to the user registration // request - I-CSCF should respond with 403. _best_rsp->msg->line.status.code = PJSIP_SC_FORBIDDEN; _best_rsp->msg->line.status.reason = *pjsip_get_status_text(_best_rsp->msg->line.status.code); } else { // The I-CSCF can't select an S-CSCF for the REGISTER request (either // because there are no more S-CSCFs that meet the mandatory // capabilitires, or the HSS is temporarily unavailable). There was at // least one valid S-CSCF (as this is retry processing). The I-CSCF // must return 504 (TS 24.229, 5.3.1.3) in this case. _best_rsp->msg->line.status.code = PJSIP_SC_SERVER_TIMEOUT; _best_rsp->msg->line.status.reason = *pjsip_get_status_text(_best_rsp->msg->line.status.code); } pjsip_tx_data_invalidate_msg(_best_rsp); } } } return retry; }
/* ret= 0! if action -> end of list(e.g DROP), > 0 to continue processing next actions and <0 on error */ int do_action(struct action* a, struct sip_msg* msg) { int ret; int v; union sockaddr_union* to; struct socket_info* send_sock; struct proxy_l* p; char* tmp; char *new_uri, *end, *crt; int len; int user; struct sip_uri uri, next_hop; struct sip_uri* u; unsigned short port; int proto; /* reset the value of error to E_UNSPEC so avoid unknowledgable functions to return with errror (status<0) and not setting it leaving there previous error; cache the previous value though for functions which want to process it */ prev_ser_error=ser_error; ser_error=E_UNSPEC; ret=E_BUG; switch ((unsigned char)a->type){ case DROP_T: ret=0; break; case FORWARD_T: #ifdef USE_TCP case FORWARD_TCP_T: #endif #ifdef USE_TLS case FORWARD_TLS_T: #endif case FORWARD_UDP_T: if (a->type==FORWARD_UDP_T) proto=PROTO_UDP; #ifdef USE_TCP else if (a->type==FORWARD_TCP_T) proto= PROTO_TCP; #endif #ifdef USE_TLS else if (a->type==FORWARD_TLS_T) proto= PROTO_TLS; #endif else proto=msg->rcv.proto; if (a->p1_type==URIHOST_ST){ /*parse uri*/ if (msg->dst_uri.len) { ret = parse_uri(msg->dst_uri.s, msg->dst_uri.len, &next_hop); u = &next_hop; } else { ret = parse_sip_msg_uri(msg); u = &msg->parsed_uri; } if (ret<0) { LOG(L_ERR, "ERROR: do_action: forward: bad_uri " " dropping packet\n"); break; } switch (a->p2_type){ case URIPORT_ST: port=u->port_no; break; case NUMBER_ST: port=a->p2.number; break; default: LOG(L_CRIT, "BUG: do_action bad forward 2nd" " param type (%d)\n", a->p2_type); ret=E_UNSPEC; goto error_fwd_uri; } switch(u->proto){ case PROTO_NONE: proto=PROTO_UDP; break; case PROTO_UDP: #ifdef USE_TCP case PROTO_TCP: #endif #ifdef USE_TLS case PROTO_TLS: #endif proto=u->proto; break; default: LOG(L_ERR,"ERROR: do action: forward: bad uri" " transport %d\n", u->proto); ret=E_BAD_PROTO; goto error_fwd_uri; } #ifdef USE_TLS if (u->secure){ if (u->proto==PROTO_UDP){ LOG(L_ERR, "ERROR: do_action: forward: secure uri" " incompatible with transport %d\n", u->proto); ret=E_BAD_PROTO; goto error_fwd_uri; } proto=PROTO_TLS; } #endif /* create a temporary proxy*/ p=mk_proxy(&u->host, port, proto); if (p==0){ LOG(L_ERR, "ERROR: bad host name in uri," " dropping packet\n"); ret=E_BAD_ADDRESS; goto error_fwd_uri; } ret=forward_request(msg, p, proto); /*free_uri(&uri); -- no longer needed, in sip_msg*/ free_proxy(p); /* frees only p content, not p itself */ pkg_free(p); if (ret>=0) ret=1; }else if ((a->p1_type==PROXY_ST) && (a->p2_type==NUMBER_ST)){ ret=forward_request(msg,(struct proxy_l*)a->p1.data, proto); if (ret>=0) ret=1; }else{ LOG(L_CRIT, "BUG: do_action: bad forward() types %d, %d\n", a->p1_type, a->p2_type); ret=E_BUG; } break; case SEND_T: case SEND_TCP_T: if ((a->p1_type!= PROXY_ST)|(a->p2_type!=NUMBER_ST)){ LOG(L_CRIT, "BUG: do_action: bad send() types %d, %d\n", a->p1_type, a->p2_type); ret=E_BUG; break; } to=(union sockaddr_union*) pkg_malloc(sizeof(union sockaddr_union)); if (to==0){ LOG(L_ERR, "ERROR: do_action: " "memory allocation failure\n"); ret=E_OUT_OF_MEM; break; } p=(struct proxy_l*)a->p1.data; if (p->ok==0){ if (p->host.h_addr_list[p->addr_idx+1]) p->addr_idx++; else p->addr_idx=0; p->ok=1; } ret=hostent2su( to, &p->host, p->addr_idx, (p->port)?p->port:SIP_PORT ); if (ret==0){ p->tx++; p->tx_bytes+=msg->len; if (a->type==SEND_T){ /*udp*/ send_sock=get_send_socket(to, PROTO_UDP); if (send_sock!=0){ ret=udp_send(send_sock, msg->buf, msg->len, to); }else{ ret=-1; } } #ifdef USE_TCP else{ /*tcp*/ ret=tcp_send(PROTO_TCP, msg->buf, msg->len, to, 0); } #endif } pkg_free(to); if (ret<0){ p->errors++; p->ok=0; }else ret=1; break; case LOG_T: if ((a->p1_type!=NUMBER_ST)|(a->p2_type!=STRING_ST)){ LOG(L_CRIT, "BUG: do_action: bad log() types %d, %d\n", a->p1_type, a->p2_type); ret=E_BUG; break; } LOG(a->p1.number, a->p2.string); ret=1; break; /* jku -- introduce a new branch */ case APPEND_BRANCH_T: if ((a->p1_type!=STRING_ST)) { LOG(L_CRIT, "BUG: do_action: bad append_branch_t %d\n", a->p1_type ); ret=E_BUG; break; } ret=append_branch( msg, a->p1.string, a->p1.string ? strlen(a->p1.string):0 ); break; /* jku begin: is_length_greater_than */ case LEN_GT_T: if (a->p1_type!=NUMBER_ST) { LOG(L_CRIT, "BUG: do_action: bad len_gt type %d\n", a->p1_type ); ret=E_BUG; break; } /* DBG("XXX: message length %d, max %d\n", msg->len, a->p1.number ); */ ret = msg->len >= a->p1.number ? 1 : -1; break; /* jku end: is_length_greater_than */ /* jku - begin : flag processing */ case SETFLAG_T: if (a->p1_type!=NUMBER_ST) { LOG(L_CRIT, "BUG: do_action: bad setflag() type %d\n", a->p1_type ); ret=E_BUG; break; } if (!flag_in_range( a->p1.number )) { ret=E_CFG; break; } setflag( msg, a->p1.number ); ret=1; break; case RESETFLAG_T: if (a->p1_type!=NUMBER_ST) { LOG(L_CRIT, "BUG: do_action: bad resetflag() type %d\n", a->p1_type ); ret=E_BUG; break; } if (!flag_in_range( a->p1.number )) { ret=E_CFG; break; } resetflag( msg, a->p1.number ); ret=1; break; case ISFLAGSET_T: if (a->p1_type!=NUMBER_ST) { LOG(L_CRIT, "BUG: do_action: bad isflagset() type %d\n", a->p1_type ); ret=E_BUG; break; } if (!flag_in_range( a->p1.number )) { ret=E_CFG; break; } ret=isflagset( msg, a->p1.number ); break; /* jku - end : flag processing */ case ERROR_T: if ((a->p1_type!=STRING_ST)|(a->p2_type!=STRING_ST)){ LOG(L_CRIT, "BUG: do_action: bad error() types %d, %d\n", a->p1_type, a->p2_type); ret=E_BUG; break; } LOG(L_NOTICE, "WARNING: do_action: error(\"%s\", \"%s\") " "not implemented yet\n", a->p1.string, a->p2.string); ret=1; break; case ROUTE_T: if (a->p1_type!=NUMBER_ST){ LOG(L_CRIT, "BUG: do_action: bad route() type %d\n", a->p1_type); ret=E_BUG; break; } if ((a->p1.number>RT_NO)||(a->p1.number<0)){ LOG(L_ERR, "ERROR: invalid routing table number in" "route(%lu)\n", a->p1.number); ret=E_CFG; break; } ret=((ret=run_actions(rlist[a->p1.number], msg))<0)?ret:1; break; case EXEC_T: if (a->p1_type!=STRING_ST){ LOG(L_CRIT, "BUG: do_action: bad exec() type %d\n", a->p1_type); ret=E_BUG; break; } LOG(L_NOTICE, "WARNING: exec(\"%s\") not fully implemented," " using dumb version...\n", a->p1.string); ret=system(a->p1.string); if (ret!=0){ LOG(L_NOTICE, "WARNING: exec() returned %d\n", ret); } ret=1; break; case REVERT_URI_T: if (msg->new_uri.s) { pkg_free(msg->new_uri.s); msg->new_uri.len=0; msg->new_uri.s=0; msg->parsed_uri_ok=0; /* invalidate current parsed uri*/ }; ret=1; break; case SET_HOST_T: case SET_HOSTPORT_T: case SET_USER_T: case SET_USERPASS_T: case SET_PORT_T: case SET_URI_T: case PREFIX_T: case STRIP_T: case STRIP_TAIL_T: user=0; if (a->type==STRIP_T || a->type==STRIP_TAIL_T) { if (a->p1_type!=NUMBER_ST) { LOG(L_CRIT, "BUG: do_action: bad set*() type %d\n", a->p1_type); break; } } else if (a->p1_type!=STRING_ST){ LOG(L_CRIT, "BUG: do_action: bad set*() type %d\n", a->p1_type); ret=E_BUG; break; } if (a->type==SET_URI_T){ if (msg->new_uri.s) { pkg_free(msg->new_uri.s); msg->new_uri.len=0; } msg->parsed_uri_ok=0; len=strlen(a->p1.string); msg->new_uri.s=pkg_malloc(len+1); if (msg->new_uri.s==0){ LOG(L_ERR, "ERROR: do_action: memory allocation" " failure\n"); ret=E_OUT_OF_MEM; break; } memcpy(msg->new_uri.s, a->p1.string, len); msg->new_uri.s[len]=0; msg->new_uri.len=len; ret=1; break; } if (msg->new_uri.s) { tmp=msg->new_uri.s; len=msg->new_uri.len; }else{ tmp=msg->first_line.u.request.uri.s; len=msg->first_line.u.request.uri.len; } if (parse_uri(tmp, len, &uri)<0){ LOG(L_ERR, "ERROR: do_action: bad uri <%s>, dropping" " packet\n", tmp); ret=E_UNSPEC; break; } new_uri=pkg_malloc(MAX_URI_SIZE); if (new_uri==0){ LOG(L_ERR, "ERROR: do_action: memory allocation " " failure\n"); ret=E_OUT_OF_MEM; break; } end=new_uri+MAX_URI_SIZE; crt=new_uri; /* begin copying */ len=strlen("sip:"); if(crt+len>end) goto error_uri; memcpy(crt,"sip:",len);crt+=len; /* user */ /* prefix (-jiri) */ if (a->type==PREFIX_T) { tmp=a->p1.string; len=strlen(tmp); if(crt+len>end) goto error_uri; memcpy(crt,tmp,len);crt+=len; /* whatever we had before, with prefix we have username now */ user=1; } if ((a->type==SET_USER_T)||(a->type==SET_USERPASS_T)) { tmp=a->p1.string; len=strlen(tmp); } else if (a->type==STRIP_T) { if (a->p1.number>uri.user.len) { LOG(L_WARN, "Error: too long strip asked; " " deleting username: %lu of <%.*s>\n", a->p1.number, uri.user.len, uri.user.s ); len=0; } else if (a->p1.number==uri.user.len) { len=0; } else { tmp=uri.user.s + a->p1.number; len=uri.user.len - a->p1.number; } } else if (a->type==STRIP_TAIL_T) { if (a->p1.number>uri.user.len) { LOG(L_WARN, "WARNING: too long strip_tail asked; " " deleting username: %lu of <%.*s>\n", a->p1.number, uri.user.len, uri.user.s ); len=0; } else if (a->p1.number==uri.user.len) { len=0; } else { tmp=uri.user.s; len=uri.user.len - a->p1.number; } } else { tmp=uri.user.s; len=uri.user.len; } if (len){ if(crt+len>end) goto error_uri; memcpy(crt,tmp,len);crt+=len; user=1; /* we have an user field so mark it */ } if (a->type==SET_USERPASS_T) tmp=0; else tmp=uri.passwd.s; /* passwd */ if (tmp){ len=uri.passwd.len; if(crt+len+1>end) goto error_uri; *crt=':'; crt++; memcpy(crt,tmp,len);crt+=len; } /* host */ if (user || tmp){ /* add @ */ if(crt+1>end) goto error_uri; *crt='@'; crt++; } if ((a->type==SET_HOST_T) ||(a->type==SET_HOSTPORT_T)) { tmp=a->p1.string; if (tmp) len = strlen(tmp); else len=0; } else { tmp=uri.host.s; len = uri.host.len; } if (tmp){ if(crt+len>end) goto error_uri; memcpy(crt,tmp,len);crt+=len; } /* port */ if (a->type==SET_HOSTPORT_T) tmp=0; else if (a->type==SET_PORT_T) { tmp=a->p1.string; if (tmp) len = strlen(tmp); else len = 0; } else { tmp=uri.port.s; len = uri.port.len; } if (tmp){ if(crt+len+1>end) goto error_uri; *crt=':'; crt++; memcpy(crt,tmp,len);crt+=len; } /* params */ tmp=uri.params.s; if (tmp){ len=uri.params.len; if(crt+len+1>end) goto error_uri; *crt=';'; crt++; memcpy(crt,tmp,len);crt+=len; } /* headers */ tmp=uri.headers.s; if (tmp){ len=uri.headers.len; if(crt+len+1>end) goto error_uri; *crt='?'; crt++; memcpy(crt,tmp,len);crt+=len; } *crt=0; /* null terminate the thing */ /* copy it to the msg */ if (msg->new_uri.s) pkg_free(msg->new_uri.s); msg->new_uri.s=new_uri; msg->new_uri.len=crt-new_uri; msg->parsed_uri_ok=0; ret=1; break; case IF_T: /* if null expr => ignore if? */ if ((a->p1_type==EXPR_ST)&&a->p1.data){ v=eval_expr((struct expr*)a->p1.data, msg); if (v<0){ if (v==EXPR_DROP){ /* hack to quit on DROP*/ ret=0; break; }else{ LOG(L_WARN,"WARNING: do_action:" "error in expression\n"); } } ret=1; /*default is continue */ if (v>0) { if ((a->p2_type==ACTIONS_ST)&&a->p2.data){ ret=run_actions((struct action*)a->p2.data, msg); } }else if ((a->p3_type==ACTIONS_ST)&&a->p3.data){ ret=run_actions((struct action*)a->p3.data, msg); } } break; case MODULE_T: if ( ((a->p1_type==CMDF_ST)&&a->p1.data)/*&& ((a->p2_type==STRING_ST)&&a->p2.data)*/ ){ ret=((cmd_function)(a->p1.data))(msg, (char*)a->p2.data, (char*)a->p3.data); }else{ LOG(L_CRIT,"BUG: do_action: bad module call\n"); } break; case FORCE_RPORT_T: msg->msg_flags|=FL_FORCE_RPORT; ret=1; /* continue processing */ break; case SET_ADV_ADDR_T: if (a->p1_type!=STR_ST){ LOG(L_CRIT, "BUG: do_action: bad set_advertised_address() " "type %d\n", a->p1_type); ret=E_BUG; break; } msg->set_global_address=*((str*)a->p1.data); ret=1; /* continue processing */ break; case SET_ADV_PORT_T: if (a->p1_type!=STR_ST){ LOG(L_CRIT, "BUG: do_action: bad set_advertised_port() " "type %d\n", a->p1_type); ret=E_BUG; break; } msg->set_global_port=*((str*)a->p1.data); ret=1; /* continue processing */ break; default: LOG(L_CRIT, "BUG: do_action: unknown type %d\n", a->type); } /*skip:*/ return ret; error_uri: LOG(L_ERR, "ERROR: do_action: set*: uri too long\n"); if (new_uri) pkg_free(new_uri); return E_UNSPEC; error_fwd_uri: /*free_uri(&uri); -- not needed anymore, using msg->parsed_uri*/ return ret; }
/* WARNING: doesn't work from failure route (deadlock, uses t_reply => tries * to get the reply lock again */ int t_relay_to( struct sip_msg *p_msg , struct proxy_l *proxy, int proto, int replicate) { int ret; int new_tran; /* struct hdr_field *hdr; */ struct cell *t; struct dest_info dst; unsigned short port; str host; short comp; #ifndef TM_DELAYED_REPLY int reply_ret; #endif ret=0; /* special case for CANCEL */ if ( p_msg->REQ_METHOD==METHOD_CANCEL){ ret=t_forward_cancel(p_msg, proxy, proto, &t); if (t) goto handle_ret; goto done; } new_tran = t_newtran( p_msg ); /* parsing error, memory alloc, whatever ... if via is bad and we are forced to reply there, return with 0 (->break), pass error status otherwise MMA: return value E_SCRIPT means that transaction was already started from the script so continue with that transaction */ if (likely(new_tran!=E_SCRIPT)) { if (new_tran<0) { ret = (ser_error==E_BAD_VIA && reply_to_via) ? 0 : new_tran; goto done; } /* if that was a retransmission, return we are happily done */ if (new_tran==0) { ret = 1; goto done; } }else if (unlikely(p_msg->REQ_METHOD==METHOD_ACK)) { /* transaction previously found (E_SCRIPT) and msg==ACK => ack to neg. reply or ack to local trans. => process it and exit */ /* FIXME: there's no way to distinguish here between acks to local trans. and neg. acks */ /* in normal operation we should never reach this point, if we do WARN(), it might hide some real bug (apart from possibly hiding a bug the most harm done is calling the TMCB_ACK_NEG callbacks twice) */ WARN("negative or local ACK caught, please report\n"); t=get_t(); if (unlikely(has_tran_tmcbs(t, TMCB_ACK_NEG_IN))) run_trans_callbacks(TMCB_ACK_NEG_IN, t, p_msg, 0, p_msg->REQ_METHOD); t_release_transaction(t); ret=1; goto done; } /* new transaction */ /* at this point if the msg is an ACK it is an e2e ACK and e2e ACKs do not establish a transaction and are fwd-ed statelessly */ if ( p_msg->REQ_METHOD==METHOD_ACK) { DBG( "SER: forwarding ACK statelessly \n"); if (proxy==0) { init_dest_info(&dst); dst.proto=proto; if (get_uri_send_info(GET_NEXT_HOP(p_msg), &host, &port, &dst.proto, &comp)!=0){ ret=E_BAD_ADDRESS; goto done; } #ifdef USE_COMP dst.comp=comp; #endif /* dst->send_sock not set, but forward_request will take care * of it */ ret=forward_request(p_msg, &host, port, &dst); } else { init_dest_info(&dst); dst.proto=get_proto(proto, proxy->proto); proxy2su(&dst.to, proxy); /* dst->send_sock not set, but forward_request will take care * of it */ ret=forward_request( p_msg , 0, 0, &dst) ; } goto done; } /* if replication flag is set, mark the transaction as local so that replies will not be relayed */ t=get_t(); if (replicate) t->flags|=T_IS_LOCAL_FLAG; /* INVITE processing might take long, particularly because of DNS look-ups -- let upstream know we're working on it */ if (p_msg->REQ_METHOD==METHOD_INVITE && (t->flags&T_AUTO_INV_100) && (t->uas.status < 100) ) { DBG( "SER: new INVITE\n"); if (!t_reply( t, p_msg , 100 , cfg_get(tm, tm_cfg, tm_auto_inv_100_r))) DBG("SER: ERROR: t_reply (100)\n"); } /* now go ahead and forward ... */ ret=t_forward_nonack(t, p_msg, proxy, proto); handle_ret: if (ret<=0) { DBG( "t_forward_nonack returned error %d (%d)\n", ret, ser_error); /* we don't want to pass upstream any reply regarding replicating * a request; replicated branch must stop at us*/ if (likely(!replicate)) { if(t->flags&T_DISABLE_INTERNAL_REPLY) { /* flag set to don't generate the internal negative reply * - let the transaction live further, processing should * continue in config */ DBG("not generating immediate reply for error %d\n", ser_error); tm_error=ser_error; ret = -4; goto done; } #ifdef TM_DELAYED_REPLY /* current error in tm_error */ tm_error=ser_error; set_kr(REQ_ERR_DELAYED); DBG("%d error reply generation delayed \n", ser_error); #else reply_ret=kill_transaction( t, ser_error ); if (reply_ret>0) { /* we have taken care of all -- do nothing in script */ DBG("ERROR: generation of a stateful reply " "on error succeeded\n"); /*ret=0; -- we don't want to stop the script */ } else { DBG("ERROR: generation of a stateful reply " "on error failed\n"); t_release_transaction(t); } #endif /* TM_DELAYED_REPLY */ }else{ t_release_transaction(t); /* kill it silently */ } } else { DBG( "SER: new transaction fwd'ed\n"); } done: return ret; }
/* WARNING: doesn't work from failure route (deadlock, uses t_reply => tries * to get the reply lock again */ int t_relay_to( struct sip_msg *p_msg , struct proxy_l *proxy, int proto, int replicate) { int ret; int new_tran; int reply_ret; /* struct hdr_field *hdr; */ struct cell *t; struct dest_info dst; unsigned short port; str host; short comp; ret=0; new_tran = t_newtran( p_msg ); /* parsing error, memory alloc, whatever ... if via is bad and we are forced to reply there, return with 0 (->break), pass error status otherwise MMA: return value E_SCRIPT means that transaction was already started from the script so continue with that transaction */ if (new_tran!=E_SCRIPT) { if (new_tran<0) { ret = (ser_error==E_BAD_VIA && reply_to_via) ? 0 : new_tran; goto done; } /* if that was a retransmission, return we are happily done */ if (new_tran==0) { ret = 1; goto done; } } /* new transaction */ /* ACKs do not establish a transaction and are fwd-ed statelessly */ if ( p_msg->REQ_METHOD==METHOD_ACK) { DBG( "SER: forwarding ACK statelessly \n"); if (proxy==0) { init_dest_info(&dst); dst.proto=proto; if (get_uri_send_info(GET_NEXT_HOP(p_msg), &host, &port, &dst.proto, &comp)!=0){ ret=E_BAD_ADDRESS; goto done; } #ifdef USE_COMP dst.comp=comp; #endif /* dst->send_sock not set, but forward_request will take care * of it */ ret=forward_request(p_msg, &host, port, &dst); } else { init_dest_info(&dst); dst.proto=get_proto(proto, proxy->proto); proxy2su(&dst.to, proxy); /* dst->send_sock not set, but forward_request will take care * of it */ ret=forward_request( p_msg , 0, 0, &dst) ; } goto done; } /* if replication flag is set, mark the transaction as local so that replies will not be relayed */ t=get_t(); if (replicate) t->flags|=T_IS_LOCAL_FLAG; /* INVITE processing might take long, particularly because of DNS look-ups -- let upstream know we're working on it */ if (p_msg->REQ_METHOD==METHOD_INVITE ) { DBG( "SER: new INVITE\n"); if (!t_reply( t, p_msg , 100 , "trying -- your call is important to us")) DBG("SER: ERROR: t_reply (100)\n"); } /* now go ahead and forward ... */ ret=t_forward_nonack(t, p_msg, proxy, proto); if (ret<=0) { DBG( "ERROR:tm:t_relay_to: t_forward_nonack returned error \n"); /* we don't want to pass upstream any reply regarding replicating * a request; replicated branch must stop at us*/ if (!replicate) { reply_ret=kill_transaction( t ); if (reply_ret>0) { /* we have taken care of all -- do nothing in script */ DBG("ERROR: generation of a stateful reply " "on error succeeded\n"); /*ret=0; -- we don't want to stop the script */ } else { DBG("ERROR: generation of a stateful reply " "on error failed\n"); t_release_transaction(t); } }else{ t_release_transaction(t); /* kill it silently */ } } else { DBG( "SER: new transaction fwd'ed\n"); } done: return ret; }
int t_relay_to( struct sip_msg *p_msg , struct proxy_l *proxy, int flags) { int ret; int new_tran; int reply_ret; struct cell *t; context_p ctx_backup; ret=0; new_tran = t_newtran( p_msg, 1/*full UAS cloning*/ ); /* parsing error, memory alloc, whatever ... */ if (new_tran<0) { ret = new_tran; goto done; } /* if that was a retransmission, break from script */ if (new_tran==0) { goto done; } /* new transaction */ /* ACKs do not establish a transaction and are fwd-ed statelessly */ if ( p_msg->REQ_METHOD==METHOD_ACK) { LM_DBG("forwarding ACK\n"); /* send it out */ if (proxy==0) { proxy=uri2proxy(GET_NEXT_HOP(p_msg), p_msg->force_send_socket ? p_msg->force_send_socket->proto : PROTO_NONE ); if (proxy==0) { ret=E_BAD_ADDRESS; goto done; } ret=forward_request( p_msg , proxy); if (ret>=0) ret=1; free_proxy( proxy ); pkg_free( proxy ); } else { ret=forward_request( p_msg , proxy); if (ret>=0) ret=1; } goto done; } /* if replication flag is set, mark the transaction as local so that replies will not be relaied */ t=get_t(); if (flags&TM_T_REPLY_repl_FLAG) t->flags|=T_IS_LOCAL_FLAG; if (flags&TM_T_REPLY_nodnsfo_FLAG) t->flags|=T_NO_DNS_FAILOVER_FLAG; if (flags&TM_T_REPLY_reason_FLAG) t->flags|=T_CANCEL_REASON_FLAG; /* INVITE processing might take long, particularly because of DNS look-ups -- let upstream know we're working on it */ if ( p_msg->REQ_METHOD==METHOD_INVITE && !(flags&(TM_T_REPLY_no100_FLAG|TM_T_REPLY_repl_FLAG)) ) { ctx_backup = current_processing_ctx; current_processing_ctx = NULL; t_reply( t, p_msg , 100 , &relay_reason_100); current_processing_ctx = ctx_backup; } /* now go ahead and forward ... */ ret=t_forward_nonack( t, p_msg, proxy); if (ret<=0) { LM_DBG("t_forward_nonack returned error \n"); /* we don't want to pass upstream any reply regarding replicating * a request; replicated branch must stop at us*/ if (!(flags&(TM_T_REPLY_repl_FLAG|TM_T_REPLY_noerr_FLAG))) { reply_ret = kill_transaction( t ); if (reply_ret>0) { /* we have taken care of all -- do nothing in script */ LM_DBG("generation of a stateful reply on error succeeded\n"); ret=0; } else { LM_DBG("generation of a stateful reply on error failed\n"); } } } else { LM_DBG("new transaction fwd'ed\n"); } done: return ret; }
/* Usage: follow the protocol to handle a request, and call right func Return: none */ void handle_request(struct name_prtl *name_request, int itemfd, int dbfd, int rservfd, int sockfd, int logfd, ssize_t n, int port, char *data) { int flag, result, m; char hostipaddr[16]; // chech which server should be responsible for the request flag = is_local(itemfd, name_request->name); if (flag == -1) { /* not have this kind of names */ // ask route server printf("[Info] ask routing server for the name\n"); result = route(rservfd, logfd, name_request->name[0], hostipaddr); if (result == -1) { /* fail */ fprintf(stderr, "[Error] route check failed\n"); write_log(logfd, "[Error] handle_request -- route check failed"); pkt_write(sockfd, 8, name_request->name, "fail to check route table"); } else if (result == 0) { /* new kind of names, add it locally */ // add new mapping first printf("[Info] find the corresponding server\n"); m = add_nameitem(itemfd, name_request->name[0]); if (m == -1) { fprintf(stderr, "[Error] fail to update indextable\n"); write_log(logfd, "[Error] handle_request -- update indextable error"); pkt_write(sockfd, 8, name_request->name, "fail to updata indextable"); } else { if (name_request->type == 2) { /* add new name */ printf("[Info] adding new name: %s\n", name_request->name); add_name(sockfd, dbfd, logfd, name_request); } else if (name_request->type == 1) { /* lookup */ printf("[Info] lookup name: %s\n", name_request->name); lookup_name(sockfd, dbfd, logfd, name_request); } else if (name_request->type == 3) { /* delete */ printf("[Info] delete name: %s\n", name_request->name); delete_name(sockfd, dbfd, logfd, name_request); } else if (name_request->type == 4) { /* update */ printf("[Info] update name: %s\n", name_request->name); update_name(sockfd, dbfd, logfd, name_request); } } } else if (result == 1) { /* there is another server which is responsible for this kind of names */ printf("[Info] forward request\n"); m = forward_request(sockfd, logfd, data, hostipaddr, port, n); if (m == -1) { /* fail */ fprintf(stderr, "[Error] fail to forward request\n"); pkt_write(sockfd, 8, name_request->name, "[Error] fail to forward pkt"); } } } else { /* find this kind of name locally */ if (name_request->type == 2) { /* add new name */ printf("[Info] adding new name: %s\n", name_request->name); add_name(sockfd, dbfd, logfd, name_request); } else if (name_request->type == 1) { /* lookup */ printf("[Info] lookup name: %s\n", name_request->name); lookup_name(sockfd, dbfd, logfd, name_request); } else if (name_request->type == 3) { /* delete */ printf("[Info] delete name: %s\n", name_request->name); delete_name(sockfd, dbfd, logfd, name_request); } else if (name_request->type == 4) { /* update */ printf("[Info] update name: %s\n", name_request->name); update_name(sockfd, dbfd, logfd, name_request); } } }
void cib_process_request(xmlNode * request, gboolean force_synchronous, gboolean privileged, gboolean from_peer, cib_client_t * cib_client) { int call_type = 0; int call_options = 0; gboolean process = TRUE; gboolean is_update = TRUE; gboolean needs_reply = TRUE; gboolean local_notify = FALSE; gboolean needs_forward = FALSE; gboolean global_update = crm_is_true(crm_element_value(request, F_CIB_GLOBAL_UPDATE)); xmlNode *op_reply = NULL; xmlNode *result_diff = NULL; int rc = pcmk_ok; const char *op = crm_element_value(request, F_CIB_OPERATION); const char *originator = crm_element_value(request, F_ORIG); const char *host = crm_element_value(request, F_CIB_HOST); const char *client_id = crm_element_value(request, F_CIB_CLIENTID); crm_trace("%s Processing msg %s", cib_our_uname, crm_element_value(request, F_SEQ)); cib_num_ops++; if (cib_num_ops == 0) { cib_num_fail = 0; cib_num_local = 0; cib_num_updates = 0; crm_info("Stats wrapped around"); } if (host != NULL && strlen(host) == 0) { host = NULL; } crm_element_value_int(request, F_CIB_CALLOPTS, &call_options); if (force_synchronous) { call_options |= cib_sync_call; } crm_trace("Processing %s message (%s) for %s...", from_peer ? "peer" : "local", from_peer ? originator : cib_our_uname, host ? host : "master"); rc = cib_get_operation_id(op, &call_type); if (rc != pcmk_ok) { /* TODO: construct error reply? */ crm_err("Pre-processing of command failed: %s", pcmk_strerror(rc)); return; } is_update = cib_op_modifies(call_type); if (is_update) { cib_num_updates++; } if (from_peer == FALSE) { parse_local_options(cib_client, call_type, call_options, host, op, &local_notify, &needs_reply, &process, &needs_forward); } else if (parse_peer_options(call_type, request, &local_notify, &needs_reply, &process, &needs_forward) == FALSE) { return; } crm_trace("Finished determining processing actions"); if (call_options & cib_discard_reply) { needs_reply = is_update; local_notify = FALSE; } if (needs_forward) { forward_request(request, cib_client, call_options); return; } if (cib_status != pcmk_ok) { rc = cib_status; crm_err("Operation ignored, cluster configuration is invalid." " Please repair and restart: %s", pcmk_strerror(cib_status)); op_reply = cib_construct_reply(request, the_cib, cib_status); } else if (process) { int level = LOG_INFO; const char *section = crm_element_value(request, F_CIB_SECTION); cib_num_local++; rc = cib_process_command(request, &op_reply, &result_diff, privileged); if (global_update) { switch (rc) { case pcmk_ok: case -pcmk_err_old_data: case -pcmk_err_diff_resync: case -pcmk_err_diff_failed: level = LOG_DEBUG_2; break; default: level = LOG_ERR; } } else if (safe_str_eq(op, CIB_OP_QUERY)) { level = LOG_DEBUG_2; } else if (rc != pcmk_ok) { cib_num_fail++; level = LOG_WARNING; } else if (safe_str_eq(op, CIB_OP_SLAVE)) { level = LOG_DEBUG_2; } else if (safe_str_eq(section, XML_CIB_TAG_STATUS)) { level = LOG_DEBUG_2; } do_crm_log_unlikely(level, "Operation complete: op %s for section %s (origin=%s/%s/%s, version=%s.%s.%s): %s (rc=%d)", op, section ? section : "'all'", originator ? originator : "local", crm_element_value(request, F_CIB_CLIENTNAME), crm_element_value(request, F_CIB_CALLID), the_cib ? crm_element_value(the_cib, XML_ATTR_GENERATION_ADMIN) : "0", the_cib ? crm_element_value(the_cib, XML_ATTR_GENERATION) : "0", the_cib ? crm_element_value(the_cib, XML_ATTR_NUMUPDATES) : "0", pcmk_strerror(rc), rc); if (op_reply == NULL && (needs_reply || local_notify)) { crm_err("Unexpected NULL reply to message"); crm_log_xml_err(request, "null reply"); needs_reply = FALSE; local_notify = FALSE; } } crm_trace("processing response cases %.16x %.16x", call_options, cib_sync_call); /* from now on we are the server */ if (needs_reply == FALSE || stand_alone) { /* nothing more to do... * this was a non-originating slave update */ crm_trace("Completed slave update"); } else if (rc == pcmk_ok && result_diff != NULL && !(call_options & cib_inhibit_bcast)) { gboolean broadcast = FALSE; cib_local_bcast_num++; crm_xml_add_int(request, F_CIB_LOCAL_NOTIFY_ID, cib_local_bcast_num); broadcast = send_peer_reply(request, result_diff, originator, TRUE); if (broadcast && client_id && local_notify && op_reply) { /* If we have been asked to sync the reply, * and a bcast msg has gone out, we queue the local notify * until we know the bcast message has been received */ local_notify = FALSE; queue_local_notify(op_reply, client_id, (call_options & cib_sync_call), from_peer); op_reply = NULL; /* the reply is queued, so don't free here */ } } else if (call_options & cib_discard_reply) { crm_trace("Caller isn't interested in reply"); } else if (from_peer) { if (is_update == FALSE || result_diff == NULL) { crm_trace("Request not broadcast: R/O call"); } else if (call_options & cib_inhibit_bcast) { crm_trace("Request not broadcast: inhibited"); } else if (rc != pcmk_ok) { crm_trace("Request not broadcast: call failed: %s", pcmk_strerror(rc)); } else { crm_trace("Directing reply to %s", originator); } send_peer_reply(op_reply, result_diff, originator, FALSE); } if (local_notify && client_id) { if (process == FALSE) { do_local_notify(request, client_id, call_options & cib_sync_call, from_peer); } else { do_local_notify(op_reply, client_id, call_options & cib_sync_call, from_peer); } } free_xml(op_reply); free_xml(result_diff); return; }
bool add_edge_h(connection_t *c) { edge_t *e; node_t *from, *to; char from_name[MAX_STRING_SIZE]; char to_name[MAX_STRING_SIZE]; char to_address[MAX_STRING_SIZE]; char to_port[MAX_STRING_SIZE]; sockaddr_t address; uint32_t options; int weight; if(sscanf(c->buffer, "%*d %*x "MAX_STRING" "MAX_STRING" "MAX_STRING" "MAX_STRING" %x %d", from_name, to_name, to_address, to_port, &options, &weight) != 6) { logger(LOG_ERR, "Got bad %s from %s (%s)", "ADD_EDGE", c->name, c->hostname); return false; } /* Check if names are valid */ if(!check_id(from_name) || !check_id(to_name)) { logger(LOG_ERR, "Got bad %s from %s (%s): %s", "ADD_EDGE", c->name, c->hostname, "invalid name"); return false; } if(seen_request(c->buffer)) return true; /* Lookup nodes */ from = lookup_node(from_name); to = lookup_node(to_name); if(tunnelserver && from != myself && from != c->node && to != myself && to != c->node) { /* ignore indirect edge registrations for tunnelserver */ ifdebug(PROTOCOL) logger(LOG_WARNING, "Ignoring indirect %s from %s (%s)", "ADD_EDGE", c->name, c->hostname); return true; } if(!from) { from = new_node(); from->name = xstrdup(from_name); node_add(from); } if(!to) { to = new_node(); to->name = xstrdup(to_name); node_add(to); } /* Convert addresses */ address = str2sockaddr(to_address, to_port); /* Check if edge already exists */ e = lookup_edge(from, to); if(e) { if(e->weight != weight || e->options != options || sockaddrcmp(&e->address, &address)) { if(from == myself) { ifdebug(PROTOCOL) logger(LOG_WARNING, "Got %s from %s (%s) for ourself which does not match existing entry", "ADD_EDGE", c->name, c->hostname); send_add_edge(c, e); return true; } else { ifdebug(PROTOCOL) logger(LOG_WARNING, "Got %s from %s (%s) which does not match existing entry", "ADD_EDGE", c->name, c->hostname); edge_del(e); graph(); } } else return true; } else if(from == myself) { ifdebug(PROTOCOL) logger(LOG_WARNING, "Got %s from %s (%s) for ourself which does not exist", "ADD_EDGE", c->name, c->hostname); contradicting_add_edge++; e = new_edge(); e->from = from; e->to = to; send_del_edge(c, e); free_edge(e); return true; } e = new_edge(); e->from = from; e->to = to; e->address = address; e->options = options; e->weight = weight; edge_add(e); /* Tell the rest about the new edge */ if(!tunnelserver) forward_request(c); /* Run MST before or after we tell the rest? */ graph(); return true; }
bool add_edge_h(meshlink_handle_t *mesh, connection_t *c, const char *request) { edge_t *e; node_t *from, *to; char from_name[MAX_STRING_SIZE]; int from_devclass; char to_name[MAX_STRING_SIZE]; char to_address[MAX_STRING_SIZE]; char to_port[MAX_STRING_SIZE]; int to_devclass; sockaddr_t address; uint32_t options; int weight; if(sscanf(request, "%*d %*x "MAX_STRING" %d "MAX_STRING" "MAX_STRING" "MAX_STRING" %d %x %d", from_name, &from_devclass, to_name, to_address, to_port, &to_devclass, &options, &weight) != 8) { logger(mesh, MESHLINK_ERROR, "Got bad %s from %s (%s)", "ADD_EDGE", c->name, c->hostname); return false; } /* Check if names are valid */ if(!check_id(from_name) || !check_id(to_name)) { logger(mesh, MESHLINK_ERROR, "Got bad %s from %s (%s): %s", "ADD_EDGE", c->name, c->hostname, "invalid name"); return false; } // Check if devclasses are valid if(from_devclass < 0 || from_devclass > _DEV_CLASS_MAX) { logger(mesh, MESHLINK_ERROR, "Got bad %s from %s (%s): %s", "ADD_EDGE", c->name, c->hostname, "from devclass invalid"); return false; } if(to_devclass < 0 || to_devclass > _DEV_CLASS_MAX) { logger(mesh, MESHLINK_ERROR, "Got bad %s from %s (%s): %s", "ADD_EDGE", c->name, c->hostname, "to devclass invalid"); return false; } if(seen_request(mesh, request)) return true; /* Lookup nodes */ from = lookup_node(mesh, from_name); to = lookup_node(mesh, to_name); if(!from) { from = new_node(); from->status.blacklisted = mesh->default_blacklist; from->name = xstrdup(from_name); node_add(mesh, from); } from->devclass = from_devclass; node_write_devclass(mesh, from); if(!to) { to = new_node(); to->status.blacklisted = mesh->default_blacklist; to->name = xstrdup(to_name); node_add(mesh, to); } to->devclass = to_devclass; node_write_devclass(mesh, to); /* Convert addresses */ address = str2sockaddr(to_address, to_port); /* Check if edge already exists */ e = lookup_edge(from, to); if(e) { if(e->weight != weight || e->options != options || sockaddrcmp(&e->address, &address)) { if(from == mesh->self) { logger(mesh, MESHLINK_WARNING, "Got %s from %s (%s) for ourself which does not match existing entry", "ADD_EDGE", c->name, c->hostname); send_add_edge(mesh, c, e); return true; } else { logger(mesh, MESHLINK_WARNING, "Got %s from %s (%s) which does not match existing entry", "ADD_EDGE", c->name, c->hostname); edge_del(mesh, e); graph(mesh); } } else return true; } else if(from == mesh->self) { logger(mesh, MESHLINK_WARNING, "Got %s from %s (%s) for ourself which does not exist", "ADD_EDGE", c->name, c->hostname); mesh->contradicting_add_edge++; e = new_edge(); e->from = from; e->to = to; send_del_edge(mesh, c, e); free_edge(e); return true; } e = new_edge(); e->from = from; e->to = to; e->address = address; e->options = options; e->weight = weight; edge_add(mesh, e); /* Tell the rest about the new edge */ forward_request(mesh, c, request); /* Run MST before or after we tell the rest? */ graph(mesh); return true; }
/* ret= 0! if action -> end of list(e.g DROP), > 0 to continue processing next actions and <0 on error */ int do_action(struct action* a, struct sip_msg* msg) { int ret; int v; int sec,usec; union sockaddr_union* to; struct proxy_l* p; char* tmp; char *new_uri, *end, *crt; int len,i; int user = 0; int expires = 0; str vals[5]; str result; struct sip_uri uri, next_hop; struct sip_uri *u; unsigned short port; int cmatch; struct action *aitem; struct action *adefault; pv_spec_t *spec; pv_elem_p model; pv_value_t val; pv_elem_t *pve; str name_s; struct timeval start; int end_time; action_elem_t *route_params_bak; int route_params_number_bak; /* reset the value of error to E_UNSPEC so avoid unknowledgable functions to return with error (status<0) and not setting it leaving there previous error; cache the previous value though for functions which want to process it */ prev_ser_error=ser_error; ser_error=E_UNSPEC; start_expire_timer(start,execmsgthreshold); ret=E_BUG; switch ((unsigned char)a->type){ case DROP_T: script_trace("core", "drop", msg, a->line) ; action_flags |= ACT_FL_DROP; case EXIT_T: script_trace("core", "exit", msg, a->line) ; ret=0; action_flags |= ACT_FL_EXIT; break; case RETURN_T: script_trace("core", "return", msg, a->line) ; if (a->elem[0].type == SCRIPTVAR_ST) { spec = (pv_spec_t*)a->elem[0].u.data; if(pv_get_spec_value(msg, spec, &val)!=0 || (val.flags&PV_VAL_NULL)) { ret=-1; } else { if(!(val.flags&PV_VAL_INT)) ret = 1; else ret = val.ri; } pv_value_destroy(&val); } else { ret=a->elem[0].u.number; } action_flags |= ACT_FL_RETURN; break; case FORWARD_T: script_trace("core", "forward", msg, a->line) ; if (a->elem[0].type==NOSUBTYPE){ /* parse uri and build a proxy */ if (msg->dst_uri.len) { ret = parse_uri(msg->dst_uri.s, msg->dst_uri.len, &next_hop); u = &next_hop; } else { ret = parse_sip_msg_uri(msg); u = &msg->parsed_uri; } if (ret<0) { LM_ERR("forward: bad_uri dropping packet\n"); break; } /* create a temporary proxy*/ p=mk_proxy(u->maddr_val.len?&u->maddr_val:&u->host, u->port_no, u->proto, (u->type==SIPS_URI_T)?1:0 ); if (p==0){ LM_ERR("bad host name in uri, dropping packet\n"); ret=E_BAD_ADDRESS; goto error_fwd_uri; } ret=forward_request(msg, p); free_proxy(p); /* frees only p content, not p itself */ pkg_free(p); if (ret==0) ret=1; }else if ((a->elem[0].type==PROXY_ST)) { ret=forward_request(msg,(struct proxy_l*)a->elem[0].u.data); if (ret==0) ret=1; }else{ LM_ALERT("BUG in forward() types %d, %d\n", a->elem[0].type, a->elem[1].type); ret=E_BUG; } break; case SEND_T: script_trace("core", "send", msg, a->line) ; if (a->elem[0].type!= PROXY_ST){ LM_ALERT("BUG in send() type %d\n", a->elem[0].type); ret=E_BUG; break; } if (a->elem[1].u.data) { if (a->elem[1].type != SCRIPTVAR_ELEM_ST){ LM_ALERT("BUG in send() header type %d\n",a->elem[1].type); ret=E_BUG; break; } else { pve = (pv_elem_t *)a->elem[1].u.data; } } else { pve = NULL; } to=(union sockaddr_union*) pkg_malloc(sizeof(union sockaddr_union)); if (to==0){ LM_ERR("memory allocation failure\n"); ret=E_OUT_OF_MEM; break; } p=(struct proxy_l*)a->elem[0].u.data; ret=hostent2su(to, &p->host, p->addr_idx, (p->port)?p->port:SIP_PORT ); if (ret==0){ if (pve) { if ( pv_printf_s(msg, pve, &name_s)!=0 || name_s.len == 0 || name_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_UNSPEC; break; } /* build new msg */ tmp = pkg_malloc(msg->len + name_s.len); if (!tmp) { LM_ERR("memory allocation failure\n"); ret = E_OUT_OF_MEM; break; } LM_DBG("searching for first line %d\n", msg->first_line.len); /* search first line of previous msg */ /* copy headers */ len = msg->first_line.len; memcpy(tmp, msg->buf, len); memcpy(tmp + len, name_s.s, name_s.len); memcpy(tmp + len + name_s.len, msg->buf + len, msg->len - len); ret = msg_send(0/*send_sock*/, p->proto, to, 0/*id*/, tmp, msg->len + name_s.len); pkg_free(tmp); } else { ret = msg_send(0/*send_sock*/, p->proto, to, 0/*id*/, msg->buf, msg->len); } if (ret!=0 && p->host.h_addr_list[p->addr_idx+1]) p->addr_idx++; } pkg_free(to); if (ret==0) ret=1; break; case LOG_T: script_trace("core", "log", msg, a->line) ; if ((a->elem[0].type!=NUMBER_ST)|(a->elem[1].type!=STRING_ST)){ LM_ALERT("BUG in log() types %d, %d\n", a->elem[0].type, a->elem[1].type); ret=E_BUG; break; } LM_GEN1(a->elem[0].u.number, "%s", a->elem[1].u.string); ret=1; break; case APPEND_BRANCH_T: script_trace("core", "append_branch", msg, a->line) ; if ((a->elem[0].type!=STR_ST)) { LM_ALERT("BUG in append_branch %d\n", a->elem[0].type ); ret=E_BUG; break; } if (a->elem[0].u.s.s==NULL) { ret = append_branch(msg, 0, &msg->dst_uri, &msg->path_vec, get_ruri_q(), getb0flags(), msg->force_send_socket); /* reset all branch info */ msg->force_send_socket = 0; setb0flags(0); set_ruri_q(Q_UNSPECIFIED); if(msg->dst_uri.s!=0) pkg_free(msg->dst_uri.s); msg->dst_uri.s = 0; msg->dst_uri.len = 0; if(msg->path_vec.s!=0) pkg_free(msg->path_vec.s); msg->path_vec.s = 0; msg->path_vec.len = 0; } else { ret = append_branch(msg, &a->elem[0].u.s, &msg->dst_uri, &msg->path_vec, a->elem[1].u.number, getb0flags(), msg->force_send_socket); } break; case REMOVE_BRANCH_T: script_trace("core", "remove_branch", msg, a->line) ; if (a->elem[0].type == SCRIPTVAR_ST) { spec = (pv_spec_t*)a->elem[0].u.data; if( pv_get_spec_value(msg, spec, &val)!=0 || (val.flags&PV_VAL_NULL) || !(val.flags&PV_VAL_INT) ) { ret=-1; break; } i = val.ri; } else { i=a->elem[0].u.number; } ret = (remove_branch((unsigned int)i)==0)?1:-1; break; case LEN_GT_T: script_trace("core", "len_gt", msg, a->line) ; if (a->elem[0].type!=NUMBER_ST) { LM_ALERT("BUG in len_gt type %d\n", a->elem[0].type ); ret=E_BUG; break; } ret = (msg->len >= (unsigned int)a->elem[0].u.number) ? 1 : -1; break; case SET_DEBUG_T: script_trace("core", "set_debug", msg, a->line) ; if (a->elem[0].type==NUMBER_ST) set_proc_debug_level(a->elem[0].u.number); else reset_proc_debug_level(); ret = 1; break; case SETFLAG_T: script_trace("core", "setflag", msg, a->line) ; ret = setflag( msg, a->elem[0].u.number ); break; case RESETFLAG_T: script_trace("core", "resetflag", msg, a->line) ; ret = resetflag( msg, a->elem[0].u.number ); break; case ISFLAGSET_T: script_trace("core", "isflagset", msg, a->line) ; ret = isflagset( msg, a->elem[0].u.number ); break; case SETSFLAG_T: script_trace("core", "setsflag", msg, a->line) ; ret = setsflag( a->elem[0].u.number ); break; case RESETSFLAG_T: script_trace("core", "resetsflag", msg, a->line) ; ret = resetsflag( a->elem[0].u.number ); break; case ISSFLAGSET_T: script_trace("core", "issflagset", msg, a->line) ; ret = issflagset( a->elem[0].u.number ); break; case SETBFLAG_T: script_trace("core", "setbflag", msg, a->line) ; ret = setbflag( a->elem[0].u.number, a->elem[1].u.number ); break; case RESETBFLAG_T: script_trace("core", "resetbflag", msg, a->line) ; ret = resetbflag( a->elem[0].u.number, a->elem[1].u.number ); break; case ISBFLAGSET_T: script_trace("core", "isbflagset", msg, a->line) ; ret = isbflagset( a->elem[0].u.number, a->elem[1].u.number ); break; case ERROR_T: script_trace("core", "error", msg, a->line) ; if ((a->elem[0].type!=STRING_ST)|(a->elem[1].type!=STRING_ST)){ LM_ALERT("BUG in error() types %d, %d\n", a->elem[0].type, a->elem[1].type); ret=E_BUG; break; } LM_ERR("error(\"%s\", \"%s\") not implemented yet\n", a->elem[0].u.string, a->elem[1].u.string); ret=1; break; case ROUTE_T: script_trace("route", rlist[a->elem[0].u.number].name, msg, a->line) ; if (a->elem[0].type!=NUMBER_ST){ LM_ALERT("BUG in route() type %d\n", a->elem[0].type); ret=E_BUG; break; } if ((a->elem[0].u.number>RT_NO)||(a->elem[0].u.number<0)){ LM_ALERT("BUG - invalid routing table number in" "route(%lu)\n", a->elem[0].u.number); ret=E_CFG; break; } /* check if the route has parameters */ if (a->elem[1].type != 0) { if (a->elem[1].type != NUMBER_ST || a->elem[2].type != SCRIPTVAR_ELEM_ST) { LM_ALERT("BUG in route() type %d/%d\n", a->elem[1].type, a->elem[2].type); ret=E_BUG; break; } route_params_bak = route_params; route_params = (action_elem_t *)a->elem[2].u.data; route_params_number_bak = route_params_number; route_params_number = a->elem[1].u.number; return_code=run_actions(rlist[a->elem[0].u.number].a, msg); route_params = route_params_bak; route_params_number = route_params_number_bak; } else { return_code=run_actions(rlist[a->elem[0].u.number].a, msg); } ret=return_code; break; case REVERT_URI_T: script_trace("core", "revert_uri", msg, a->line) ; if (msg->new_uri.s) { pkg_free(msg->new_uri.s); msg->new_uri.len=0; msg->new_uri.s=0; msg->parsed_uri_ok=0; /* invalidate current parsed uri*/ }; ret=1; break; case SET_HOST_T: case SET_HOSTPORT_T: case SET_USER_T: case SET_USERPASS_T: case SET_PORT_T: case SET_URI_T: case PREFIX_T: case STRIP_T: case STRIP_TAIL_T: script_trace("core", (unsigned char)a->type == SET_HOST_T ? "set_host" : (unsigned char)a->type == SET_HOSTPORT_T ? "set_hostport" : (unsigned char)a->type == SET_USER_T ? "set_user" : (unsigned char)a->type == SET_USERPASS_T ? "set_userpass" : (unsigned char)a->type == SET_PORT_T ? "set_port" : (unsigned char)a->type == SET_URI_T ? "set_uri" : (unsigned char)a->type == PREFIX_T ? "prefix" : (unsigned char)a->type == STRIP_T ? "strip" : "strip_tail", msg, a->line); user=0; if (a->type==STRIP_T || a->type==STRIP_TAIL_T) { if (a->elem[0].type!=NUMBER_ST) { LM_ALERT("BUG in set*() type %d\n", a->elem[0].type); break; } } else if (a->elem[0].type!=STR_ST){ LM_ALERT("BUG in set*() type %d\n", a->elem[0].type); ret=E_BUG; break; } if (a->type==SET_URI_T) { if (set_ruri( msg, &a->elem[0].u.s) ) { LM_ERR("failed to set new RURI\n"); ret=E_OUT_OF_MEM; break; } ret=1; break; } if (msg->new_uri.s) { tmp=msg->new_uri.s; len=msg->new_uri.len; }else{ tmp=msg->first_line.u.request.uri.s; len=msg->first_line.u.request.uri.len; } if (parse_uri(tmp, len, &uri)<0){ LM_ERR("bad uri <%.*s>, dropping packet\n", len, tmp); ret=E_UNSPEC; break; } new_uri=pkg_malloc(MAX_URI_SIZE); if (new_uri==0){ LM_ERR("memory allocation failure\n"); ret=E_OUT_OF_MEM; break; } end=new_uri+MAX_URI_SIZE; crt=new_uri; /* begin copying */ len = (uri.user.len?uri.user.s:uri.host.s) - tmp; if (crt+len>end) goto error_uri; memcpy(crt,tmp,len);crt+=len; if (a->type==PREFIX_T) { if (crt+a->elem[0].u.s.len>end) goto error_uri; memcpy( crt, a->elem[0].u.s.s, a->elem[0].u.s.len); crt+=a->elem[0].u.s.len; /* whatever we had before, with prefix we have username now */ user=1; } if ((a->type==SET_USER_T)||(a->type==SET_USERPASS_T)) { tmp=a->elem[0].u.s.s; len=a->elem[0].u.s.len; } else if (a->type==STRIP_T) { if (a->elem[0].u.number>uri.user.len) { LM_WARN("too long strip asked; " " deleting username: %lu of <%.*s>\n", a->elem[0].u.number, uri.user.len, uri.user.s); len=0; } else if (a->elem[0].u.number==uri.user.len) { len=0; } else { tmp=uri.user.s + a->elem[0].u.number; len=uri.user.len - a->elem[0].u.number; } } else if (a->type==STRIP_TAIL_T) { if (a->elem[0].u.number>uri.user.len) { LM_WARN("too long strip_tail asked;" " deleting username: %lu of <%.*s>\n", a->elem[0].u.number, uri.user.len, uri.user.s); len=0; } else if (a->elem[0].u.number==uri.user.len) { len=0; } else { tmp=uri.user.s; len=uri.user.len - a->elem[0].u.number; } } else { tmp=uri.user.s; len=uri.user.len; } if (len){ if(crt+len>end) goto error_uri; memcpy(crt,tmp,len);crt+=len; user=1; /* we have an user field so mark it */ } if (a->type==SET_USERPASS_T) tmp=0; else tmp=uri.passwd.s; /* passwd */ if (tmp){ len=uri.passwd.len; if(crt+len+1>end) goto error_uri; *crt=':'; crt++; memcpy(crt,tmp,len);crt+=len; } /* host */ if (user || tmp){ /* add @ */ if(crt+1>end) goto error_uri; *crt='@'; crt++; } if ((a->type==SET_HOST_T) ||(a->type==SET_HOSTPORT_T)) { tmp=a->elem[0].u.s.s; len=a->elem[0].u.s.len; } else { tmp=uri.host.s; len = uri.host.len; } if (tmp){ if(crt+len>end) goto error_uri; memcpy(crt,tmp,len);crt+=len; } /* port */ if (a->type==SET_HOSTPORT_T) tmp=0; else if (a->type==SET_PORT_T) { tmp=a->elem[0].u.s.s; len=a->elem[0].u.s.len; } else { tmp=uri.port.s; len = uri.port.len; } if (tmp && len>0){ if(crt+len+1>end) goto error_uri; *crt=':'; crt++; memcpy(crt,tmp,len);crt+=len; } /* params */ tmp=uri.params.s; if (tmp){ /* include in param string the starting ';' */ len=uri.params.len+1; tmp--; if(crt+len+1>end) goto error_uri; /* if a maddr param is present, strip it out */ if (uri.maddr.len && (a->type==SET_HOSTPORT_T || a->type==SET_HOST_T)) { memcpy(crt,tmp,uri.maddr.s-tmp-1); crt+=uri.maddr.s-tmp-1; memcpy(crt,uri.maddr_val.s+uri.maddr_val.len, tmp+len-uri.maddr_val.s-uri.maddr_val.len); crt+=tmp+len-uri.maddr_val.s-uri.maddr_val.len; } else { memcpy(crt,tmp,len);crt+=len; } } /* headers */ tmp=uri.headers.s; if (tmp){ len=uri.headers.len; if(crt+len+1>end) goto error_uri; *crt='?'; crt++; memcpy(crt,tmp,len);crt+=len; } *crt=0; /* null terminate the thing */ /* copy it to the msg */ if (msg->new_uri.s) pkg_free(msg->new_uri.s); msg->new_uri.s=new_uri; msg->new_uri.len=crt-new_uri; msg->parsed_uri_ok=0; ret=1; break; case SET_DSTURI_T: script_trace("core", "set_dsturi", msg, a->line) ; if (a->elem[0].type!=STR_ST){ LM_ALERT("BUG in setdsturi() type %d\n", a->elem[0].type); ret=E_BUG; break; } if(set_dst_uri(msg, &a->elem[0].u.s)!=0) ret = -1; else ret = 1; break; case SET_DSTHOST_T: case SET_DSTPORT_T: script_trace("core", (unsigned char) a->type == SET_DSTHOST_T ? "set_dsturi" : "set_dstport", msg, a->line); if (a->elem[0].type!=STR_ST){ LM_ALERT("BUG in domain setting type %d\n", a->elem[0].type); ret=E_BUG; break; } tmp = msg->dst_uri.s; len = msg->dst_uri.len; if (tmp == NULL || len == 0) { LM_ERR("failure - null uri\n"); ret = E_UNSPEC; break; } if (a->type == SET_DSTHOST_T && (a->elem[0].u.s.s == NULL || a->elem[0].u.s.len == 0)) { LM_ERR("cannot set a null uri domain\n"); break; } if (parse_uri(tmp, len, &uri)<0) { LM_ERR("bad uri <%.*s>, dropping packet\n", len, tmp); break; } new_uri=pkg_malloc(MAX_URI_SIZE); if (new_uri == NULL) { LM_ERR("memory allocation failure\n"); ret=E_OUT_OF_MEM; break; } end=new_uri+MAX_URI_SIZE; crt=new_uri; len = (uri.user.len?uri.user.s:uri.host.s) - tmp; if (crt+len>end) goto error_uri; memcpy(crt,tmp,len); crt += len; /* user */ tmp = uri.user.s; len = uri.user.len; if (tmp) { if (crt+len>end) goto error_uri; memcpy(crt,tmp,len); crt += len; user = 1; } /* passwd */ tmp = uri.passwd.s; len = uri.passwd.len; if (user || tmp) { if (crt+len+1>end) goto error_uri; *crt++=':'; memcpy(crt, tmp, len); crt += len; } /* host */ if (a->type==SET_DSTHOST_T) { tmp = a->elem[0].u.s.s; len = a->elem[0].u.s.len; } else { tmp = uri.host.s; len = uri.host.len; } if (tmp) { if (user) { if (crt+1>end) goto error_uri; *crt++='@'; } if (crt+len+1>end) goto error_uri; memcpy(crt, tmp, len); crt += len; } /* port */ if (a->type==SET_DSTPORT_T) { tmp = a->elem[0].u.s.s; len = a->elem[0].u.s.len; } else { tmp = uri.port.s; len = uri.port.len; } if (tmp) { if (crt+len+1>end) goto error_uri; *crt++=':'; memcpy(crt, tmp, len); crt += len; } /* params */ tmp=uri.params.s; if (tmp){ len=uri.params.len; if(crt+len+1>end) goto error_uri; *crt++=';'; memcpy(crt,tmp,len); crt += len; } /* headers */ tmp=uri.headers.s; if (tmp){ len=uri.headers.len; if(crt+len+1>end) goto error_uri; *crt++='?'; memcpy(crt,tmp,len); crt += len; } *crt=0; /* null terminate the thing */ /* copy it to the msg */ pkg_free(msg->dst_uri.s); msg->dst_uri.s=new_uri; msg->dst_uri.len=crt-new_uri; ret = 1; break; case RESET_DSTURI_T: script_trace("core", "reset_dsturi", msg, a->line) ; if(msg->dst_uri.s!=0) pkg_free(msg->dst_uri.s); msg->dst_uri.s = 0; msg->dst_uri.len = 0; ret = 1; break; case ISDSTURISET_T: script_trace("core", "isdsturiset", msg, a->line) ; if(msg->dst_uri.s==0 || msg->dst_uri.len<=0) ret = -1; else ret = 1; break; case IF_T: script_trace("core", "if", msg, a->line) ; /* if null expr => ignore if? */ if ((a->elem[0].type==EXPR_ST)&&a->elem[0].u.data){ v=eval_expr((struct expr*)a->elem[0].u.data, msg, 0); /* set return code to expr value */ if (v<0 || (action_flags&ACT_FL_RETURN) || (action_flags&ACT_FL_EXIT) ){ if (v==EXPR_DROP || (action_flags&ACT_FL_RETURN) || (action_flags&ACT_FL_EXIT) ){ /* hack to quit on DROP*/ ret=0; return_code = 0; break; }else{ LM_WARN("error in expression (l=%d)\n", a->line); } } ret=1; /*default is continue */ if (v>0) { if ((a->elem[1].type==ACTIONS_ST)&&a->elem[1].u.data){ ret=run_action_list( (struct action*)a->elem[1].u.data,msg ); return_code = ret; } else return_code = v; }else{ if ((a->elem[2].type==ACTIONS_ST)&&a->elem[2].u.data){ ret=run_action_list( (struct action*)a->elem[2].u.data,msg); return_code = ret; } else return_code = v; } } break; case WHILE_T: script_trace("core", "while", msg, a->line) ; /* if null expr => ignore if? */ if ((a->elem[0].type==EXPR_ST)&&a->elem[0].u.data){ len = 0; while(1) { if(len++ >= max_while_loops) { LM_INFO("max while loops are encountered\n"); break; } v=eval_expr((struct expr*)a->elem[0].u.data, msg, 0); /* set return code to expr value */ if (v<0 || (action_flags&ACT_FL_RETURN) || (action_flags&ACT_FL_EXIT) ){ if (v==EXPR_DROP || (action_flags&ACT_FL_RETURN) || (action_flags&ACT_FL_EXIT) ){ ret=0; return_code = 0; break; }else{ LM_WARN("error in expression (l=%d)\n", a->line); } } ret=1; /*default is continue */ if (v>0) { if ((a->elem[1].type==ACTIONS_ST) &&a->elem[1].u.data){ ret=run_action_list( (struct action*)a->elem[1].u.data,msg ); /* check if return was done */ if ((action_flags&ACT_FL_RETURN) || (action_flags&ACT_FL_EXIT) ){ break; } return_code = ret; } else { /* we should not get here */ return_code = v; break; } } else { /* condition was false */ return_code = v; break; } } } break; case CACHE_STORE_T: script_trace("core", "cache_store", msg, a->line) ; if ((a->elem[0].type!=STR_ST)) { LM_ALERT("BUG in cache_store() - first argument not of" " type string [%d]\n", a->elem[0].type ); ret=E_BUG; break; } if ((a->elem[1].type!=STR_ST)) { LM_ALERT("BUG in cache_store() - second argument not of " "type string [%d]\n", a->elem[1].type ); ret=E_BUG; break; } if ((a->elem[2].type!=STR_ST)) { LM_ALERT("BUG in cache_store() - third argument not of type" " string%d\n", a->elem[2].type ); ret=E_BUG; break; } str val_s; /* parse the name argument */ pve = (pv_elem_t *)a->elem[1].u.data; if ( pv_printf_s(msg, pve, &name_s)!=0 || name_s.len == 0 || name_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; break; } /* parse the value argument */ pve = (pv_elem_t *)a->elem[2].u.data; if ( pv_printf_s(msg, pve, &val_s)!=0 || val_s.len == 0 || val_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; break; } /* get the expires value */ if ( a->elem[3].type == SCRIPTVAR_ST ) { spec = (pv_spec_t*)a->elem[3].u.data; memset(&val, 0, sizeof(pv_value_t)); if(pv_get_spec_value(msg, spec, &val) < 0) { LM_DBG("Failed to get scriptvar value while executing cache_store\n"); ret=E_BUG; break; } if (!(val.flags&PV_VAL_INT)) { LM_ERR("Wrong value for cache_store expires, not an integer [%.*s]\n", val.rs.len, val.rs.s); } expires = val.ri; } else if ( a->elem[3].type == NUMBER_ST ) { expires = (int)a->elem[3].u.number; } ret = cachedb_store( &a->elem[0].u.s, &name_s, &val_s,expires); break; case CACHE_REMOVE_T: script_trace("core", "cache_remove", msg, a->line) ; if ((a->elem[0].type!=STR_ST)) { LM_ALERT("BUG in cache_remove() %d\n", a->elem[0].type ); ret=E_BUG; break; } if ((a->elem[1].type!=STR_ST)) { LM_ALERT("BUG in cache_remove() %d\n", a->elem[1].type ); ret=E_BUG; break; } /* parse the name argument */ pve = (pv_elem_t *)a->elem[1].u.data; if ( pv_printf_s(msg, pve, &name_s)!=0 || name_s.len == 0 || name_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; break; } ret = cachedb_remove( &a->elem[0].u.s, &name_s); break; case CACHE_FETCH_T: script_trace("core", "cache_fetch", msg, a->line) ; if ((a->elem[0].type!=STR_ST)) { LM_ALERT("BUG in cache_fetch() %d\n", a->elem[0].type ); ret=E_BUG; break; } if ((a->elem[1].type!=STR_ST)) { LM_ALERT("BUG in cache_fetch() %d\n", a->elem[1].type ); ret=E_BUG; break; } if (a->elem[2].type!=SCRIPTVAR_ST){ LM_ALERT("BUG in cache_fetch() type %d\n", a->elem[2].type); ret=E_BUG; break; } str aux = {0, 0}; /* parse the name argument */ pve = (pv_elem_t *)a->elem[1].u.data; if ( pv_printf_s(msg, pve, &name_s)!=0 || name_s.len == 0 || name_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; break; } ret = cachedb_fetch( &a->elem[0].u.s, &name_s, &aux); if(ret > 0) { val.rs = aux; val.flags = PV_VAL_STR; spec = (pv_spec_t*)a->elem[2].u.data; if (pv_set_value(msg, spec, 0, &val) < 0) { LM_ERR("cannot set the variable value\n"); pkg_free(aux.s); return -1; } pkg_free(aux.s); } break; case CACHE_COUNTER_FETCH_T: script_trace("core", "cache_counter_fetch", msg, a->line) ; if ((a->elem[0].type!=STR_ST)) { LM_ALERT("BUG in cache_fetch() %d\n", a->elem[0].type ); ret=E_BUG; break; } if ((a->elem[1].type!=STR_ST)) { LM_ALERT("BUG in cache_fetch() %d\n", a->elem[1].type ); ret=E_BUG; break; } if (a->elem[2].type!=SCRIPTVAR_ST){ LM_ALERT("BUG in cache_fetch() type %d\n", a->elem[2].type); ret=E_BUG; break; } int aux_counter; /* parse the name argument */ pve = (pv_elem_t *)a->elem[1].u.data; if ( pv_printf_s(msg, pve, &name_s)!=0 || name_s.len == 0 || name_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; break; } ret = cachedb_counter_fetch( &a->elem[0].u.s, &name_s, &aux_counter); if(ret > 0) { val.ri = aux_counter; val.flags = PV_TYPE_INT|PV_VAL_INT; spec = (pv_spec_t*)a->elem[2].u.data; if (pv_set_value(msg, spec, 0, &val) < 0) { LM_ERR("cannot set the variable value\n"); pkg_free(aux.s); return -1; } } break; case CACHE_ADD_T: script_trace("core", "cache_add", msg, a->line) ; if ((a->elem[0].type!=STR_ST)) { LM_ALERT("BUG in cache_add() - first argument not of" " type string [%d]\n", a->elem[0].type ); ret=E_BUG; break; } if ((a->elem[1].type!=STR_ST)) { LM_ALERT("BUG in cache_add() - second argument not of " "type string [%d]\n", a->elem[1].type ); ret=E_BUG; break; } /* parse the name argument */ pve = (pv_elem_t *)a->elem[1].u.data; if ( pv_printf_s(msg, pve, &name_s)!=0 || name_s.len == 0 || name_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; break; } int increment=0; /* get the increment value */ if ( a->elem[2].type == SCRIPTVAR_ST ) { spec = (pv_spec_t*)a->elem[2].u.data; memset(&val, 0, sizeof(pv_value_t)); if(pv_get_spec_value(msg, spec, &val) < 0) { LM_DBG("Failed to get scriptvar value while executing cache_add\n"); ret=E_BUG; break; } if (!(val.flags&PV_VAL_INT)) { LM_ERR("Wrong value for cache_add, not an integer [%.*s]\n", val.rs.len, val.rs.s); } increment = val.ri; } else if ( a->elem[2].type == NUMBER_ST ) { increment = (int)a->elem[2].u.number; } expires = (int)a->elem[3].u.number; /* TODO - return the new value to script ? */ ret = cachedb_add(&a->elem[0].u.s, &name_s, increment,expires,NULL); break; case CACHE_SUB_T: script_trace("core", "cache_sub", msg, a->line) ; if ((a->elem[0].type!=STR_ST)) { LM_ALERT("BUG in cache_sub() - first argument not of" " type string [%d]\n", a->elem[0].type ); ret=E_BUG; break; } if ((a->elem[1].type!=STR_ST)) { LM_ALERT("BUG in cache_sub() - second argument not of " "type string [%d]\n", a->elem[1].type ); ret=E_BUG; break; } /* parse the name argument */ pve = (pv_elem_t *)a->elem[1].u.data; if ( pv_printf_s(msg, pve, &name_s)!=0 || name_s.len == 0 || name_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; break; } int decrement=0; /* get the increment value */ if ( a->elem[2].type == SCRIPTVAR_ST ) { spec = (pv_spec_t*)a->elem[2].u.data; memset(&val, 0, sizeof(pv_value_t)); if(pv_get_spec_value(msg, spec, &val) < 0) { LM_DBG("Failed to get scriptvar value while executing cache_sub\n"); ret=E_BUG; break; } if (!(val.flags&PV_VAL_INT)) { LM_ERR("Wrong value for cache_sub, not an integer [%.*s]\n", val.rs.len, val.rs.s); } decrement = val.ri; } else if ( a->elem[2].type == NUMBER_ST ) { decrement = (int)a->elem[2].u.number; } expires = (int)a->elem[3].u.number; /* TODO - return new value to script ? */ ret = cachedb_sub(&a->elem[0].u.s, &name_s, decrement,expires,NULL); break; case CACHE_RAW_QUERY_T: if ((a->elem[0].type!=STR_ST)) { LM_ALERT("BUG in cache_fetch() %d\n", a->elem[0].type ); ret=E_BUG; break; } if ((a->elem[1].type!=STR_ST)) { LM_ALERT("BUG in cache_fetch() %d\n", a->elem[1].type ); ret=E_BUG; break; } if (a->elem[2].u.data != NULL && a->elem[2].type!=STR_ST){ LM_ALERT("BUG in cache_raw_query() type %d\n", a->elem[2].type); ret=E_BUG; break; } /* parse the name argument */ pve = (pv_elem_t *)a->elem[1].u.data; if ( pv_printf_s(msg, pve, &name_s)!=0 || name_s.len == 0 || name_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; break; } cdb_raw_entry **cdb_reply; int val_number=0,i,j; int key_number=0; pvname_list_t *cdb_res,*it; int_str avp_val; int_str avp_name; unsigned short avp_type; if (a->elem[2].u.data) { cdb_res = (pvname_list_t*)a->elem[2].u.data; for (it=cdb_res;it;it=it->next) val_number++; LM_DBG("The query expects %d results back\n",val_number); ret = cachedb_raw_query( &a->elem[0].u.s, &name_s, &cdb_reply,val_number,&key_number); if (ret >= 0 && val_number > 0) { for (i=key_number-1; i>=0;i--) { it=cdb_res; for (j=0;j < val_number;j++) { avp_type = 0; if (pv_get_avp_name(msg,&it->sname.pvp,&avp_name.n, &avp_type) != 0) { LM_ERR("cannot get avp name [%d/%d]\n",i,j); goto next_avp; } switch (cdb_reply[i][j].type) { case CDB_INT: avp_val.n = cdb_reply[i][j].val.n; break; case CDB_STR: avp_type |= AVP_VAL_STR; avp_val.s = cdb_reply[i][j].val.s; break; default: LM_WARN("Unknown type %d\n",cdb_reply[i][j].type); goto next_avp; } if (add_avp(avp_type,avp_name.n,avp_val) != 0) { LM_ERR("Unable to add AVP\n"); free_raw_fetch(cdb_reply,val_number,key_number); return -1; } next_avp: if (it) { it = it->next; if (it==NULL); break; } } } free_raw_fetch(cdb_reply,val_number,key_number); } } else ret = cachedb_raw_query( &a->elem[0].u.s, &name_s, NULL,0,NULL); break; case XDBG_T: script_trace("core", "xdbg", msg, a->line) ; if (a->elem[0].type == SCRIPTVAR_ELEM_ST) { if (xdbg(msg, a->elem[0].u.data, val.rs.s) < 0) { LM_ALERT("Cannot print message"); break; } } else { LM_ALERT("BUG in xdbg() type %d\n", a->elem[0].type); ret=E_BUG; } break; case XLOG_T: script_trace("core", "xlog", msg, a->line) ; if (a->elem[1].u.data != NULL) { if (a->elem[1].type != SCRIPTVAR_ELEM_ST) { LM_ALERT("BUG in xlog() type %d\n", a->elem[1].type); ret=E_BUG; break; } if (a->elem[0].type != STR_ST) { LM_ALERT("BUG in xlog() type %d\n", a->elem[0].type); ret=E_BUG; break; } if (xlog_2(msg,a->elem[0].u.data, a->elem[1].u.data) < 0) { LM_ALERT("Cannot print xlog debug message"); break; } } else { if (a->elem[0].type != SCRIPTVAR_ELEM_ST) { LM_ALERT("BUG in xlog() type %d\n", a->elem[0].type); ret=E_BUG; break; } if (xlog_1(msg,a->elem[0].u.data, val.rs.s) < 0) { LM_ALERT("Cannot print xlog debug message"); break; } } break; case RAISE_EVENT_T: script_trace("core", "raise_event", msg, a->line) ; if (a->elem[0].type != NUMBER_ST) { LM_ERR("invalid event id\n"); ret=E_BUG; break; } if (a->elem[2].u.data) { /* three parameters specified */ ret = evi_raise_script_event(msg, (event_id_t)a->elem[0].u.number, a->elem[1].u.data, a->elem[2].u.data); } else { /* two parameters specified */ ret = evi_raise_script_event(msg, (event_id_t)a->elem[0].u.number, NULL, a->elem[1].u.data); } if (ret <= 0) { LM_ERR("cannot raise event\n"); ret=E_UNSPEC; break; } break; case SUBSCRIBE_EVENT_T: script_trace("core", "subscribe_event", msg, a->line) ; if (a->elem[0].type != STR_ST || a->elem[1].type != STR_ST) { LM_ERR("BUG in subscribe arguments\n"); ret=E_BUG; break; } if (a->elem[2].u.data) { if (a->elem[2].type != NUMBER_ST) { LM_ERR("BUG in subscribe expiration time\n"); ret=E_BUG; break; } else { i = a->elem[2].u.number; } } else { i = 0; } name_s.s = a->elem[0].u.data; name_s.len = strlen(name_s.s); /* result should be the socket */ result.s = a->elem[1].u.data; result.len = strlen(result.s); ret = evi_event_subscribe(name_s, result, i, 0); break; case CONSTRUCT_URI_T: script_trace("core", "construct_uri", msg, a->line) ; for (i=0;i<5;i++) { pve = (pv_elem_t *)a->elem[i].u.data; if (pve->spec.getf) { if ( pv_printf_s(msg, pve, &vals[i])!=0 || vals[i].len == 0 || vals[i].s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; return -1; } } else vals[i] = pve->text; } result.s = construct_uri(&vals[0],&vals[1],&vals[2],&vals[3],&vals[4], &result.len); if (result.s) { int_str res; int avp_name; unsigned short avp_type; spec = (pv_spec_t*)a->elem[5].u.data; if (pv_get_avp_name( msg, &(spec->pvp), &avp_name, &avp_type)!=0){ LM_CRIT("BUG in getting AVP name\n"); return -1; } res.s = result; if (add_avp(AVP_VAL_STR|avp_type, avp_name, res)<0){ LM_ERR("cannot add AVP\n"); return -1; } } break; case GET_TIMESTAMP_T: script_trace("core", "get_timestamp", msg, a->line) ; if (get_timestamp(&sec,&usec) == 0) { int avp_name; int_str res; unsigned short avp_type; spec = (pv_spec_t*)a->elem[0].u.data; if (pv_get_avp_name(msg, &(spec->pvp), &avp_name, &avp_type) != 0) { LM_CRIT("BUG in getting AVP name\n"); return -1; } res.n = sec; if (add_avp(avp_type, avp_name, res) < 0) { LM_ERR("cannot add AVP\n"); return -1; } spec = (pv_spec_t*)a->elem[1].u.data; if (pv_get_avp_name(msg, &(spec->pvp), &avp_name, &avp_type) != 0) { LM_CRIT("BUG in getting AVP name\n"); return -1; } res.n = usec; if (add_avp(avp_type, avp_name, res) < 0) { LM_ERR("cannot add AVP\n"); return -1; } } else { LM_ERR("failed to get time\n"); return -1; } break; case SWITCH_T: script_trace("core", "switch", msg, a->line) ; if (a->elem[0].type!=SCRIPTVAR_ST){ LM_ALERT("BUG in switch() type %d\n", a->elem[0].type); ret=E_BUG; break; } spec = (pv_spec_t*)a->elem[0].u.data; if(pv_get_spec_value(msg, spec, &val)!=0) { LM_ALERT("BUG - no value in switch()\n"); ret=E_BUG; break; } /* get the value of pvar */ if(a->elem[1].type!=ACTIONS_ST) { LM_ALERT("BUG in switch() actions\n"); ret=E_BUG; break; } return_code=1; adefault = NULL; aitem = (struct action*)a->elem[1].u.data; cmatch=0; while(aitem) { if((unsigned char)aitem->type==DEFAULT_T) adefault=aitem; if(cmatch==0) { if(aitem->elem[0].type==STR_ST) { if(val.flags&PV_VAL_STR && val.rs.len==aitem->elem[0].u.s.len && strncasecmp(val.rs.s, aitem->elem[0].u.s.s, val.rs.len)==0) cmatch = 1; } else { /* number */ if(val.flags&PV_VAL_INT && val.ri==aitem->elem[0].u.number) cmatch = 1; } } if(cmatch==1) { if(aitem->elem[1].u.data) { return_code=run_action_list( (struct action*)aitem->elem[1].u.data, msg); if ((action_flags&ACT_FL_RETURN) || (action_flags&ACT_FL_EXIT)) break; } if(aitem->elem[2].u.number==1) break; } aitem = aitem->next; } if((cmatch==0) && (adefault!=NULL)) { LM_DBG("switch: running default statement\n"); if(adefault->elem[0].u.data) return_code=run_action_list( (struct action*)adefault->elem[0].u.data, msg); } ret=return_code; break; case MODULE_T: script_trace("module", ((cmd_export_t*)(a->elem[0].u.data))->name, msg, a->line) ; if ( (a->elem[0].type==CMD_ST) && a->elem[0].u.data ) { ret=((cmd_export_t*)(a->elem[0].u.data))->function(msg, (char*)a->elem[1].u.data, (char*)a->elem[2].u.data, (char*)a->elem[3].u.data, (char*)a->elem[4].u.data, (char*)a->elem[5].u.data, (char*)a->elem[6].u.data); }else{ LM_ALERT("BUG in module call\n"); } break; case FORCE_RPORT_T: script_trace("core", "force_rport", msg, a->line) ; msg->msg_flags|=FL_FORCE_RPORT; ret=1; /* continue processing */ break; case FORCE_LOCAL_RPORT_T: script_trace("core", "force_local_rport", msg, a->line) ; msg->msg_flags|=FL_FORCE_LOCAL_RPORT; ret=1; /* continue processing */ break; case SET_ADV_ADDR_T: script_trace("core", "set_adv_addr", msg, a->line) ; if (a->elem[0].type!=STR_ST){ LM_ALERT("BUG in set_advertised_address() " "type %d\n", a->elem[0].type); ret=E_BUG; break; } str adv_addr; pve = (pv_elem_t *)a->elem[0].u.data; if ( pv_printf_s(msg, pve, &adv_addr)!=0 || adv_addr.len == 0 || adv_addr.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; break; } LM_DBG("adv address = [%.*s]\n",adv_addr.len,adv_addr.s); msg->set_global_address=adv_addr; ret=1; /* continue processing */ break; case SET_ADV_PORT_T: script_trace("core", "set_adv_port", msg, a->line) ; if (a->elem[0].type!=STR_ST){ LM_ALERT("BUG in set_advertised_port() " "type %d\n", a->elem[0].type); ret=E_BUG; break; } msg->set_global_port=*((str*)a->elem[0].u.data); ret=1; /* continue processing */ break; #ifdef USE_TCP case FORCE_TCP_ALIAS_T: script_trace("core", "force_tcp_alias", msg, a->line) ; if ( msg->rcv.proto==PROTO_TCP #ifdef USE_TLS || msg->rcv.proto==PROTO_TLS #endif ){ if (a->elem[0].type==NOSUBTYPE) port=msg->via1->port; else if (a->elem[0].type==NUMBER_ST) port=(int)a->elem[0].u.number; else{ LM_ALERT("BUG in force_tcp_alias" " port type %d\n", a->elem[0].type); ret=E_BUG; break; } if (tcpconn_add_alias(msg->rcv.proto_reserved1, port, msg->rcv.proto)!=0){ LM_ERR("tcp alias failed\n"); ret=E_UNSPEC; break; } } #endif ret=1; /* continue processing */ break; case FORCE_SEND_SOCKET_T: script_trace("core", "force_send_socket", msg, a->line) ; if (a->elem[0].type!=SOCKETINFO_ST){ LM_ALERT("BUG in force_send_socket argument" " type: %d\n", a->elem[0].type); ret=E_BUG; break; } msg->force_send_socket=(struct socket_info*)a->elem[0].u.data; ret=1; /* continue processing */ break; case SERIALIZE_BRANCHES_T: script_trace("core", "serialize_branches", msg, a->line) ; if (a->elem[0].type!=NUMBER_ST){ LM_ALERT("BUG in serialize_branches argument" " type: %d\n", a->elem[0].type); ret=E_BUG; break; } if (serialize_branches(msg,(int)a->elem[0].u.number)!=0) { LM_ERR("serialize_branches failed\n"); ret=E_UNSPEC; break; } ret=1; /* continue processing */ break; case NEXT_BRANCHES_T: script_trace("core", "next_branches", msg, a->line) ; if ((ret=next_branches(msg))<0) { LM_ERR("next_branches failed\n"); ret=E_UNSPEC; break; } /* continue processing */ break; case EQ_T: case COLONEQ_T: case PLUSEQ_T: case MINUSEQ_T: case DIVEQ_T: case MULTEQ_T: case MODULOEQ_T: case BANDEQ_T: case BOREQ_T: case BXOREQ_T: ret = do_assign(msg, a); break; case USE_BLACKLIST_T: script_trace("core", "use_blacklist", msg, a->line) ; mark_for_search((struct bl_head*)a->elem[0].u.data, 1); break; case UNUSE_BLACKLIST_T: script_trace("core", "unuse_blacklist", msg, a->line); mark_for_search((struct bl_head*)a->elem[0].u.data, 0); break; case PV_PRINTF_T: script_trace("core", "pv_printf", msg, a->line); ret = -1; spec = (pv_spec_p)a->elem[0].u.data; if(!pv_is_w(spec)) { LM_ERR("read only PV in first parameter of pv_printf\n"); goto error; } model = (pv_elem_p)a->elem[1].u.data; memset(&val, 0, sizeof(pv_value_t)); if(pv_printf_s(msg, model, &val.rs)!=0) { LM_ERR("cannot eval second parameter\n"); goto error; } val.flags = PV_VAL_STR; if(pv_set_value(msg, spec, EQ_T, &val)<0) { LM_ERR("setting PV failed\n"); goto error; } ret = 1; break; case SCRIPT_TRACE_T: script_trace("core", "script_trace", msg, a->line); if (a->elem[0].type==NOSUBTYPE) { use_script_trace = 0; } else { use_script_trace = 1; if (a->elem[0].type != NUMBER_ST || a->elem[1].type != SCRIPTVAR_ELEM_ST) { LM_ERR("BUG in use_script_trace() arguments\n"); ret=E_BUG; break; } if (a->elem[2].type!=NOSUBTYPE) { script_trace_info = (char *)a->elem[2].u.data; } else { script_trace_info = NULL; } script_trace_log_level = (int)a->elem[0].u.number; script_trace_elem = *(pv_elem_p)a->elem[1].u.data; } break; default: LM_ALERT("BUG - unknown type %d\n", a->type); goto error; } if((unsigned char)a->type!=IF_T && (unsigned char)a->type!=ROUTE_T) return_code = ret; /*skip:*/ update_longest_action(); return ret; error: LM_ERR("error at line: %d\n", a->line); update_longest_action(); return ret; error_uri: LM_ERR("set*: uri too long\n"); if (new_uri) pkg_free(new_uri); update_longest_action(); return E_UNSPEC; error_fwd_uri: update_longest_action(); return ret; }
/* Handle the HTTP Connection */ void handle_request( int connfd ) { struct http_request r_data; struct timeval starttime, endtime; struct valid_flags r_flags; char request_buffer[10001], response_buffer[10001]; char *new_request; char reply_date_string[128]; int n; gettimeofday(&starttime, NULL); r_flags.disallowed_method = 0; r_flags.malformed_request = 0; r_flags.contains_valid_host = 0; r_flags.contains_valid_method = 0; // Read the request into buffer while( (n = read(connfd, request_buffer, 4096)) > 0 ) { if( n < 0 ) { #ifdef DEBUG fprintf(stderr, "ERROR\tRead error.\n"); #endif } request_buffer[n] = 0; if( request_buffer[n-1] == '\n' ) { break; } } new_request = format_request( request_buffer, &r_data, &r_flags, n ); // Well, every request has a date/time, so lets get to it... time_t t = time(NULL); r_data.t_data = localtime(&t); r_data.port = 80; r_data.close = 0; strftime( reply_date_string, 128, "%a, %d %b %Y %H:%M:%S", r_data.t_data); #ifdef DEBUG fprintf(stderr, "method: %s\n", r_data.method); fprintf(stderr, "url: %s\n", r_data.url); fprintf(stderr, "host: %s\n", r_data.host); fprintf(stderr, "date: %s\n", reply_date_string); fprintf(stderr, "contains_valid_host: %d\ncontains_valid_method: %d\ndisallowed_method: %d\nmalformed_request: %d\n", r_flags.contains_valid_host, r_flags.contains_valid_method, r_flags.disallowed_method, r_flags.malformed_request); #endif //bzero(buffer, sizeof(buffer)); if ( r_flags.contains_valid_method && r_flags.contains_valid_host && !r_flags.disallowed_method && !r_flags.malformed_request ) { r_data.response = 200; // Method is GET or HEAD, well formed (presumably) forward_request( connfd, &r_data, new_request ); } else if ( r_flags.contains_valid_method && r_flags.contains_valid_host && r_flags.disallowed_method && !r_flags.malformed_request ) { r_data.response = 405; // Method VALID but not GET or HEAD -- Send 405 response snprintf(response_buffer, sizeof(response_buffer), invalid_method_response, reply_date_string, r_data.method); write( connfd, response_buffer, strlen(response_buffer) ); } else { // Response is MALFORMEd -- does not contain host, or is otherwise BAD r_data.response = 400; snprintf(response_buffer, sizeof(response_buffer), malformed_response, reply_date_string); write( connfd, response_buffer, strlen(response_buffer) ); } // Close connection if ((n = close( connfd )) < 0 ) { #ifdef DEBUG fprintf(stderr, "ERROR\tClient Socket Close error.\n"); #endif } gettimeofday(&endtime, NULL); r_data.time_spent = (int)(((double)(endtime.tv_usec - starttime.tv_usec) / 1000000 + (double)(endtime.tv_sec - starttime.tv_sec))*100); // Log request data to stdout output_request( r_data ); }
bool hostupdate_h(connection_t *c) { /* FIXME: Whoah! Even more!! */ char rawfile[MAX_STRING_SIZE]; char rawhost[MAX_STRING_SIZE], b64host[MAX_STRING_SIZE]; char rawdgst[MAX_STRING_SIZE], b64dgst[MAX_STRING_SIZE]; char updname[MAX_STRING_SIZE], hosttoupd[MAX_STRING_SIZE]; char *fname; FILE *fp; size_t slen, dlen, rlen; RSA *updkey; /* We ignore host files updates, maybe for reason */ if (ignorenetupdates() || ignorehostsupdates()) return true; /* handle received host data, check sign, (over)write on disk */ if (sscanf(c->buffer, "%*d " MAX_STRING " " MAX_STRING " " MAX_STRING " %zd %zd " MAX_STRING, updname, hosttoupd, b64host, &slen, &dlen, b64dgst) != 6) { logger(LOG_ERR, "Got bad %s from %s (%s)", "HOSTUPDATE", c->name, c->hostname); return false; } /* verify the originating node is permitted to send updates */ if (dontverifyupdatepermission()) goto _next; if(!getconf_bool_node_offline(updname, "HostsFilesMaster")) { ifdebug(PROTOCOL) logger(LOG_WARNING, "Ignoring hosts update request originating from %s [which came from %s (%s)]", updname, c->name, c->hostname); return true; } /* some other sanity checks */ _next: if (!isvalidfname(updname)) { logger(LOG_ERR, "Got bogus updater name \"%s\" from %s (%s) (from: %s)", updname, c->name, c->hostname, updname); return false; } if (!isvalidfname(hosttoupd)) { logger(LOG_ERR, "Got bogus update name \"%s\" from %s (%s) (from: %s)", hosttoupd, c->name, c->hostname, updname); return false; } if (slen >= MAX_STRING_SIZE || dlen >= MAX_STRING_SIZE) { logger(LOG_ERR, "HOSTUPDATE string sizes for %s are bigger than buffer can fit (%zd, %zd)", hosttoupd, slen, dlen); return false; } /* verify it */ if (dontverifyupdatesignature()) goto _out; if (!read_rsa_public_key_offline(updname, &updkey)) { logger(LOG_ERR, "Could not find public key for %s", updname); return true; } base64_decode(b64dgst, rawdgst, sizeof(rawdgst)-1); snprintf(rawhost, sizeof(rawhost), "%s %s %s %zd %zd", updname, hosttoupd, b64host, slen, dlen); rlen = strlen(rawhost); if (!EVP_verify(updkey, rawdgst, dlen, rawhost, rlen)) { logger(LOG_WARNING, "Ignoring hosts update request with bad signature from %s for %s" " [which came from %s (%s)]", updname, hosttoupd, c->name, c->hostname); RSA_free(updkey); return true; } RSA_free(updkey); /* neighbours return us our own packets */ _out: if (!strcmp(updname, myself->name)) return true; /* All right, let's start updating */ xasprintf(&fname, "%s/hosts/%s", confbase, hosttoupd); /* Tell others if needed */ if (!dontforwardhostsupdates()) { exceptmasters = true; forward_request(c); } /* Check if it's a START marker */ if (!strcmp(updname, hosttoupd) && !strcmp(b64host, "START")) { /* Run pre-update script (embedded devices do remount,rw fs for example) We really need to run this once, so that's why there are START and END markers */ run_script("hostsupdate-before"); /* That's it folks! Waiting for files to arrive */ free(fname); return true; } /* Check if it's a END marker */ else if (!strcmp(updname, hosttoupd) && !strcmp(b64host, "END")) { /* Run post-update script (embedded devices do remount,ro fs for example) */ run_script("hostsupdate-after"); /* Schedule config/host reload */ schedulereload(); /* That's it folks! */ free(fname); return true; } /* Remove unneeded hosts */ else if (!strcmp(b64host, "DEAD")) { unlink(fname); /* That's it, waiting for other next request */ free(fname); return true; } /* We need this early for next test */ base64_decode(b64host, rawhost, sizeof(rawhost)-1); /* * Via broadcasting host files one hosts file master can become config file master. * Reject such a claims even if they're authentic. */ if (dontverifyupdatepermission()) goto _write; if(!getconf_bool_node_offline(updname, "ConfFileMaster") && strcasestr_local(rawhost, "ConfFileMaster")) { logger(LOG_WARNING, "Ignoring %s which tried to raise privileges for %s to ConfFileMaster!", updname, hosttoupd); goto _end; } /* Finally write it to disk */ _write: fp = fopen(fname, "w"); if (!fp) { logger(LOG_ERR, "Unable to write new host file: %s (%s)", fname, strerror(errno)); free(fname); return true; } #ifdef HAVE_FCHMOD fchmod(fileno(fp), 0640); #endif fwrite(rawhost, slen, 1, fp); fclose(fp); _end: free(fname); return true; }
void cib_process_request(xmlNode * request, gboolean force_synchronous, gboolean privileged, gboolean unused, crm_client_t * cib_client) { int call_type = 0; int call_options = 0; gboolean process = TRUE; gboolean is_update = TRUE; gboolean from_peer = TRUE; gboolean needs_reply = TRUE; gboolean local_notify = FALSE; gboolean needs_forward = FALSE; gboolean global_update = crm_is_true(crm_element_value(request, F_CIB_GLOBAL_UPDATE)); xmlNode *op_reply = NULL; xmlNode *result_diff = NULL; int rc = pcmk_ok; const char *op = crm_element_value(request, F_CIB_OPERATION); const char *originator = crm_element_value(request, F_ORIG); const char *host = crm_element_value(request, F_CIB_HOST); const char *target = NULL; const char *call_id = crm_element_value(request, F_CIB_CALLID); const char *client_id = crm_element_value(request, F_CIB_CLIENTID); const char *client_name = crm_element_value(request, F_CIB_CLIENTNAME); const char *reply_to = crm_element_value(request, F_CIB_ISREPLY); if (cib_client) { from_peer = FALSE; } cib_num_ops++; if (cib_num_ops == 0) { cib_num_fail = 0; cib_num_local = 0; cib_num_updates = 0; crm_info("Stats wrapped around"); } crm_element_value_int(request, F_CIB_CALLOPTS, &call_options); if (force_synchronous) { call_options |= cib_sync_call; } if (host != NULL && strlen(host) == 0) { host = NULL; } if (host) { target = host; } else if (call_options & cib_scope_local) { target = "local host"; } else { target = "master"; } if (from_peer) { crm_trace("Processing peer %s operation from %s/%s on %s intended for %s (reply=%s)", op, client_name, call_id, originator, target, reply_to); } else { crm_xml_add(request, F_ORIG, cib_our_uname); crm_trace("Processing local %s operation from %s/%s intended for %s", op, client_name, call_id, target); } rc = cib_get_operation_id(op, &call_type); if (rc != pcmk_ok) { /* TODO: construct error reply? */ crm_err("Pre-processing of command failed: %s", pcmk_strerror(rc)); return; } if (from_peer == FALSE) { parse_local_options(cib_client, call_type, call_options, host, op, &local_notify, &needs_reply, &process, &needs_forward); } else if (parse_peer_options(call_type, request, &local_notify, &needs_reply, &process, &needs_forward) == FALSE) { return; } is_update = cib_op_modifies(call_type); if (is_update) { cib_num_updates++; } if (call_options & cib_discard_reply) { needs_reply = is_update; local_notify = FALSE; } if (needs_forward) { const char *host = crm_element_value(request, F_CIB_HOST); const char *section = crm_element_value(request, F_CIB_SECTION); crm_info("Forwarding %s operation for section %s to %s (origin=%s/%s/%s)", op, section ? section : "'all'", host ? host : "master", originator ? originator : "local", client_name, call_id); forward_request(request, cib_client, call_options); return; } if (cib_status != pcmk_ok) { const char *call = crm_element_value(request, F_CIB_CALLID); rc = cib_status; crm_err("Operation ignored, cluster configuration is invalid." " Please repair and restart: %s", pcmk_strerror(cib_status)); op_reply = create_xml_node(NULL, "cib-reply"); crm_xml_add(op_reply, F_TYPE, T_CIB); crm_xml_add(op_reply, F_CIB_OPERATION, op); crm_xml_add(op_reply, F_CIB_CALLID, call); crm_xml_add(op_reply, F_CIB_CLIENTID, client_id); crm_xml_add_int(op_reply, F_CIB_CALLOPTS, call_options); crm_xml_add_int(op_reply, F_CIB_RC, rc); crm_trace("Attaching reply output"); add_message_xml(op_reply, F_CIB_CALLDATA, the_cib); crm_log_xml_explicit(op_reply, "cib:reply"); } else if (process) { time_t finished = 0; int now = time(NULL); int level = LOG_INFO; const char *section = crm_element_value(request, F_CIB_SECTION); cib_num_local++; rc = cib_process_command(request, &op_reply, &result_diff, privileged); if (is_update == FALSE) { level = LOG_TRACE; } else if (global_update) { switch (rc) { case pcmk_ok: level = LOG_INFO; break; case -pcmk_err_old_data: case -pcmk_err_diff_resync: case -pcmk_err_diff_failed: level = LOG_TRACE; break; default: level = LOG_ERR; } } else if (rc != pcmk_ok && is_update) { cib_num_fail++; level = LOG_WARNING; } do_crm_log(level, "Completed %s operation for section %s: %s (rc=%d, origin=%s/%s/%s, version=%s.%s.%s)", op, section ? section : "'all'", pcmk_strerror(rc), rc, originator ? originator : "local", client_name, call_id, the_cib ? crm_element_value(the_cib, XML_ATTR_GENERATION_ADMIN) : "0", the_cib ? crm_element_value(the_cib, XML_ATTR_GENERATION) : "0", the_cib ? crm_element_value(the_cib, XML_ATTR_NUMUPDATES) : "0"); finished = time(NULL); if (finished - now > 3) { crm_trace("%s operation took %ds to complete", op, finished - now); crm_write_blackbox(0, NULL); } if (op_reply == NULL && (needs_reply || local_notify)) { crm_err("Unexpected NULL reply to message"); crm_log_xml_err(request, "null reply"); needs_reply = FALSE; local_notify = FALSE; } } /* from now on we are the server */ if(is_update && cib_legacy_mode() == FALSE) { crm_trace("Completed pre-sync update from %s/%s/%s%s", originator ? originator : "local", client_name, call_id, local_notify?" with local notification":""); } else if (needs_reply == FALSE || stand_alone) { /* nothing more to do... * this was a non-originating slave update */ crm_trace("Completed slave update"); } else if (call_options & cib_discard_reply) { crm_trace("Caller isn't interested in reply"); } else if (from_peer) { if (is_update == FALSE || result_diff == NULL) { crm_trace("Request not broadcast: R/O call"); } else if (call_options & cib_inhibit_bcast) { crm_trace("Request not broadcast: inhibited"); } else if (rc != pcmk_ok) { crm_trace("Request not broadcast: call failed: %s", pcmk_strerror(rc)); } else { crm_trace("Directing reply to %s", originator); } send_peer_reply(op_reply, result_diff, originator, FALSE); } if (local_notify && client_id) { crm_trace("Performing local %ssync notification for %s", (call_options & cib_sync_call) ? "" : "a-", client_id); if (process == FALSE) { do_local_notify(request, client_id, call_options & cib_sync_call, from_peer); } else { do_local_notify(op_reply, client_id, call_options & cib_sync_call, from_peer); } } free_xml(op_reply); free_xml(result_diff); return; }
bool confupdate_h(connection_t *c) { char updname[MAX_STRING_SIZE]; char rawconf[MAX_STRING_SIZE], b64conf[MAX_STRING_SIZE]; char rawdgst[MAX_STRING_SIZE], b64dgst[MAX_STRING_SIZE]; node_t *n; char *fname, *tname; FILE *fp; int x; size_t slen, dlen, rlen; RSA *updkey; /* Guard ourselves against updates */ if (ignorenetupdates() || ignoreconfupdates()) return true; if (sscanf(c->buffer, "%*d " MAX_STRING " " MAX_STRING " %zd %zd " MAX_STRING, updname, b64conf, &slen, &dlen, b64dgst) != 5) { logger(LOG_ERR, "Got bad %s from %s (%s)", "CONFUPDATE", c->name, c->hostname); return false; } if (dontverifyupdatepermission()) goto _next; if(!getconf_bool_node_offline(updname, "ConfFileMaster")) { ifdebug(PROTOCOL) logger(LOG_WARNING, "Ignoring config update request originating from %s [which came from %s (%s)]", updname, c->name, c->hostname); return true; } _next: if (!isvalidfname(updname)) { logger(LOG_ERR, "Got bogus updater name \"%s\" from %s (%s) (from: %s)", updname, c->name, c->hostname, updname); return false; } if (slen >= MAX_STRING_SIZE || dlen >= MAX_STRING_SIZE) { logger(LOG_ERR, "CONFUPDATE string sizes are bigger than buffer can fit (%zd, %zd)", slen, dlen); return false; } if (dontverifyupdatesignature()) goto _out; if (!read_rsa_public_key_offline(updname, &updkey)) { logger(LOG_ERR, "Could not find public key for %s", updname); return true; } base64_decode(b64dgst, rawdgst, sizeof(rawdgst)-1); snprintf(rawconf, sizeof(rawconf), "%s %s %zd %zd", updname, b64conf, slen, dlen); rlen = strlen(rawconf); if (!EVP_verify(updkey, rawdgst, dlen, rawconf, rlen)) { logger(LOG_WARNING, "Ignoring config update request with bad signature" " from %s [which came from %s (%s)]", updname, c->name, c->hostname); RSA_free(updkey); return true; } RSA_free(updkey); _out: if (!strcmp(updname, myself->name)) return true; if (!dontforwardconfupdates()) { exceptmasters = true; forward_request(c); } if (!strcmp(b64conf, "START")) { run_script("confupdate-before"); return true; } else if (!strcmp(b64conf, "END")) { run_script("confupdate-after"); schedulereload(); return true; } xasprintf(&fname, "%s/tinc.conf", confbase); fp = fopen(fname, "w"); if (!fp) { logger(LOG_ERR, "Could not update %s: %s", fname, strerror(errno)); free(fname); return true; } /* Save variables which are sensitive */ for (x = 0; confvarstopreserve[x]; x++) { if(get_config_string(lookup_config(config_tree, confvarstopreserve[x]), &tname)) { fprintf(fp, "%s = %s\n", confvarstopreserve[x], tname); free(tname); } } /* Decode and append our template */ base64_decode(b64conf, rawconf, sizeof(rawconf)-1); fwrite(rawconf, slen, 1, fp); fclose(fp); free(fname); return true; }
bool del_edge_h(connection_t *c) { edge_t *e; char from_name[MAX_STRING_SIZE]; char to_name[MAX_STRING_SIZE]; node_t *from, *to; if(sscanf(c->buffer, "%*d %*x "MAX_STRING" "MAX_STRING, from_name, to_name) != 2) { logger(LOG_ERR, "Got bad %s from %s (%s)", "DEL_EDGE", c->name, c->hostname); return false; } /* Check if names are valid */ if(!check_id(from_name) || !check_id(to_name)) { logger(LOG_ERR, "Got bad %s from %s (%s): %s", "DEL_EDGE", c->name, c->hostname, "invalid name"); return false; } if(seen_request(c->buffer)) return true; /* Lookup nodes */ from = lookup_node(from_name); to = lookup_node(to_name); if(tunnelserver && from != myself && from != c->node && to != myself && to != c->node) { /* ignore indirect edge registrations for tunnelserver */ ifdebug(PROTOCOL) logger(LOG_WARNING, "Ignoring indirect %s from %s (%s)", "DEL_EDGE", c->name, c->hostname); return true; } if(!from) { ifdebug(PROTOCOL) logger(LOG_ERR, "Got %s from %s (%s) which does not appear in the edge tree", "DEL_EDGE", c->name, c->hostname); return true; } if(!to) { ifdebug(PROTOCOL) logger(LOG_ERR, "Got %s from %s (%s) which does not appear in the edge tree", "DEL_EDGE", c->name, c->hostname); return true; } /* Check if edge exists */ e = lookup_edge(from, to); if(!e) { ifdebug(PROTOCOL) logger(LOG_WARNING, "Got %s from %s (%s) which does not appear in the edge tree", "DEL_EDGE", c->name, c->hostname); return true; } if(e->from == myself) { ifdebug(PROTOCOL) logger(LOG_WARNING, "Got %s from %s (%s) for ourself", "DEL_EDGE", c->name, c->hostname); contradicting_del_edge++; send_add_edge(c, e); /* Send back a correction */ return true; } /* Tell the rest about the deleted edge */ if(!tunnelserver) forward_request(c); /* Delete the edge */ edge_del(e); /* Run MST before or after we tell the rest? */ graph(); /* If the node is not reachable anymore but we remember it had an edge to us, clean it up */ if(!to->status.reachable) { e = lookup_edge(to, myself); if(e) { if(!tunnelserver) send_del_edge(broadcast, e); edge_del(e); } } return true; }
int t_relay_to( struct sip_msg *p_msg , struct proxy_l *proxy, int proto, int replicate) { int ret; int new_tran; str *uri; int reply_ret; /* struct hdr_field *hdr; */ struct cell *t; ret=0; new_tran = t_newtran( p_msg ); /* parsing error, memory alloc, whatever ... if via is bad and we are forced to reply there, return with 0 (->break), pass error status otherwise */ if (new_tran<0) { ret = (ser_error==E_BAD_VIA && reply_to_via) ? 0 : new_tran; goto done; } /* if that was a retransmission, return we are happily done */ if (new_tran==0) { ret = 1; goto done; } /* new transaction */ /* ACKs do not establish a transaction and are fwd-ed statelessly */ if ( p_msg->REQ_METHOD==METHOD_ACK) { DBG("DEBUG:tm:t_relay: forwarding ACK statelessly \n"); if (proxy==0) { uri = GET_RURI(p_msg); proxy=uri2proxy(GET_NEXT_HOP(p_msg), proto); if (proxy==0) { ret=E_BAD_ADDRESS; goto done; } proto=proxy->proto; /* uri2proxy set it correctly */ ret=forward_request( p_msg , proxy, proto) ; free_proxy( proxy ); pkg_free( proxy ); } else { proto=get_proto(proto, proxy->proto); ret=forward_request( p_msg , proxy, proto ) ; } goto done; } /* if replication flag is set, mark the transaction as local so that replies will not be relaied */ t=get_t(); if (replicate) t->flags|=T_IS_LOCAL_FLAG; /* INVITE processing might take long, particularly because of DNS look-ups -- let upstream know we're working on it */ if (p_msg->REQ_METHOD==METHOD_INVITE ) { DBG("DEBUG:tm:t_relay: new INVITE\n"); if (!t_reply( t, p_msg , 100 , "trying -- your call is important to us")) DBG("SER: ERROR: t_reply (100)\n"); } /* now go ahead and forward ... */ ret=t_forward_nonack(t, p_msg, proxy, proto); if (ret<=0) { DBG( "ERROR:tm:t_relay_to: t_forward_nonack returned error \n"); /* we don't want to pass upstream any reply regarding replicating * a request; replicated branch must stop at us*/ if (!replicate) { reply_ret=kill_transaction( t ); if (reply_ret>0) { /* we have taken care of all -- do nothing in script */ DBG("ERROR: generation of a stateful reply " "on error succeeded\n"); ret=0; } else { DBG("ERROR: generation of a stateful reply " "on error failed\n"); } } } else { DBG( "SER: new transaction fwd'ed\n"); } done: return ret; }
int t_relay_to( struct sip_msg *p_msg , struct proxy_l *proxy, int flags) { int ret; int new_tran; int reply_ret; struct cell *t; ret=0; new_tran = t_newtran( p_msg, 1/*full UAS cloning*/ ); /* parsing error, memory alloc, whatever ... */ if (new_tran<0) { ret = new_tran; goto done; } /* if that was a retransmission, break from script */ if (new_tran==0) { goto done; } /* new transaction */ /* ACKs do not establish a transaction and are fwd-ed statelessly */ if ( p_msg->REQ_METHOD==METHOD_ACK) { LM_DBG("forwarding ACK\n"); /* send it out */ if (proxy==0) { proxy=uri2proxy(GET_NEXT_HOP(p_msg), p_msg->force_send_socket ? p_msg->force_send_socket->proto : PROTO_NONE ); if (proxy==0) { ret=E_BAD_ADDRESS; goto done; } ret=forward_request( p_msg , proxy); if (ret>=0) ret=1; free_proxy( proxy ); pkg_free( proxy ); } else { ret=forward_request( p_msg , proxy); if (ret>=0) ret=1; } goto done; } /* if replication flag is set, mark the transaction as local so that replies will not be relaied */ t=get_t(); if (flags&TM_T_RELAY_repl_FLAG) t->flags|=T_IS_LOCAL_FLAG; if (flags&TM_T_RELAY_nodnsfo_FLAG) t->flags|=T_NO_DNS_FAILOVER_FLAG; if (flags&TM_T_RELAY_reason_FLAG) t->flags|=T_CANCEL_REASON_FLAG; if ((flags&TM_T_RELAY_do_cancel_dis_FLAG) && tm_has_request_disponsition_no_cancel(p_msg)==0 ) t->flags|=T_MULTI_200OK_FLAG; /* now go ahead and forward ... */ ret=t_forward_nonack( t, p_msg, proxy, 0/*no reset*/, 0/*unlocked*/); if (ret<=0) { LM_DBG("t_forward_nonack returned error \n"); /* we don't want to pass upstream any reply regarding replicating * a request; replicated branch must stop at us*/ if (!(flags&(TM_T_RELAY_repl_FLAG|TM_T_RELAY_noerr_FLAG))) { reply_ret = kill_transaction( t ); if (reply_ret>0) { /* we have taken care of all -- do nothing in script */ LM_DBG("generation of a stateful reply on error succeeded\n"); ret=0; } else { LM_DBG("generation of a stateful reply on error failed\n"); } } } else { LM_DBG("new transaction fwd'ed\n"); } done: return ret; }
bool del_edge_h(meshlink_handle_t *mesh, connection_t *c, const char *request) { edge_t *e; char from_name[MAX_STRING_SIZE]; char to_name[MAX_STRING_SIZE]; node_t *from, *to; if(sscanf(request, "%*d %*x "MAX_STRING" "MAX_STRING, from_name, to_name) != 2) { logger(mesh, MESHLINK_ERROR, "Got bad %s from %s (%s)", "DEL_EDGE", c->name, c->hostname); return false; } /* Check if names are valid */ if(!check_id(from_name) || !check_id(to_name)) { logger(mesh, MESHLINK_ERROR, "Got bad %s from %s (%s): %s", "DEL_EDGE", c->name, c->hostname, "invalid name"); return false; } if(seen_request(mesh, request)) return true; /* Lookup nodes */ from = lookup_node(mesh, from_name); to = lookup_node(mesh, to_name); if(!from) { logger(mesh, MESHLINK_ERROR, "Got %s from %s (%s) which does not appear in the edge tree", "DEL_EDGE", c->name, c->hostname); return true; } if(!to) { logger(mesh, MESHLINK_ERROR, "Got %s from %s (%s) which does not appear in the edge tree", "DEL_EDGE", c->name, c->hostname); return true; } /* Check if edge exists */ e = lookup_edge(from, to); if(!e) { logger(mesh, MESHLINK_WARNING, "Got %s from %s (%s) which does not appear in the edge tree", "DEL_EDGE", c->name, c->hostname); return true; } if(e->from == mesh->self) { logger(mesh, MESHLINK_WARNING, "Got %s from %s (%s) for ourself", "DEL_EDGE", c->name, c->hostname); mesh->contradicting_del_edge++; send_add_edge(mesh, c, e); /* Send back a correction */ return true; } /* Tell the rest about the deleted edge */ forward_request(mesh, c, request); /* Delete the edge */ edge_del(mesh, e); /* Run MST before or after we tell the rest? */ graph(mesh); /* If the node is not reachable anymore but we remember it had an edge to us, clean it up */ if(!to->status.reachable) { e = lookup_edge(to, mesh->self); if(e) { send_del_edge(mesh, mesh->everyone, e); edge_del(mesh, e); } } return true; }