📄 tunnel.c
字号:
break; case TUNNEL_ERROR: tunnel->buf[len] = 0; log_error ("tunnel_read: received error: %s", tunnel->buf); errno = EIO; return -1; case TUNNEL_CLOSE: return 0; case TUNNEL_DISCONNECT: tunnel_in_disconnect (tunnel); if (tunnel_is_client (tunnel) && tunnel_in_connect (tunnel) == -1) return -1; errno = EAGAIN; return -1; default: log_error ("tunnel_read: protocol error: unknown request 0x%02x", req); errno = EINVAL; return -1; } errno = EAGAIN; return -1;}inttunnel_pollin_fd (Tunnel *tunnel){ if (tunnel_is_server (tunnel) && (tunnel->in_fd == -1 || tunnel->out_fd == -1)) { if (tunnel->in_fd == -1) log_verbose ("tunnel_pollin_fd: in_fd = -1; returning server_socket = %d", tunnel->server_socket); else log_verbose ("tunnel_pollin_fd: out_fd = -1; returning server_socket = %d", tunnel->server_socket); return tunnel->server_socket; } else if (tunnel->in_fd != -1) return tunnel->in_fd; else { log_error ("tunnel_pollin_fd: returning -1"); return -1; }}/*If the write connection is up and needs padding to the block lengthspecified in the second argument, send some padding.*/inttunnel_maybe_pad (Tunnel *tunnel, size_t length){ size_t padding; if (tunnel_is_disconnected (tunnel) || tunnel->bytes % length == 0 || tunnel->padding_only) return 0; padding = length - tunnel->bytes % length; if (padding > tunnel->content_length - tunnel->bytes) padding = tunnel->content_length - tunnel->bytes; return tunnel_padding (tunnel, padding);}#if 0ssize_told_parse_header (int s, int *type){ static const char *end_of_header = "\r\n\r\n"; ssize_t n, len = 0; char c; int i; *type = -1; n = read_all (s, &c, 1); if (n != 1) return -1; len += n; if (c == 'P') *type = TUNNEL_IN; else if (c == 'G') *type = TUNNEL_OUT; else { log_error ("parse_header: unknown HTTP request starting with '%c'", c); errno = EINVAL; return -1; } i = 0; while (i < 4) { n = read_all (s, &c, 1); if (n != 1 && errno != EAGAIN) return n; len += n; if (c == end_of_header[i]) i++; else i = 0; } return len;}#endifinttunnel_accept (Tunnel *tunnel){ if (tunnel->in_fd != -1 && tunnel->out_fd != -1) { log_debug ("tunnel_accept: tunnel already established"); return 0; } while (tunnel->in_fd == -1 || tunnel->out_fd == -1) { struct sockaddr_in addr; Http_request *request; struct pollfd p; ssize_t m; int len; int n; int s; p.fd = tunnel->server_socket; p.events = POLLIN; n = poll (&p, 1, (tunnel->in_fd != -1 || tunnel->out_fd != -1 ? ACCEPT_TIMEOUT * 1000 : -1)); if (n == -1) { log_error ("tunnel_accept: poll error: %s", strerror (errno)); return -1; } else if (n == 0) { log_error ("tunnel_accept: poll timed out"); errno = ETIMEDOUT; break; } len = sizeof addr; s = accept (tunnel->server_socket, (struct sockaddr *)&addr, &len); if (s == -1) { log_error ("tunnel_accept: accept error: %s", strerror (errno)); return -1; } m = http_parse_request (s, &request); if (m <= 0) return m; if (request->method == -1) { log_error ("tunnel_accept: error parsing header: %s", strerror (errno)); close (s); } else if (request->method == HTTP_POST || request->method == HTTP_PUT) { if (tunnel->in_fd == -1) { tunnel->in_fd = s;#ifdef IO_COUNT_HTTP_HEADER tunnel->in_total_raw += m; /* from parse_header() */ log_annoying ("tunnel_accept: in_total_raw = %u", tunnel->in_total_raw);#endif fcntl (tunnel->in_fd, F_SETFL, fcntl (tunnel->in_fd, F_GETFL) | O_NONBLOCK); tunnel_in_setsockopts (tunnel->in_fd); log_debug ("tunnel_accept: input connected"); } else { log_error ("rejected tunnel_in: already got a connection"); close (s); } } else if (request->method == HTTP_GET) { if (tunnel->out_fd == -1) { char str[1024]; tunnel->out_fd = s; tunnel_out_setsockopts (tunnel->out_fd); sprintf (str,"HTTP/1.1 200 OK\r\n"/* "Date: %s\r\n" *//* "Server: %s\r\n" *//* "Last-Modified: %s\r\n" *//* "ETag: %s\r\n" *//* "Accept-Ranges: %s\r\n" */"Content-Length: %d\r\n""Connection: close\r\n""Pragma: no-cache\r\n""Cache-Control: no-cache, no-store, must-revalidate\r\n""Expires: 0\r\n" /* FIXME: "0" is not a legitimate HTTP date. */"Content-Type: text/html\r\n""\r\n", /* +1 to allow for TUNNEL_DISCONNECT */ tunnel->content_length + 1); if (write_all (tunnel->out_fd, str, strlen (str)) <= 0) { log_error ("tunnel_accept: couldn't write GET header: %s", strerror (errno)); close (tunnel->out_fd); tunnel->out_fd = -1; } else { tunnel->bytes = 0; tunnel->buf_len = 0; tunnel->buf_ptr = tunnel->buf;#ifdef IO_COUNT_HTTP_HEADER tunnel->out_total_raw += strlen (str); log_annoying ("tunnel_accept: out_total_raw = %u", tunnel->out_total_raw);#endif log_debug ("tunnel_accept: output connected"); } } else { log_error ("tunnel_accept: rejected tunnel_out: " "already got a connection"); close (s); } } else { log_error ("tunnel_accept: unknown header type"); log_debug ("tunnel_accept: closing connection"); close (s); } http_destroy_request (request); } if (tunnel->in_fd == -1 || tunnel->out_fd == -1) { log_error ("tunnel_accept: in_fd = %d, out_fd = %d", tunnel->in_fd, tunnel->out_fd); if (tunnel->in_fd != -1) close (tunnel->in_fd); tunnel->in_fd = -1; log_debug ("tunnel_accept: input disconnected"); tunnel_out_disconnect (tunnel); return -1; } return 0;}Tunnel *tunnel_new_server (int port, size_t content_length){ Tunnel *tunnel; tunnel = malloc (sizeof (Tunnel)); if (tunnel == NULL) return NULL; /* If content_length is 0, a value must be determined automatically. */ /* For now, a default value will do. */ if (content_length == 0) content_length = DEFAULT_CONTENT_LENGTH; tunnel->in_fd = -1; tunnel->out_fd = -1; tunnel->server_socket = -1; tunnel->dest.host_name = NULL; tunnel->dest.host_port = port; tunnel->buf_ptr = tunnel->buf; tunnel->buf_len = 0; /* -1 to allow for TUNNEL_DISCONNECT */ tunnel->content_length = content_length - 1; tunnel->in_total_raw = 0; tunnel->in_total_data = 0; tunnel->out_total_raw = 0; tunnel->out_total_data = 0; tunnel->strict_content_length = FALSE; tunnel->server_socket = server_socket (tunnel->dest.host_port, 1); if (tunnel->server_socket == -1) { log_error ("tunnel_new_server: server_socket (%d) = -1", tunnel->dest.host_port); tunnel_destroy (tunnel); return NULL; } return tunnel;}Tunnel *tunnel_new_client (const char *host, int host_port, const char *proxy, int proxy_port, size_t content_length){ const char *remote; int remote_port; Tunnel *tunnel; log_verbose ("tunnel_new_client (\"%s\", %d, \"%s\", %d, %d)", host, host_port, proxy ? proxy : "(null)", proxy_port, content_length); tunnel = malloc (sizeof (Tunnel)); if (tunnel == NULL) { log_error ("tunnel_new_client: out of memory"); return NULL; } tunnel->in_fd = -1; tunnel->out_fd = -1; tunnel->server_socket = -1; tunnel->dest.host_name = host; tunnel->dest.host_port = host_port; tunnel->dest.proxy_name = proxy; tunnel->dest.proxy_port = proxy_port; tunnel->dest.proxy_authorization = NULL; tunnel->dest.user_agent = NULL; /* -1 to allow for TUNNEL_DISCONNECT */ tunnel->content_length = content_length - 1; tunnel->buf_ptr = tunnel->buf; tunnel->buf_len = 0; tunnel->in_total_raw = 0; tunnel->in_total_data = 0; tunnel->out_total_raw = 0; tunnel->out_total_data = 0; tunnel->strict_content_length = FALSE; if (tunnel->dest.proxy_name == NULL) { remote = tunnel->dest.host_name; remote_port = tunnel->dest.host_port; } else { remote = tunnel->dest.proxy_name; remote_port = tunnel->dest.proxy_port; } if (set_address (&tunnel->address, remote, remote_port) == -1) { log_error ("tunnel_new_client: set_address: %s", strerror (errno)); free (tunnel); return NULL; } return tunnel;}voidtunnel_destroy (Tunnel *tunnel){ if (tunnel_is_connected (tunnel) || tunnel->in_fd != -1) tunnel_close (tunnel); if (tunnel->server_socket != -1) close (tunnel->server_socket); free (tunnel);}static inttunnel_opt (Tunnel *tunnel, const char *opt, void *data, int get_flag){ if (strcmp (opt, "strict_content_length") == 0) { if (get_flag) *(int *)data = tunnel->strict_content_length; else tunnel->strict_content_length = *(int *)data; } else if (strcmp (opt, "keep_alive") == 0) { if (get_flag) *(int *)data = tunnel->keep_alive; else tunnel->keep_alive = *(int *)data; } else if (strcmp (opt, "max_connection_age") == 0) { if (get_flag) *(int *)data = tunnel->max_connection_age; else tunnel->max_connection_age = *(int *)data; } else if (strcmp (opt, "proxy_authorization") == 0) { if (get_flag) { if (tunnel->dest.proxy_authorization == NULL) *(char **)data = NULL; else *(char **)data = strdup (tunnel->dest.proxy_authorization); } else { if (tunnel->dest.proxy_authorization != NULL) free ((char *)tunnel->dest.proxy_authorization); tunnel->dest.proxy_authorization = strdup ((char *)data); if (tunnel->dest.proxy_authorization == NULL) return -1; } } else if (strcmp (opt, "user_agent") == 0) { if (get_flag) { if (tunnel->dest.user_agent == NULL) *(char **)data = NULL; else *(char **)data = strdup (tunnel->dest.user_agent); } else { if (tunnel->dest.user_agent != NULL) free ((char *)tunnel->dest.user_agent); tunnel->dest.user_agent = strdup ((char *)data); if (tunnel->dest.user_agent == NULL) return -1; } } else { errno = EINVAL; return -1; } return 0;}inttunnel_setopt (Tunnel *tunnel, const char *opt, void *data){ return tunnel_opt (tunnel, opt, data, FALSE);}inttunnel_getopt (Tunnel *tunnel, const char *opt, void *data){ return tunnel_opt (tunnel, opt, data, TRUE);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -