static int stateless_connect(const char *service_name) { struct discovery *discover; struct proxy_state p; /* * Run the info/refs request and see if the server supports protocol * v2. If and only if the server supports v2 can we successfully * establish a stateless connection, otherwise we need to tell the * client to fallback to using other transport helper functions to * complete their request. */ discover = discover_refs(service_name, 0); if (discover->version != protocol_v2) { printf("fallback\n"); fflush(stdout); return -1; } else { /* Stateless Connection established */ printf("\n"); fflush(stdout); } proxy_state_init(&p, service_name, discover->version); /* * Dump the capability listing that we got from the server earlier * during the info/refs request. */ write_or_die(p.out, discover->buf, discover->len); /* Peek the next packet line. Until we see EOF keep sending POSTs */ while (packet_reader_peek(&p.reader) != PACKET_READ_EOF) { if (proxy_request(&p)) { /* We would have an err here */ break; } } proxy_state_clear(&p); return 0; }
/* Serve the client that connected to the webserver */ static int serve_client(t_session *session) { int result, length, auth_result; char *qmark, chr, *header; t_host *host_record; t_access access; t_deny_body *deny_body; t_req_method request_method; t_ip_addr ip_addr; #ifdef ENABLE_XSLT char *xslt_file; #endif #ifdef ENABLE_TOOLKIT int i; t_toolkit_options toolkit_options; #endif #ifdef ENABLE_RPROXY t_rproxy *rproxy; #endif #ifdef ENABLE_DEBUG session->current_task = "fetch & parse request"; #endif if ((result = fetch_request(session)) != 200) { session->request_method = GET; return result; } else if ((result = parse_request(session, session->header_length + session->content_length)) != 200) { session->request_method = GET; return result; } #ifdef ENABLE_DEBUG session->current_task = "serve client"; #endif session->time = time(NULL); /* Hide reverse proxies */ if (in_iplist(session->config->hide_proxy, &(session->ip_address))) { if (last_forwarded_ip(session->http_headers, &ip_addr) == 0) { if (reposition_client(session, &ip_addr) != -1) { copy_ip(&(session->ip_address), &ip_addr); } } } /* SSH tunneling */ #ifdef ENABLE_RPROXY if (session->request_method == CONNECT) { if (in_iplist(session->config->tunnel_ssh, &(session->ip_address)) == false) { return 405; } #ifdef ENABLE_SSL if (session->binding->use_ssl) { return 405; } #endif if (strcmp(session->request_uri, "localhost:22") != 0) { if (strcmp(session->request_uri, "127.0.0.1:22") != 0) { if (strcmp(session->request_uri, "::1.22") != 0) { return 403; } } } log_system(session, "SSH tunnel requested"); if (tunnel_ssh_connection(session->client_socket) != 0) { log_system(session, "SSH tunnel failed"); } else { log_system(session, "SSH tunnel terminated"); } session->keep_alive = false; return 200; } #endif /* Find host record */ if (session->hostname != NULL) { if (remove_port_from_hostname(session) == -1) { log_error(session, "error removing port from hostname"); return 500; } if ((host_record = get_hostrecord(session->config->first_host, session->hostname, session->binding)) != NULL) { session->host = host_record; #ifdef ENABLE_TOMAHAWK session->last_host = host_record; #endif } } session->host->access_time = session->time; #ifdef ENABLE_SSL /* SSL client authentication */ if (session->binding->use_ssl) { if ((session->host->ca_certificate != NULL) && (ssl_has_peer_cert(&(session->ssl_context)) == false)) { log_error(session, "Missing client SSL certificate"); return 440; } } #endif /* Enforce usage of first hostname */ if (session->host->enforce_first_hostname && (session->hostname != NULL)) { if (**(session->host->hostname.item) != '*') { if (strcmp(session->hostname, *(session->host->hostname.item)) != 0) { session->cause_of_301 = enforce_first_hostname; return 301; } } } /* Enforce usage of SSL */ #ifdef ENABLE_SSL if (session->host->require_ssl && (session->binding->use_ssl == false)) { if ((qmark = strchr(session->uri, '?')) != NULL) { *qmark = '\0'; session->vars = qmark + 1; session->uri_len = strlen(session->uri); } session->cause_of_301 = require_ssl; return 301; } #endif /* Deny matching bodies */ if (session->body != NULL) { chr = *(session->body + session->content_length); *(session->body + session->content_length) = '\0'; deny_body = session->host->deny_body; while (deny_body != NULL) { if (strpcmp(session->body, &(deny_body->pattern)) == 0) { if ((session->config->ban_on_denied_body > 0) && (ip_allowed(&(session->ip_address), session->config->banlist_mask) != deny)) { ban_ip(&(session->ip_address), session->config->ban_on_denied_body, session->config->kick_on_ban); log_system(session, "Client banned because of denied body"); #ifdef ENABLE_MONITOR if (session->config->monitor_enabled) { monitor_count_ban(session); } #endif } log_exploit_attempt(session, "denied body", session->body); #ifdef ENABLE_TOMAHAWK increment_counter(COUNTER_EXPLOIT); #endif #ifdef ENABLE_MONITOR if (session->config->monitor_enabled) { monitor_count_exploit(session); monitor_event("Request body denied for %s", session->host->hostname.item[0]); } #endif *(session->body + session->content_length) = chr; return 403; } deny_body = deny_body->next; } *(session->body + session->content_length) = chr; } /* Websocket */ if (session->request_method == GET) { if ((header = get_http_header("Connection:", session->http_headers)) != NULL) { if (strcasestr(header, "upgrade") != NULL) { if ((header = get_http_header("Upgrade:", session->http_headers)) != NULL) { if (strcasecmp(header, "websocket") == 0) { switch (access = allow_client(session)) { case deny: log_error(session, fb_accesslist); return 403; case allow: break; case pwd: case unspecified: if ((auth_result = http_authentication_result(session, access == unspecified)) != 200) { return auth_result; } } session->keep_alive = false; if (forward_to_websocket(session) == -1) { return 500; } return 200; } } } } } #ifdef ENABLE_RPROXY /* Reverse proxy */ rproxy = session->host->rproxy; while (rproxy != NULL) { if (rproxy_match(rproxy, session->request_uri)) { if (rproxy_loop_detected(session->http_headers)) { return 508; } if ((qmark = strchr(session->uri, '?')) != NULL) { *qmark = '\0'; session->vars = qmark + 1; } if (validate_url(session) == false) { return -1; } if ((session->vars != NULL) && (session->host->secure_url)) { if (forbidden_chars_present(session->vars)) { log_error(session, "URL contains forbidden characters"); return 403; } } if (duplicate_host(session) == false) { log_error(session, "duplicate_host() error"); return 500; } if ((result = uri_to_path(session)) != 200) { return result; } if (session->host->ignore_dot_hiawatha == false) { if (load_user_config(session) == -1) { return 500; } } if ((result = copy_directory_settings(session)) != 200) { return result; } switch (access = allow_client(session)) { case deny: log_error(session, fb_accesslist); return 403; case allow: break; case pwd: case unspecified: if ((auth_result = http_authentication_result(session, access == unspecified)) != 200) { return auth_result; } } /* Prevent SQL injection */ if (session->host->prevent_sqli) { result = prevent_sqli(session); if (result == 1) { session->error_cause = ec_SQL_INJECTION; } if (result != 0) { return -1; } } /* Prevent Cross-site Scripting */ if (session->host->prevent_xss != p_no) { if (prevent_xss(session) > 0) { if (session->host->prevent_xss == p_block) { session->error_cause = ec_XSS; return -1; } } } /* Prevent Cross-site Request Forgery */ if (session->host->prevent_csrf != p_no) { if (prevent_csrf(session) > 0) { if (session->host->prevent_csrf == p_block) { session->error_cause = ec_CSRF; return -1; } } } return proxy_request(session, rproxy); } rproxy = rproxy->next; } #endif /* Actions based on request method */ switch (session->request_method) { case TRACE: if (session->binding->enable_trace == false) { return 501; } return handle_trace_request(session); case PUT: case DELETE: if ((session->binding->enable_alter == false) && (session->host->webdav_app == false)) { return 501; } break; case unknown: return 400; case unsupported: if (session->host->webdav_app == false) { return 501; } break; default: break; } if (duplicate_host(session) == false) { log_error(session, "duplicate_host() error"); return 500; } #ifdef ENABLE_TOOLKIT if (session->host->ignore_dot_hiawatha == false) { if (load_user_root_config(session) == -1) { return 500; } } /* URL toolkit */ init_toolkit_options(&toolkit_options); toolkit_options.method = session->method; toolkit_options.website_root = session->host->website_root; toolkit_options.url_toolkit = session->config->url_toolkit; toolkit_options.allow_dot_files = session->host->allow_dot_files; toolkit_options.http_headers = session->http_headers; #ifdef ENABLE_SSL toolkit_options.use_ssl = session->binding->use_ssl; #endif if (((session->request_method != PUT) && (session->request_method != DELETE)) || session->host->webdav_app) { for (i = 0; i < session->host->toolkit_rules.size; i++) { if ((result = use_toolkit(session->uri, session->host->toolkit_rules.item[i], &toolkit_options)) == UT_ERROR) { return 500; } if ((toolkit_options.ban > 0) && (ip_allowed(&(session->ip_address), session->config->banlist_mask) != deny)) { ban_ip(&(session->ip_address), toolkit_options.ban, session->config->kick_on_ban); log_system(session, "Client banned because of URL match in UrlToolkit rule"); #ifdef ENABLE_MONITOR if (session->config->monitor_enabled) { monitor_count_ban(session); } #endif return 403; } session->toolkit_fastcgi = toolkit_options.fastcgi_server; if (toolkit_options.new_url != NULL) { if (register_tempdata(&(session->tempdata), toolkit_options.new_url, tc_data) == -1) { free(toolkit_options.new_url); log_error(session, "error registering temporary data"); return 500; } session->uri = toolkit_options.new_url; } if (result == UT_REDIRECT) { if ((session->location = strdup(toolkit_options.new_url)) == NULL) { return -1; } session->cause_of_301 = location; return 301; } if (result == UT_DENY_ACCESS) { log_error(session, "access denied via URL toolkit rule"); return 403; } if (toolkit_options.expire > -1) { session->expires = toolkit_options.expire; session->caco_private = toolkit_options.caco_private; } } } #endif /* Find GET data */ if ((qmark = strchr(session->uri, '?')) != NULL) { *qmark = '\0'; session->vars = qmark + 1; } url_decode(session->uri); session->uri_len = strlen(session->uri); if ((session->vars != NULL) && (session->host->secure_url)) { if (forbidden_chars_present(session->vars)) { log_error(session, "URL contains forbidden characters"); return 403; } } if (validate_url(session) == false) { return -1; } if ((result = uri_to_path(session)) != 200) { return result; } /* Load configfile from directories */ if (session->host->ignore_dot_hiawatha == false) { if (load_user_config(session) == -1) { return 500; } } if ((result = copy_directory_settings(session)) != 200) { return result; } switch (access = allow_client(session)) { case deny: log_error(session, fb_accesslist); return 403; case allow: break; case pwd: case unspecified: if ((auth_result = http_authentication_result(session, access == unspecified)) != 200) { return auth_result; } } switch (is_directory(session->file_on_disk)) { case error: return 500; case yes: session->uri_is_dir = true; break; case no: if (((session->request_method != PUT) || session->host->webdav_app) && (session->host->enable_path_info)) { if ((result = get_path_info(session)) != 200) { return result; } } break; case no_access: log_error(session, fb_filesystem); return 403; case not_found: if (session->request_method == DELETE) { return 404; } } #ifdef ENABLE_TOOLKIT if ((session->toolkit_fastcgi == NULL) && session->uri_is_dir) { #else if (session->uri_is_dir) { #endif length = strlen(session->file_on_disk); if (*(session->file_on_disk + length - 1) == '/') { strcpy(session->file_on_disk + length, session->host->start_file); } else { return 301; } } if (get_target_extension(session) == -1) { log_error(session, "error getting extension"); return 500; } if (((session->request_method != PUT) && (session->request_method != DELETE)) || session->host->webdav_app) { check_target_is_cgi(session); } /* Handle request based on request method */ request_method = session->request_method; if (session->host->webdav_app) { if ((request_method == PUT) || (request_method == DELETE)) { request_method = POST; } } switch (request_method) { case GET: case HEAD: if (session->cgi_type != no_cgi) { session->body = NULL; result = execute_cgi(session); #ifdef ENABLE_XSLT } else if ((xslt_file = find_xslt_file(session)) != NULL) { result = handle_xml_file(session, xslt_file); free(xslt_file); #endif } else { result = send_file(session); } if (result == 404) { #ifdef ENABLE_XSLT if ((session->host->show_index != NULL) && (session->uri[session->uri_len - 1] == '/')) { result = show_index(session); } #endif #ifdef ENABLE_MONITOR } else if (session->config->monitor_enabled) { if ((result == 200) && (session->host->monitor_host)) { unlink(session->file_on_disk); } #endif } if ((session->request_method == GET) && (session->cgi_type == no_cgi) && (session->directory != NULL)) { if (session->directory->run_on_download != NULL) { run_program(session, session->directory->run_on_download, result); } } break; case POST: case unsupported: if (session->cgi_type != no_cgi) { result = execute_cgi(session); #ifdef ENABLE_XSLT } else if ((xslt_file = find_xslt_file(session)) != NULL) { result = handle_xml_file(session, xslt_file); free(xslt_file); #endif } else { result = 405; } break; case PUT: result = handle_put_request(session); if (((result == 201) || (result == 204)) && (session->host->run_on_alter != NULL)) { run_program(session, session->host->run_on_alter, result); } break; case DELETE: result = handle_delete_request(session); if ((result == 204) && (session->host->run_on_alter != NULL)) { run_program(session, session->host->run_on_alter, result); } break; case WHEN: send_code(session); break; default: result = 400; } return result; } /* Handle timeout upon sending request */ static void handle_timeout(t_session *session) { if ((session->config->ban_on_timeout > 0) && (ip_allowed(&(session->ip_address), session->config->banlist_mask) != deny)) { ban_ip(&(session->ip_address), session->config->ban_on_timeout, session->config->kick_on_ban); log_system(session, "Client banned because of connection timeout"); #ifdef ENABLE_MONITOR if (session->config->monitor_enabled) { monitor_count_ban(session); } #endif } else { log_system(session, "Timeout while waiting for first request"); } } /* Request has been handled, handle the return code. */ static void handle_request_result(t_session *session, int result) { char *hostname; #ifdef ENABLE_DEBUG session->current_task = "handle request result"; #endif if (result == -1) switch (session->error_cause) { case ec_MAX_REQUESTSIZE: log_system(session, "Maximum request size reached"); session->return_code = 413; send_code(session); if ((session->config->ban_on_max_request_size > 0) && (ip_allowed(&(session->ip_address), session->config->banlist_mask) != deny)) { ban_ip(&(session->ip_address), session->config->ban_on_max_request_size, session->config->kick_on_ban); log_system(session, "Client banned because of sending a too large request"); #ifdef ENABLE_MONITOR if (session->config->monitor_enabled) { monitor_count_ban(session); } #endif } break; case ec_TIMEOUT: if (session->kept_alive == 0) { session->return_code = 408; send_code(session); handle_timeout(session); } break; case ec_CLIENT_DISCONNECTED: if (session->kept_alive == 0) { log_system(session, "Silent client disconnected"); } break; case ec_SOCKET_READ_ERROR: if (errno != ECONNRESET) { log_system(session, "Error while reading request"); } break; case ec_SOCKET_WRITE_ERROR: log_request(session); break; case ec_FORCE_QUIT: log_system(session, "Client kicked"); break; case ec_SQL_INJECTION: if ((session->config->ban_on_sqli > 0) && (ip_allowed(&(session->ip_address), session->config->banlist_mask) != deny)) { ban_ip(&(session->ip_address), session->config->ban_on_sqli, session->config->kick_on_ban); hostname = (session->hostname != NULL) ? session->hostname : unknown_host; log_system(session, "Client banned because of SQL injection on %s", hostname); #ifdef ENABLE_MONITOR if (session->config->monitor_enabled) { monitor_count_ban(session); } #endif } session->return_code = 441; send_code(session); log_request(session); break; case ec_XSS: session->return_code = 442; send_code(session); log_request(session); break; case ec_CSRF: session->return_code = 443; send_code(session); log_request(session); break; case ec_INVALID_URL: if ((session->config->ban_on_invalid_url > 0) && (ip_allowed(&(session->ip_address), session->config->banlist_mask) != deny)) { ban_ip(&(session->ip_address), session->config->ban_on_invalid_url, session->config->kick_on_ban); hostname = (session->hostname != NULL) ? session->hostname : unknown_host; log_system(session, "Client banned because of invalid URL on %s", hostname); #ifdef ENABLE_MONITOR if (session->config->monitor_enabled) { monitor_count_ban(session); } #endif } send_code(session); break; default: if (session->data_sent == false) { session->return_code = 500; if (send_code(session) == -1) { session->keep_alive = false; } } } else switch (result) { case 200: break; case 201: case 204: case 304: case 412: if (session->data_sent == false) { session->return_code = result; if (send_header(session) == -1) { session->keep_alive = false; } else if (send_buffer(session, "Content-Length: 0\r\n\r\n", 21) == -1) { session->keep_alive = false; } } break; case 411: case 413: session->keep_alive = false; if (session->data_sent == false) { session->return_code = result; if (send_header(session) == -1) { session->keep_alive = false; } else if (send_buffer(session, "Content-Length: 0\r\n\r\n", 21) == -1) { session->keep_alive = false; } } break; case 400: log_garbage(session); if (session->data_sent == false) { session->return_code = 400; if (send_code(session) == -1) { session->keep_alive = false; } } if ((session->config->ban_on_garbage > 0) && (ip_allowed(&(session->ip_address), session->config->banlist_mask) != deny)) { ban_ip(&(session->ip_address), session->config->ban_on_garbage, session->config->kick_on_ban); log_system(session, "Client banned because of sending garbage"); #ifdef ENABLE_MONITOR if (session->config->monitor_enabled) { monitor_count_ban(session); } #endif } #ifdef ENABLE_MONITOR if (session->config->monitor_enabled) { monitor_count_bad_request(session); } #endif break; case 401: case 403: case 404: case 501: case 503: if (session->data_sent == false) { switch (handle_error(session, result)) { case -1: session->keep_alive = false; break; case 200: break; default: if (session->data_sent == false) { session->return_code = result; if (send_code(session) == -1) { session->keep_alive = false; } } } } break; case 500: session->keep_alive = false; default: if (session->data_sent == false) { session->return_code = result; send_code(session); } } if ((result > 0) && (result != 400)) { log_request(session); } else { session->keep_alive = false; } }
int main (int argc, char *argv[]) { int sts; int i; int buflen; int access; char buff [BUFFER_SIZE]; sip_ticket_t ticket; extern char *optarg; /* Defined in libc getopt and unistd.h */ int ch1; char configfile[64]="siproxd"; /* basename of configfile */ int config_search=1; /* search the config file */ int cmdline_debuglevel=0; char *pidfilename=NULL; struct sigaction act; log_set_stderr(1); /* * setup signal handlers */ act.sa_handler=sighandler; sigemptyset(&act.sa_mask); act.sa_flags=SA_RESTART; if (sigaction(SIGTERM, &act, NULL)) { ERROR("Failed to install SIGTERM handler"); } if (sigaction(SIGINT, &act, NULL)) { ERROR("Failed to install SIGINT handler"); } if (sigaction(SIGUSR2, &act, NULL)) { ERROR("Failed to install SIGUSR2 handler"); } /* * prepare default configuration */ make_default_config(); log_set_pattern(configuration.debuglevel); /* * parse command line */ { #ifdef HAVE_GETOPT_LONG int option_index = 0; static struct option long_options[] = { {"help", no_argument, NULL, 'h'}, {"config", required_argument, NULL, 'c'}, {"debug", required_argument, NULL, 'd'}, {"pid-file", required_argument, NULL,'p'}, {0,0,0,0} }; while ((ch1 = getopt_long(argc, argv, "hc:d:p:", long_options, &option_index)) != -1) { #else /* ! HAVE_GETOPT_LONG */ while ((ch1 = getopt(argc, argv, "hc:d:p:")) != -1) { #endif switch (ch1) { case 'h': /* help */ DEBUGC(DBCLASS_CONFIG,"option: help"); fprintf(stderr,str_helpmsg); exit(0); break; case 'c': /* load config file */ DEBUGC(DBCLASS_CONFIG,"option: config file=%s",optarg); i=sizeof(configfile)-1; strncpy(configfile,optarg,i-1); configfile[i]='\0'; config_search=0; break; case 'd': /* set debug level */ DEBUGC(DBCLASS_CONFIG,"option: set debug level: %s",optarg); cmdline_debuglevel=atoi(optarg); log_set_pattern(cmdline_debuglevel); break; case 'p': pidfilename = optarg; break; default: DEBUGC(DBCLASS_CONFIG,"no command line options"); break; } } } /* * Init stuff */ INFO(PACKAGE"-"VERSION"-"BUILDSTR" "UNAME" starting up"); /* read the config file */ if (read_config(configfile, config_search) == STS_FAILURE) exit(1); /* if a debug level > 0 has been given on the commandline use its value and not what is in the config file */ if (cmdline_debuglevel != 0) { configuration.debuglevel=cmdline_debuglevel; } /* * open a the pwfile instance, so we still have access after * we possibly have chroot()ed to somewhere. */ if (configuration.proxy_auth_pwfile) { siproxd_passwordfile = fopen(configuration.proxy_auth_pwfile, "r"); } else { siproxd_passwordfile = NULL; } /* set debug level as desired */ log_set_pattern(configuration.debuglevel); log_set_listen_port(configuration.debugport); /* change user and group IDs */ secure_enviroment(); /* daemonize if requested to */ if (configuration.daemonize) { DEBUGC(DBCLASS_CONFIG,"daemonizing"); if (fork()!=0) exit(0); setsid(); if (fork()!=0) exit(0); log_set_stderr(0); INFO("daemonized, pid=%i", getpid()); } /* write PID file of main thread */ if (pidfilename == NULL) pidfilename = configuration.pid_file; if (pidfilename) { FILE *pidfile; DEBUGC(DBCLASS_CONFIG,"creating PID file [%s]", pidfilename); sts=unlink(configuration.pid_file); if ((sts==0) ||(errno == ENOENT)) { if ((pidfile=fopen(pidfilename, "w"))) { fprintf(pidfile,"%i\n",(int)getpid()); fclose(pidfile); } else { WARN("couldn't create new PID file: %s", strerror(errno)); } } else { WARN("couldn't delete old PID file: %s", strerror(errno)); } } /* initialize the RTP proxy */ sts=rtpproxy_init(); if (sts != STS_SUCCESS) { ERROR("unable to initialize RTP proxy - aborting"); exit(1); } /* init the oSIP parser */ parser_init(); /* listen for incoming messages */ sts=sipsock_listen(); if (sts == STS_FAILURE) { /* failure to allocate SIP socket... */ ERROR("unable to bind to SIP listening socket - aborting"); exit(1); } /* initialize the registration facility */ register_init(); /* * silence the log - if so required... */ log_set_silence(configuration.silence_log); INFO(PACKAGE"-"VERSION"-"BUILDSTR" "UNAME" started"); /***************************** * Main loop *****************************/ while (!exit_program) { DEBUGC(DBCLASS_BABBLE,"going into sipsock_wait\n"); while (sipsock_wait()<=0) { /* got no input, here by timeout. do aging */ register_agemap(); /* TCP log: check for a connection */ log_tcp_connect(); /* dump memory stats if requested to do so */ if (dmalloc_dump) { dmalloc_dump=0; #ifdef DMALLOC INFO("SIGUSR2 - DMALLOC statistics is dumped"); dmalloc_log_stats(); dmalloc_log_unfreed(); #else INFO("SIGUSR2 - DMALLOC support is not compiled in"); #endif } if (exit_program) goto exit_prg; } /* * got input, process */ DEBUGC(DBCLASS_BABBLE,"back from sipsock_wait"); ticket.direction=0; buflen=sipsock_read(&buff, sizeof(buff)-1, &ticket.from, &ticket.protocol); buff[buflen]='\0'; /* * evaluate the access lists (IP based filter) */ access=accesslist_check(ticket.from); if (access == 0) { DEBUGC(DBCLASS_ACCESS,"access for this packet was denied"); continue; /* there are no resources to free */ } /* * integrity checks */ sts=security_check_raw(buff, buflen); if (sts != STS_SUCCESS) { DEBUGC(DBCLASS_SIP,"security check (raw) failed"); continue; /* there are no resources to free */ } /* * init sip_msg */ sts=osip_message_init(&ticket.sipmsg); ticket.sipmsg->message=NULL; if (sts != 0) { ERROR("osip_message_init() failed... this is not good"); continue; /* skip, there are no resources to free */ } /* * RFC 3261, Section 16.3 step 1 * Proxy Behavior - Request Validation - Reasonable Syntax * (parse the received message) */ sts=sip_message_parse(ticket.sipmsg, buff, buflen); if (sts != 0) { ERROR("sip_message_parse() failed... this is not good"); DUMP_BUFFER(-1, buff, buflen); goto end_loop; /* skip and free resources */ } /* * integrity checks - parsed buffer */ sts=security_check_sip(&ticket); if (sts != STS_SUCCESS) { ERROR("security_check_sip() failed... this is not good"); DUMP_BUFFER(-1, buff, buflen); goto end_loop; /* skip and free resources */ } /* * RFC 3261, Section 16.3 step 2 * Proxy Behavior - Request Validation - URI scheme * (check request URI and refuse with 416 if not understood) */ /* NOT IMPLEMENTED */ /* * RFC 3261, Section 16.3 step 3 * Proxy Behavior - Request Validation - Max-Forwards check * (check Max-Forwards header and refuse with 483 if too many hops) */ { osip_header_t *max_forwards; int forwards_count = DEFAULT_MAXFWD; osip_message_get_max_forwards(ticket.sipmsg, 0, &max_forwards); if (max_forwards && max_forwards->hvalue) { forwards_count = atoi(max_forwards->hvalue); } DEBUGC(DBCLASS_PROXY,"checking Max-Forwards (=%i)",forwards_count); if (forwards_count <= 0) { DEBUGC(DBCLASS_SIP, "Forward count reached 0 -> 483 response"); sip_gen_response(&ticket, 483 /*Too many hops*/); goto end_loop; /* skip and free resources */ } } /* * RFC 3261, Section 16.3 step 4 * Proxy Behavior - Request Validation - Loop Detection check * (check for loop and return 482 if a loop is detected) */ if (check_vialoop(&ticket) == STS_TRUE) { /* make sure we don't end up in endless loop when detecting * an loop in an "loop detected" message - brrr */ if (MSG_IS_RESPONSE(ticket.sipmsg) && MSG_TEST_CODE(ticket.sipmsg, 482)) { DEBUGC(DBCLASS_SIP,"loop in loop-response detected, ignoring"); } else { DEBUGC(DBCLASS_SIP,"via loop detected, ignoring request"); sip_gen_response(&ticket, 482 /*Loop detected*/); } goto end_loop; /* skip and free resources */ } /* * RFC 3261, Section 16.3 step 5 * Proxy Behavior - Request Validation - Proxy-Require check * (check Proxy-Require header and return 420 if unsupported option) */ /* NOT IMPLEMENTED */ /* * RFC 3261, Section 16.5 * Proxy Behavior - Determining Request Targets */ /* NOT IMPLEMENTED */ DEBUGC(DBCLASS_SIP,"received SIP type %s:%s", (MSG_IS_REQUEST(ticket.sipmsg))? "REQ" : "RES", (MSG_IS_REQUEST(ticket.sipmsg) ? ((ticket.sipmsg->sip_method)? ticket.sipmsg->sip_method : "NULL") : ((ticket.sipmsg->reason_phrase) ? ticket.sipmsg->reason_phrase : "NULL"))); /********************************* * The message did pass all the * tests above and is now ready * to be proxied. * Before we do so, we apply some * additional preprocessing *********************************/ /* Dial shortcuts */ if (configuration.pi_shortdial) { sts = plugin_shortdial(&ticket); if (sts == STS_SIP_SENT) goto end_loop; } /********************************* * finally proxy the message. * This includes the masquerading * of the local UA and starting/ * stopping the RTP proxy for this * call *********************************/ /* * if a REQ REGISTER, check if it is directed to myself, * or am I just the outbound proxy but no registrar. * - If I'm the registrar, register & generate answer * - If I'm just the outbound proxy, register, rewrite & forward */ if (MSG_IS_REGISTER(ticket.sipmsg) && MSG_IS_REQUEST(ticket.sipmsg)) { if (access & ACCESSCTL_REG) { osip_uri_t *url; struct in_addr addr1, addr2, addr3; int dest_port; url = osip_message_get_uri(ticket.sipmsg); dest_port= (url->port)?atoi(url->port):SIP_PORT; if ( (get_ip_by_host(url->host, &addr1) == STS_SUCCESS) && (get_interface_ip(IF_INBOUND,&addr2) == STS_SUCCESS) && (get_interface_ip(IF_OUTBOUND,&addr3) == STS_SUCCESS)) { if ((configuration.sip_listen_port == dest_port) && ((memcmp(&addr1, &addr2, sizeof(addr1)) == 0) || (memcmp(&addr1, &addr3, sizeof(addr1)) == 0))) { /* I'm the registrar, send response myself */ sts = register_client(&ticket, 0); sts = register_response(&ticket, sts); } else { /* I'm just the outbound proxy */ DEBUGC(DBCLASS_SIP,"proxying REGISTER request to:%s", url->host); sts = register_client(&ticket, 1); if (sts == STS_SUCCESS) { sts = proxy_request(&ticket); } } } else { sip_gen_response(&ticket, 408 /*request timeout*/); } } else { WARN("non-authorized registration attempt from %s", utils_inet_ntoa(ticket.from.sin_addr)); } /* * check if outbound interface is UP. * If not, send back error to UA and * skip any proxying attempt */ } else if (get_interface_ip(IF_OUTBOUND,NULL) != STS_SUCCESS) { DEBUGC(DBCLASS_SIP, "got a %s to proxy, but outbound interface " "is down", (MSG_IS_REQUEST(ticket.sipmsg))? "REQ" : "RES"); if (MSG_IS_REQUEST(ticket.sipmsg)) sip_gen_response(&ticket, 408 /*request timeout*/); /* * MSG is a request, add current via entry, * do a lookup in the URLMAP table and * send to the final destination */ } else if (MSG_IS_REQUEST(ticket.sipmsg)) { if (access & ACCESSCTL_SIP) { sts = proxy_request(&ticket); } else { INFO("non-authorized request received from %s", utils_inet_ntoa(ticket.from.sin_addr)); } /* * MSG is a response, remove current via and * send to the next VIA in chain */ } else if (MSG_IS_RESPONSE(ticket.sipmsg)) { if (access & ACCESSCTL_SIP) { sts = proxy_response(&ticket); } else { INFO("non-authorized response received from %s", utils_inet_ntoa(ticket.from.sin_addr)); } /* * unsupported message */ } else { ERROR("received unsupported SIP type %s %s", (MSG_IS_REQUEST(ticket.sipmsg))? "REQ" : "RES", ticket.sipmsg->sip_method); } /********************************* * Done with proxying. Message * has been sent to its destination. *********************************/ /* * free the SIP message buffers */ end_loop: osip_message_free(ticket.sipmsg); } /* while TRUE */ exit_prg: /* save current known SIP registrations */ register_save(); INFO("properly terminating siproxd"); /* remove PID file */ if (pidfilename) { DEBUGC(DBCLASS_CONFIG,"deleting PID file [%s]", pidfilename); sts=unlink(pidfilename); if (sts != 0) { WARN("couldn't delete old PID file: %s", strerror(errno)); } } /* END */ return 0; } /* main */ /* * Signal handler * * this one is called asynchronously whevener a registered * signal is applied. Just set a flag and don't do any funny * things here. */ static void sighandler(int sig) { if (sig==SIGTERM) exit_program=1; if (sig==SIGINT) exit_program=1; if (sig==SIGUSR2) dmalloc_dump=1; return; }
static void work_http( connection* conn ) { int i; virtual_host * host; //check if the connection cannot work. if( conn->state != C_READY ) return; conn->state = C_REQUESTING; http_request( conn ); if( conn->state != C_REQUESTING ) return; //response conn->code = 200; conn->state = C_RESPONSING; /* Check Host and then set root directory. */ host = loop_search( &conn->server->loop_vhost, conn->host, vhost_searcher ); if( !host ){ host = loop_search( &conn->server->loop_vhost, "*", vhost_searcher ); } if( host ){ //read root conn->root_dir = host->root_dir; if( !loop_is_empty( &host->loop_rewrite ) ) loop_search( &host->loop_rewrite, (void*)conn, loop_rewrite_match ); http_parse_uri( conn ); DBG("[%s]%s%s", conn->client->ip_string, conn->host, conn->uri ); _RESPONSE: http_parse_path( conn ); conn->document_type = http_doctype( conn->server, conn->extension ); if( !conn->document_type ){ http_error( conn, 404, "<h1>File not found.</h1>" ); }else if( conn->extension[0] && strstr( conn->server->asp_exts, conn->extension ) ) { //php do ... exec_asp( conn ); }else if( host->proxy && ( !host->proxy_exts[0] || strstr( host->proxy_exts, conn->extension ) ) ) { // uses proxy server proxy_request( conn, host->proxy_ip, host->proxy_port ); }else if( access(conn->full_path, 0)==0 ){ if( is_dir(conn->full_path) ){ char* tmp; NEW( tmp, PATH_LEN+32 ); if( conn->script_name[strlen(conn->script_name)-1] != '/' ){ //Are you sure that script starts with '/'? sprintf( tmp, "http://%s%s/", conn->host, conn->script_name ); http_redirect( conn, tmp ); }else{ if( tmp ){ for( i = 0; i<10; i++ ) { if( !conn->server->default_pages[i][0] ) { i=10; break; } sprintf( tmp, "%s/%s", conn->full_path, conn->server->default_pages[i] ); if( access( tmp, 0 ) == 0 ) { //091004 by Huang Guan. sprintf( conn->script_name, "%s%s", conn->script_name, conn->server->default_pages[i] ); DEL( tmp ); goto _RESPONSE; } } } if( i == 10 ){ // List Directory if( host->list ){ int ret; NEW( conn->data_send, MAX_DATASEND+4 ); strcpy( conn->extension, "html" ); conn->document_type = http_doctype( conn->server, conn->extension ); ret = listdir( conn->data_send, MAX_DATASEND, conn->full_path, conn->script_name ); conn->data_size = ret; }else{ http_error( conn, 403, "<h1>Forbidden</h1>" ); } } } DEL( tmp ); }else{ http_sendfile( conn, conn->full_path ); } }else if( strncmp(conn->current_dir, "/system", 7)==0 && conn->root_dir==host->root_dir ){ strcpy(conn->script_name, conn->script_name+7); conn->root_dir = conn->client->server->root_dir; goto _RESPONSE; }else{ http_error( conn, 404, "<h1>File not found.</h1>" ); } }else{ http_error( conn, 403, "<h1>Unknown host name.</h1>" ); } if( conn->state == C_RESPONSING ) http_response( conn ); conn->requests ++; if( conn->form_data ) DEL( conn->form_data ); if( conn->data_send ) DEL( conn->data_send ); if( conn->session ) conn->session->reference --; conn->session = NULL; //next request if( conn->keep_alive ){ conn->state = C_READY; }else{ conn->state = C_END; } }