int cache_query(struct cache_s *cache, const char* key, void **value) { pthread_rwlock_rdlock(&cache -> lock); hashmap_entry_by_key(cache -> map, key, value); pthread_rwlock_unlock(&cache -> lock); return 0; }
/* * If there is a Content-Length header, then return the value; otherwise, return * a negative number. */ static long get_content_length(hashmap_t hashofheaders) { ssize_t len; char *data; long content_length = -1; len = hashmap_entry_by_key(hashofheaders, "content-length", (void **)&data); if (len > 0) content_length = atol(data); return content_length; }
/* * Extract the headers to remove. These headers were listed in the Connection * and Proxy-Connection headers. */ static int remove_connection_headers(hashmap_t hashofheaders) { static char* headers[] = { "connection", "proxy-connection" }; char *data; char* ptr; ssize_t len; int i; for (i = 0; i != (sizeof(headers) / sizeof(char *)); ++i) { /* Look for the connection header. If it's not found, return. */ len = hashmap_entry_by_key(hashofheaders, headers[i], (void **)&data); if (len <= 0) return 0; /* * Go through the data line and replace any special characters * with a NULL. */ ptr = data; while ((ptr = strpbrk(ptr, "()<>@,;:\\\"/[]?={} \t"))) *ptr++ = '\0'; /* * All the tokens are separated by NULLs. Now go through the * token and remove them from the hashofheaders. */ ptr = data; while (ptr < data + len) { hashmap_remove(hashofheaders, ptr); /* Advance ptr to the next token */ ptr += strlen(ptr) + 1; while (*ptr == '\0') ptr++; } /* Now remove the connection header it self. */ hashmap_remove(hashofheaders, headers[i]); } return 0; }
/* * Search for Via header in a hash of headers and either write a new Via * header, or append our information to the end of an existing Via header. * * FIXME: Need to add code to "hide" our internal information for security * purposes. */ static int write_via_header(int fd, hashmap_t hashofheaders, unsigned int major, unsigned int minor) { ssize_t len; char hostname[512]; char *data; int ret; if (config.via_proxy_name) { strlcpy(hostname, config.via_proxy_name, sizeof(hostname)); } else if (gethostname(hostname, sizeof(hostname)) < 0) { strcpy(hostname, "unknown"); } /* * See if there is a "Via" header. If so, again we need to do a bit * of processing. */ len = hashmap_entry_by_key(hashofheaders, "via", (void **)&data); if (len > 0) { ret = write_message(fd, "Via: %s, %hu.%hu %s (%s/%s)\r\n", data, major, minor, hostname, PACKAGE, VERSION); hashmap_remove(hashofheaders, "via"); } else { ret = write_message(fd, "Via: %hu.%hu %s (%s/%s)\r\n", major, minor, hostname, PACKAGE, VERSION); } return ret; }
void process_pkt(unsigned char* arg, const struct pcap_pkthdr* pkthdr, const unsigned char* packet) { int rtn = IPTRAFFIC_FUNC_SUCCESS; struct iphdr* ip_hdr = NULL; struct tcphdr* tcp_hdr = NULL; struct ethhdr * eth_hdr = NULL; unsigned char* cp = (unsigned char*)packet; struct http_request_s *req = g_cycle.request; struct http_response_s *resp = g_cycle.response; struct list_s * l = NULL; eth_hdr = (struct ethhdr*)cp; /* only IP or PPP */ u_int16_t ether_type = ntohs(eth_hdr->h_proto); if(ether_type != 0x0800 && ether_type != 0x8100) { return; } cp = cp + ETHER_HDR_LEN; /* check 802.1Q packet*/ if (ether_type == 0x8100) { cp = cp + 2; if (cp[0] == 0x88 && cp[1] == 0x64) /* PPPOE */ { cp = cp + 10; } else if (cp[0] == 0x08 && cp[1] == 0x00) /* VLAN */ { cp = cp + 2; } else { return; } } /* IP header */ ip_hdr = (struct iphdr*)cp; cp+=(ip_hdr->ihl*4); #ifdef HAVE_UDPGRE_HEADER //UDP报头 或者 GRE报头,都为8字节 if(ip_hdr->protocol == 0x11 || ip_hdr->protocol == 0x2f) { cp+=8; //GPRS报头 u_int8_t gtp_flag = *cp; switch(gtp_flag) { case 0x30: cp+=8; break; case 0x32: cp+=12; break; default: break; } //真正的IP报文 ip_hdr = (struct iphdr*)cp; cp+=(ip_hdr->ihl*4); } #endif tcp_hdr = (struct tcphdr*)cp; cp+=(tcp_hdr->doff*4); if (memcmp(cp, "GET", 3) == 0) { cp+=4; } else if(memcmp(cp, "POST", 4) == 0) { cp+=5; } else { /* 非GET/POST请求包 */ return; } /* 匹配GET请求各个字段失败 */ rtn = http_parse_get(req, cp); if (IPTRAFFIC_FUNC_ERROR == rtn) { return; } /* http 报文错误 */ if ((req->host_len <= 0) || (req->uri_len <= 0)) { return; } #if 0 /* 无效报文,例如:图片、视频、文件等 */ if(http_detect_request_type(req->url, req->url_len) == IPTRAFFIC_FUNC_ERROR) { return; } #endif /* 依据host为关键字在hash表中搜寻规则 */ hashmap_entry_by_key(g_cycle.hashmap, req->host, &l); if (NULL == l) { /* 根据host关键字未找到相应的规则,在默认规则中第二次查找 */ hashmap_entry_by_key(g_cycle.hashmap, "null", &l); if (NULL == l) { return; } } /* 匹配该规则 */ struct rule_entry_s *rule = match_rules_repled(req, l, g_cycle.filter, resp); if (!rule) { return; } #ifndef ENABLE_STAT_ONLY //收集数据,UDP实时返回指定服务器 if(rule->type_repled == REDIRECT_TYPE_RECORD) { dcenter_udp_packet(ip_hdr, req); return; } /* 生成替换后的链接*/ rtn = build_url_repled(resp->index, rule, req->url, resp->url); if(IPTRAFFIC_FUNC_ERROR == rtn) { warnlog("Wrong rule!Please check it:url=%s",req->url); return; } build_response_payload(rule, req, resp); /* 回响应报文*/ rtn = send_http_get_ack(eth_hdr, ip_hdr, tcp_hdr); if (rtn != IPTRAFFIC_FUNC_SUCCESS) { errlog( "Failed to send http get ack"); return; } /* 发送响应报文*/ rtn = send_http_resp_repled(eth_hdr, ip_hdr, tcp_hdr, resp->payload); if (rtn != IPTRAFFIC_FUNC_SUCCESS) { errlog( "Failed to send response with replaced URI"); return; } #endif rule->matched_count++; return; }
/* * Break the request line apart and figure out where to connect and * build a new request line. Finally connect to the remote server. */ static struct request_s * process_request(struct conn_s *connptr, hashmap_t hashofheaders) { char *url; struct request_s *request; int ret; size_t request_len; /* NULL out all the fields so frees don't cause segfaults. */ request = safecalloc(1, sizeof(struct request_s)); if (!request) return NULL; request_len = strlen(connptr->request_line) + 1; request->method = safemalloc(request_len); url = safemalloc(request_len); request->protocol = safemalloc(request_len); if (!request->method || !url || !request->protocol) { safefree(url); free_request_struct(request); return NULL; } ret = sscanf(connptr->request_line, "%[^ ] %[^ ] %[^ ]", request->method, url, request->protocol); if (ret < 2) { log_message(LOG_ERR, "process_request: Bad Request on file descriptor %d", connptr->client_fd); indicate_http_error(connptr, 400, "Bad Request", "detail", "Request has an invalid format", "url", url, NULL); safefree(url); free_request_struct(request); return NULL; } /* * FIXME: We need to add code for the simple HTTP/0.9 style GET * request. */ if (!url) { log_message(LOG_ERR, "process_request: Null URL on file descriptor %d", connptr->client_fd); indicate_http_error(connptr, 400, "Bad Request", "detail", "Request has an empty URL", "url", url, NULL); safefree(url); free_request_struct(request); return NULL; } if (strncasecmp(url, "http://", 7) == 0 || (UPSTREAM_CONFIGURED() && strncasecmp(url, "ftp://", 6) == 0)) { char *skipped_type = strstr(url, "//") + 2; if (extract_http_url(skipped_type, request) < 0) { indicate_http_error(connptr, 400, "Bad Request", "detail", "Could not parse URL", "url", url, NULL); safefree(url); free_request_struct(request); return NULL; } } else if (strcmp(request->method, "CONNECT") == 0) { if (extract_ssl_url(url, request) < 0) { indicate_http_error(connptr, 400, "Bad Request", "detail", "Could not parse URL", "url", url, NULL); safefree(url); free_request_struct(request); return NULL; } /* Verify that the port in the CONNECT method is allowed */ if (check_allowed_connect_ports(request->port) <= 0) { indicate_http_error(connptr, 403, "Access violation", "detail", "The CONNECT method not allowed " \ "with the port you tried to use.", "url", url, NULL); log_message(LOG_INFO, "Refused CONNECT method on port %d", request->port); safefree(url); free_request_struct(request); return NULL; } connptr->connect_method = TRUE; } else { #ifdef TRANSPARENT_PROXY /* * This section of code is used for the transparent proxy * option. You will need to configure your firewall to * redirect all connections for HTTP traffic to tinyproxy * for this to work properly. * * This code was written by Petr Lampa <*****@*****.**> */ int length; char *data; length = hashmap_entry_by_key(hashofheaders, "host", (void **)&data); if (length <= 0) { struct sockaddr_in dest_addr; if (getsockname(connptr->client_fd, (struct sockaddr *)&dest_addr, &length) < 0) { log_message(LOG_ERR, "process_request: cannot get destination IP for %d", connptr->client_fd); indicate_http_error(connptr, 400, "Bad Request", "detail", "Unknown destination", "url", url, NULL); safefree(url); free_request_struct(request); return NULL; } request->host = safemalloc(17); strcpy(request->host, inet_ntoa(dest_addr.sin_addr)); request->port = ntohs(dest_addr.sin_port); request->path = safemalloc(strlen(url) + 1); strcpy(request->path, url); safefree(url); build_url(&url, request->host, request->port, request->path); log_message(LOG_INFO, "process_request: trans IP %s %s for %d", request->method, url, connptr->client_fd); } else { request->host = safemalloc(length+1); if (sscanf(data, "%[^:]:%hu", request->host, &request->port) != 2) { strcpy(request->host, data); request->port = HTTP_PORT; } request->path = safemalloc(strlen(url) + 1); strcpy(request->path, url); safefree(url); build_url(&url, request->host, request->port, request->path); log_message(LOG_INFO, "process_request: trans Host %s %s for %d", request->method, url, connptr->client_fd); } if (config.ipAddr && strcmp(request->host, config.ipAddr) == 0) { log_message(LOG_ERR, "process_request: destination IP is localhost %d", connptr->client_fd); indicate_http_error(connptr, 400, "Bad Request", "detail", "You tried to connect to the machine the proxy is running on", "url", url, NULL); safefree(url); free_request_struct(request); return NULL; } #else log_message(LOG_ERR, "process_request: Unknown URL type on file descriptor %d", connptr->client_fd); indicate_http_error(connptr, 400, "Bad Request", "detail", "Unknown URL type", "url", url, NULL); safefree(url); free_request_struct(request); return NULL; #endif } #ifdef FILTER_ENABLE /* * Filter restricted domains/urls */ if (config.filter) { if (config.filter_url) ret = filter_url(url); else ret = filter_domain(request->host); if (ret) { update_stats(STAT_DENIED); if (config.filter_url) log_message(LOG_NOTICE, "Proxying refused on filtered url \"%s\"", url); else log_message(LOG_NOTICE, "Proxying refused on filtered domain \"%s\"", request->host); indicate_http_error(connptr, 403, "Filtered", "detail", "The request you made has been filted", "url", url, NULL); safefree(url); free_request_struct(request); return NULL; } } #endif safefree(url); /* * Check to see if they're requesting the stat host */ if (config.stathost && strcmp(config.stathost, request->host) == 0) { log_message(LOG_NOTICE, "Request for the stathost."); connptr->show_stats = TRUE; free_request_struct(request); return NULL; } /* * Break apart the protocol and update the connection structure. */ if (strncasecmp(request->protocol, "http", 4) == 0) { memcpy(request->protocol, "HTTP", 4); sscanf(request->protocol, "HTTP/%u.%u", &connptr->protocol.major, &connptr->protocol.minor); } return request; }
int do_transparent_proxy (struct conn_s *connptr, hashmap_t hashofheaders, struct request_s *request, struct config_s *conf, char **url) { socklen_t length; char *data; size_t ulen = strlen (*url); ssize_t i; length = hashmap_entry_by_key (hashofheaders, "host", (void **) &data); if (length <= 0) { struct sockaddr_in dest_addr; if (getsockname (connptr->client_fd, (struct sockaddr *) &dest_addr, &length) < 0) { log_message (LOG_ERR, "process_request: cannot get destination IP for %d", connptr->client_fd); indicate_http_error (connptr, 400, "Bad Request", "detail", "Unknown destination", "url", *url, NULL); return 0; } request->host = (char *) safemalloc (17); strlcpy (request->host, inet_ntoa (dest_addr.sin_addr), 17); request->port = ntohs (dest_addr.sin_port); request->path = (char *) safemalloc (ulen + 1); strlcpy (request->path, *url, ulen + 1); build_url (url, request->host, request->port, request->path); log_message (LOG_INFO, "process_request: trans IP %s %s for %d", request->method, *url, connptr->client_fd); } else { request->host = (char *) safemalloc (length + 1); if (sscanf (data, "%[^:]:%hu", request->host, &request->port) != 2) { strlcpy (request->host, data, length + 1); request->port = HTTP_PORT; } request->path = (char *) safemalloc (ulen + 1); strlcpy (request->path, *url, ulen + 1); build_url (url, request->host, request->port, request->path); log_message (LOG_INFO, "process_request: trans Host %s %s for %d", request->method, *url, connptr->client_fd); } if (conf->listen_addrs == NULL) { return 1; } for (i = 0; i < vector_length(conf->listen_addrs); i++) { const char *addr; addr = (char *)vector_getentry(conf->listen_addrs, i, NULL); if (addr && strcmp(request->host, addr) == 0) { log_message(LOG_ERR, "transparent: destination IP %s is local " "on socket fd %d", request->host, connptr->client_fd); indicate_http_error(connptr, 400, "Bad Request", "detail", "You tried to connect to the " "machine the proxy is running on", "url", *url, NULL); return 0; } } return 1; }