Client *client_new(SocksLink *sl, int fd, struct sockaddr_storage *addr, socklen_t addrlen) { Client *cl = calloc(sizeof (*cl), 1); struct bufferevent *bev; INIT_LIST_HEAD(&cl->next); INIT_LIST_HEAD(&cl->next_auth); if (!cl) return NULL; bev = bufferevent_new(fd, NULL, NULL, NULL, NULL); if (!bev) { free(cl); return NULL; } bufferevent_base_set(sl->base, bev); cl->client_method = AUTH_METHOD_INVALID; cl->server_method = AUTH_METHOD_INVALID; cl->parent = sl; cl->client.bufev = bev; cl->client.fd = fd; cl->client.addr = *addr; cl->client.addrlen = addrlen; cl->server.fd = -1; list_add(&cl->next, &sl->clients); if (sl->pipe) { client_connect_server(cl); } else { bufferevent_setcb(bev, on_client_read_init, on_client_write, on_client_event, cl); bufferevent_settimeout(bev, SOCKS5_AUTH_TIMEOUT, SOCKS5_AUTH_TIMEOUT); bufferevent_enable(bev, EV_READ|EV_WRITE); } return cl; }
static void on_client_read_auth_username(struct bufferevent *bev, void *ctx) { Client *cl = ctx; uint8_t ver, ulen, plen; uint8_t *buffer = EVBUFFER_DATA(EVBUFFER_INPUT(bev)); size_t bytes = EVBUFFER_LENGTH(EVBUFFER_INPUT(bev)); prcl_trace(cl, "received %d bytes from client", bytes); if (bytes < 2) return ; ver = buffer[0]; ulen = buffer[1]; if (ver != 0x01) { client_invalid_version(cl); return ; } if (bytes < 2 + ulen + 1) return ; plen = buffer[2 + ulen]; prcl_trace(cl, "ulen: %d, plen: %d", ulen, plen); if (bytes < 2 + ulen + 1 + plen) return ; cl->auth.username.ulen = ulen; cl->auth.username.plen = plen; memcpy(cl->auth.username.uname, buffer + 2, ulen); memcpy(cl->auth.username.passwd, buffer + 2 + ulen + 1, plen); evbuffer_drain(EVBUFFER_INPUT(bev), 2 + ulen + 1 + plen); client_connect_server(cl); }
/* case 1: server configuration(ip , port) updated case 2: server offline(No heartbeat) */ int client_reconnect(void) { static int counter =0; if (g_sockfd_client > 0){ g_sockfd_client_status = SOCKFD_CLIENT_NULL; close(g_sockfd_client); g_sockfd_client = -1; } led_ctrl(LED_D3_ALARM_SERVER_STATUS, LED_OFF); while (FAILURE == client_connect_server()){ if (g_sockfd_client > 0){ g_sockfd_client_status = SOCKFD_CLIENT_NULL; close(g_sockfd_client); g_sockfd_client = -1; } sys_log(FUNC, LOG_WARN, "Reconnect duration %dS: counter: %d",CLIENT_RECONNECT_DURATION, ++counter); sleep(CLIENT_RECONNECT_DURATION); } return SUCCESS; }
static void on_client_read_init(struct bufferevent *bev, void *ctx) { Client *cl = ctx; SocksLink *sl = cl->parent; uint8_t ver, nmeth, method; uint8_t *buffer = EVBUFFER_DATA(EVBUFFER_INPUT(bev)); size_t bytes = EVBUFFER_LENGTH(EVBUFFER_INPUT(bev)); prcl_trace(cl, "received %d bytes from client", bytes); if (bytes < 2) return ; ver = buffer[0]; nmeth = buffer[1]; if (ver != SOCKS5_VER) { client_invalid_version(cl); return ; } if (bytes < 2 + nmeth) return ; method = AUTH_METHOD_INVALID; /* Choose prefered method */ for (int i = 0; i < ARRAY_SIZE(sl->methods); ++i) { if (sl->methods[i] == AUTH_METHOD_INVALID) break ; for (int j = 0; j < nmeth; ++j) { if (sl->methods[i] == buffer[2 + j]) { method = sl->methods[i]; break ; } } if (method != AUTH_METHOD_INVALID) break ; } if (method == AUTH_METHOD_INVALID) { prcl_debug(cl, "no matching authentication method found"); } else { prcl_debug(cl, "using 0x%.2x authentication method", method); } evbuffer_drain(bev->input, 2 + nmeth); cl->client_method = method; if (method == AUTH_METHOD_NONE) client_connect_server(cl); else if (method == AUTH_METHOD_USERNAME) { bufferevent_setcb(cl->client.bufev, on_client_read_auth_username, on_client_write, on_client_event, cl); /* there is still data available in the buffer, call next callback */ if (EVBUFFER_LENGTH(EVBUFFER_INPUT(bev))) on_client_read_auth_username(bev, cl); } bufferevent_write(cl->client.bufev, (uint8_t []){SOCKS5_VER, method}, 2); if (method == AUTH_METHOD_INVALID) client_disconnect(cl); }