int main (int argc, char *argv[]) { int res = 1; if (argc != 3) { fprintf(stderr, "Usage: %s < unix:<socket_path> / tcp:<address>:<port> > <request_payload>\n", (argc > 0 ? argv[0] : "")); goto fail0; } char *connect_address = argv[1]; char *request_payload_string = argv[2]; BLog_InitStderr(); BTime_Init(); NCDValMem_Init(&request_mem); if (!NCDValParser_Parse(request_payload_string, strlen(request_payload_string), &request_mem, &request_value)) { BLog(BLOG_ERROR, "BReactor_Init failed"); goto fail1; } if (!BNetwork_GlobalInit()) { BLog(BLOG_ERROR, "BNetwork_Init failed"); goto fail1; } if (!BReactor_Init(&reactor)) { BLog(BLOG_ERROR, "BReactor_Init failed"); goto fail1; } struct BConnection_addr addr; if (!make_connect_addr(connect_address, &addr)) { goto fail2; } if (!NCDRequestClient_Init(&client, addr, &reactor, NULL, client_handler_error, client_handler_connected)) { BLog(BLOG_ERROR, "NCDRequestClient_Init failed"); goto fail2; } have_request = 0; res = BReactor_Exec(&reactor); if (have_request) { NCDRequestClientRequest_Free(&request); } NCDRequestClient_Free(&client); fail2: BReactor_Free(&reactor); fail1: NCDValMem_Free(&request_mem); BLog_Free(); fail0: DebugObjectGlobal_Finish(); return res; }
int NCDIfConfig_query (const char *ifname) { struct ifreq ifr; int flags = 0; int s = socket(AF_INET, SOCK_DGRAM, 0); if (!s) { BLog(BLOG_ERROR, "socket failed"); goto fail0; } memset(&ifr, 0, sizeof(ifr)); snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", ifname); if (ioctl(s, SIOCGIFFLAGS, &ifr)) { BLog(BLOG_ERROR, "SIOCGIFFLAGS failed"); goto fail1; } flags |= NCDIFCONFIG_FLAG_EXISTS; if ((ifr.ifr_flags&IFF_UP)) { flags |= NCDIFCONFIG_FLAG_UP; if ((ifr.ifr_flags&IFF_RUNNING)) { flags |= NCDIFCONFIG_FLAG_RUNNING; } } fail1: close(s); fail0: return flags; }
int NCDStringIndex_Init (NCDStringIndex *o) { o->entries_size = 0; if (!Array_Init(o, NCDSTRINGINDEX_INITIAL_CAPACITY)) { BLog(BLOG_ERROR, "Array_Init failed"); goto fail0; } if (!NCDStringIndex__Hash_Init(&o->hash, NCDSTRINGINDEX_INITIAL_HASH_BUCKETS)) { BLog(BLOG_ERROR, "NCDStringIndex__Hash_Init failed"); goto fail1; } for (size_t i = 0; i < B_ARRAY_LENGTH(static_strings); i++) { if (do_get(o, static_strings[i], strlen(static_strings[i])) < 0) { goto fail2; } } DebugObject_Init(&o->d_obj); return 1; fail2: for (NCD_string_id_t i = 0; i < o->entries_size; i++) { free(o->entries[i].str); } NCDStringIndex__Hash_Free(&o->hash); fail1: Array_Free(o); fail0: return 0; }
static void process_handler_closed (NCDUdevMonitor *o, int is_error) { DebugObject_Access(&o->d_obj); ASSERT(o->input_running) if (is_error) { BLog(BLOG_ERROR, "pipe error"); } else { BLog(BLOG_INFO, "pipe closed"); } // disconnect connector StreamRecvConnector_DisconnectInput(&o->connector); // set input not running o->input_running = 0; // remember input error o->input_was_error = is_error; if (!o->process_running) { report_error(o); return; } }
static void listener_olap_handler (BListener *o, int event, DWORD bytes) { DebugObject_Access(&o->d_obj); ASSERT(o->busy) ASSERT(!o->ready) ASSERT(event == BREACTOR_IOCP_EVENT_SUCCEEDED || event == BREACTOR_IOCP_EVENT_FAILED) // set not busy o->busy = 0; // schedule next accept BPending_Set(&o->next_job); if (event == BREACTOR_IOCP_EVENT_FAILED) { BLog(BLOG_ERROR, "accepting failed"); // close new socket if (closesocket(o->newsock) == SOCKET_ERROR) { BLog(BLOG_ERROR, "closesocket failed"); } return; } BLog(BLOG_INFO, "connection accepted"); // set ready o->ready = 1; // call handler o->handler(o->user); return; }
int BProcessManager_Init (BProcessManager *o, BReactor *reactor) { // init arguments o->reactor = reactor; // init signal handling sigset_t sset; ASSERT_FORCE(sigemptyset(&sset) == 0) ASSERT_FORCE(sigaddset(&sset, SIGCHLD) == 0) if (!BUnixSignal_Init(&o->signal, o->reactor, sset, (BUnixSignal_handler)signal_handler, o)) { BLog(BLOG_ERROR, "BUnixSignal_Init failed"); goto fail0; } // init processes list LinkedList2_Init(&o->processes); // init wait job BPending_Init(&o->wait_job, BReactor_PendingGroup(o->reactor), (BPending_handler)wait_job_handler, o); DebugObject_Init(&o->d_obj); return 1; fail0: return 0; }
void process_data (PacketProtoDecoder *enc) { int was_error = 0; do { uint8_t *data = enc->buf + enc->buf_start; int left = enc->buf_used; // check if header was received if (left < sizeof(struct packetproto_header)) { break; } struct packetproto_header header; memcpy(&header, data, sizeof(header)); data += sizeof(struct packetproto_header); left -= sizeof(struct packetproto_header); int data_len = ltoh16(header.len); // check data length if (data_len > enc->output_mtu) { BLog(BLOG_NOTICE, "error: packet too large"); was_error = 1; break; } // check if whole packet was received if (left < data_len) { break; } // update buffer enc->buf_start += sizeof(struct packetproto_header) + data_len; enc->buf_used -= sizeof(struct packetproto_header) + data_len; // submit packet PacketPassInterface_Sender_Send(enc->output, data, data_len); return; } while (0); if (was_error) { // reset buffer enc->buf_start = 0; enc->buf_used = 0; } else { // if we reached the end of the buffer, wrap around to allow more data to be received if (enc->buf_start + enc->buf_used == enc->buf_size) { memmove(enc->buf, enc->buf + enc->buf_start, enc->buf_used); enc->buf_start = 0; } } // receive data StreamRecvInterface_Receiver_Recv(enc->input, enc->buf + (enc->buf_start + enc->buf_used), enc->buf_size - (enc->buf_start + enc->buf_used)); // if we had error, report it if (was_error) { enc->handler_error(enc->user); return; } }
static void send_request (BArpProbe *o) { if (o->send_sending) { BLog(BLOG_ERROR, "cannot send packet while another packet is being sent!"); return; } // build packet struct arp_packet *arp = &o->send_packet; arp->hardware_type = hton16(ARP_HARDWARE_TYPE_ETHERNET); arp->protocol_type = hton16(ETHERTYPE_IPV4); arp->hardware_size = hton8(6); arp->protocol_size = hton8(4); arp->opcode = hton16(ARP_OPCODE_REQUEST); memcpy(arp->sender_mac, o->if_mac, 6); arp->sender_ip = hton32(0); memset(arp->target_mac, 0, sizeof(arp->target_mac)); arp->target_ip = o->addr; // send packet PacketPassInterface_Sender_Send(o->send_if, (uint8_t *)&o->send_packet, sizeof(o->send_packet)); // set sending o->send_sending = 1; }
int reserve_buffer (BSocksClient *o, bsize_t size) { if (size.is_overflow) { BLog(BLOG_ERROR, "size overflow"); return 0; } char *buffer = (char *)BRealloc(o->buffer, size.value); if (!buffer) { BLog(BLOG_ERROR, "BRealloc failed"); return 0; } o->buffer = buffer; return 1; }
static void set_pktinfo (SOCKET sock, int family) { DWORD opt = 1; switch (family) { case BADDR_TYPE_IPV4: { if (setsockopt(sock, IPPROTO_IP, IP_PKTINFO, (char *)&opt, sizeof(opt)) < 0) { BLog(BLOG_ERROR, "setsockopt(IP_PKTINFO) failed"); } } break; case BADDR_TYPE_IPV6: { if (setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO, (char *)&opt, sizeof(opt)) < 0) { BLog(BLOG_ERROR, "setsockopt(IPV6_PKTINFO) failed"); } } break; } }
static void listener_next_job_handler (BListener *o) { DebugObject_Access(&o->d_obj); ASSERT(!o->busy) // free ready socket if (o->ready) { BLog(BLOG_ERROR, "discarding connection"); // close new socket if (closesocket(o->newsock) == SOCKET_ERROR) { BLog(BLOG_ERROR, "closesocket failed"); } // set not ready o->ready = 0; } // create new socket if ((o->newsock = WSASocket(o->sys_family, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET) { BLog(BLOG_ERROR, "WSASocket failed"); goto fail0; } // start accept operation while (1) { memset(&o->olap.olap, 0, sizeof(o->olap.olap)); DWORD bytes; BOOL res = o->fnAcceptEx(o->sock, o->newsock, o->addrbuf, 0, sizeof(struct BListener_addrbuf_stub), sizeof(struct BListener_addrbuf_stub), &bytes, &o->olap.olap); if (res == FALSE && WSAGetLastError() != ERROR_IO_PENDING) { BLog(BLOG_ERROR, "AcceptEx failed"); continue; } break; } // set busy o->busy = 1; return; fail0: return; }
static void dgram_handler (BArpProbe *o, int event) { DebugObject_Access(&o->d_obj); BLog(BLOG_ERROR, "packet socket error"); // report error DEBUGERROR(&o->d_err, o->handler(o->user, BARPPROBE_EVENT_ERROR)); return; }
static NCD_string_id_t do_get (NCDStringIndex *o, const char *str, size_t str_len) { ASSERT(str) NCDStringIndex_hash_key key = {str, str_len}; NCDStringIndex__HashRef ref = NCDStringIndex__Hash_Lookup(&o->hash, o->entries, key); ASSERT(ref.link == -1 || ref.link >= 0) ASSERT(ref.link == -1 || ref.link < o->entries_size) ASSERT(ref.link == -1 || (ref.ptr->str_len == str_len && !memcmp(ref.ptr->str, str, str_len))) if (ref.link != -1) { return ref.link; } if (o->entries_size == o->entries_capacity) { if (!Array_DoubleUp(o)) { BLog(BLOG_ERROR, "Array_DoubleUp failed"); return -1; } if (!NCDStringIndex__Hash_MultiplyBuckets(&o->hash, o->entries, 1)) { BLog(BLOG_ERROR, "NCDStringIndex__Hash_MultiplyBuckets failed"); return -1; } } ASSERT(o->entries_size < o->entries_capacity) struct NCDStringIndex__entry *entry = &o->entries[o->entries_size]; if (!(entry->str = b_strdup_bin(str, str_len))) { BLog(BLOG_ERROR, "b_strdup_bin failed"); return -1; } entry->str_len = str_len; entry->has_nulls = !!memchr(str, '\0', str_len); NCDStringIndex__HashRef newref = {entry, o->entries_size}; int res = NCDStringIndex__Hash_Insert(&o->hash, o->entries, newref, NULL); ASSERT_EXECUTE(res) return o->entries_size++; }
static void work_signals (BProcessManager *o) { // read exit status with waitpid() int status; pid_t pid = waitpid(-1, &status, WNOHANG); if (pid <= 0) { return; } // schedule next waitpid BPending_Set(&o->wait_job); // find process BProcess *p = find_process(o, pid); if (!p) { BLog(BLOG_DEBUG, "unknown child %p"); } if (WIFEXITED(status)) { uint8_t exit_status = WEXITSTATUS(status); BLog(BLOG_INFO, "child %"PRIiMAX" exited with status %"PRIu8, (intmax_t)pid, exit_status); if (p) { call_handler(p, 1, exit_status); return; } } else if (WIFSIGNALED(status)) { int signo = WTERMSIG(status); BLog(BLOG_INFO, "child %"PRIiMAX" exited with signal %d", (intmax_t)pid, signo); if (p) { call_handler(p, 0, 0); return; } } else { BLog(BLOG_ERROR, "unknown wait status type for pid %"PRIiMAX" (%d)", (intmax_t)pid, status); } }
int NCDIfConfig_set_down (const char *ifname) { if (strlen(ifname) >= IFNAMSIZ) { BLog(BLOG_ERROR, "ifname too long"); return 0; } char cmd[50 + IFNAMSIZ]; sprintf(cmd, IP_CMD" link set %s down", ifname); return !run_command(cmd); }
static int make_connect_addr (const char *str, struct BConnection_addr *out_addr) { size_t i; if (i = string_begins_with(str, "unix:")) { *out_addr = BConnection_addr_unix(str + i, strlen(str + i)); } else if (i = string_begins_with(str, "tcp:")) { BAddr baddr; if (!BAddr_Parse2(&baddr, (char *)str + i, NULL, 0, 1)) { BLog(BLOG_ERROR, "failed to parse tcp address"); return 0; } *out_addr = BConnection_addr_baddr(baddr); } else { BLog(BLOG_ERROR, "address must start with unix: or tcp:"); return 0; } return 1; }
int BProcess_Kill (BProcess *o) { DebugObject_Access(&o->d_obj); DebugError_AssertNoError(&o->d_err); ASSERT(o->pid > 0) if (kill(o->pid, SIGKILL) < 0) { BLog(BLOG_ERROR, "kill(%"PRIiMAX", SIGKILL) failed", (intmax_t)o->pid); return 0; } return 1; }
static void connector_abort (BConnector *o) { if (o->sock != INVALID_SOCKET) { // cancel I/O if (o->busy) { if (!CancelIo((HANDLE)o->sock)) { BLog(BLOG_ERROR, "CancelIo failed"); } } // close socket if (closesocket(o->sock) == SOCKET_ERROR) { BLog(BLOG_ERROR, "closesocket failed"); } } // wait for connect operation to finish if (o->busy) { BReactorIOCPOverlapped_Wait(&o->olap, NULL, NULL); } // free olap BReactorIOCPOverlapped_Free(&o->olap); }
int NCDPlaceholderDb_Init (NCDPlaceholderDb *o, NCDStringIndex *string_index) { ASSERT(string_index) o->count = 0; o->capacity = 1; o->string_index = string_index; if (!(o->arr = BAllocArray(o->capacity, sizeof(o->arr[0])))) { BLog(BLOG_ERROR, "NCDPlaceholderDb_Init failed"); return 0; } return 1; }
static int func_globalinit (struct NCDInterpModuleGroup *group, const struct NCDModuleInst_iparams *params) { // allocate global state structure struct global *g = BAlloc(sizeof(*g)); if (!g) { BLog(BLOG_ERROR, "BAlloc failed"); return 0; } // set group state pointer group->group_state = g; // init instances list LinkedList1_Init(&g->instances); return 1; }
static void process_handler_terminated (NCDUdevMonitor *o, int normally, uint8_t normally_exit_status) { DebugObject_Access(&o->d_obj); ASSERT(o->process_running) BLog(BLOG_INFO, "process terminated"); // set process not running (so we don't try to kill it) o->process_running = 0; // remember process error o->process_was_error = !(normally && normally_exit_status == 0); if (!o->input_running) { report_error(o); return; } }
static void connector_olap_handler (BConnector *o, int event, DWORD bytes) { DebugObject_Access(&o->d_obj); ASSERT(o->sock != INVALID_SOCKET) ASSERT(o->busy) ASSERT(!o->ready) ASSERT(event == BREACTOR_IOCP_EVENT_SUCCEEDED || event == BREACTOR_IOCP_EVENT_FAILED) // set not busy o->busy = 0; if (event == BREACTOR_IOCP_EVENT_FAILED) { BLog(BLOG_ERROR, "connection failed"); } else { // set ready o->ready = 1; } // call handler o->handler(o->user, !o->ready); return; }
int DPReceiveDevice_Init (DPReceiveDevice *o, int device_mtu, DPReceiveDevice_output_func output_func, void *output_func_user, BReactor *reactor, int relay_flow_buffer_size, int relay_flow_inactivity_time) { ASSERT(device_mtu >= 0) ASSERT(device_mtu <= INT_MAX - DATAPROTO_MAX_OVERHEAD) ASSERT(output_func) ASSERT(relay_flow_buffer_size > 0) // init arguments o->device_mtu = device_mtu; o->output_func = output_func; o->output_func_user = output_func_user; o->reactor = reactor; o->relay_flow_buffer_size = relay_flow_buffer_size; o->relay_flow_inactivity_time = relay_flow_inactivity_time; // remember packet MTU o->packet_mtu = DATAPROTO_MAX_OVERHEAD + o->device_mtu; // init relay router if (!DPRelayRouter_Init(&o->relay_router, o->device_mtu, o->reactor)) { BLog(BLOG_ERROR, "DPRelayRouter_Init failed"); goto fail0; } // have no peer ID o->have_peer_id = 0; // init peers list LinkedList1_Init(&o->peers_list); DebugObject_Init(&o->d_obj); return 1; fail0: return 0; }
static void receiver_recv_handler_send (DPReceiveReceiver *o, uint8_t *packet, int packet_len) { DebugObject_Access(&o->d_obj); DPReceivePeer *peer = o->peer; DPReceiveDevice *device = peer->device; ASSERT(packet_len >= 0) ASSERT(packet_len <= device->packet_mtu) uint8_t *data = packet; int data_len = packet_len; int local = 0; DPReceivePeer *src_peer; DPReceivePeer *relay_dest_peer = NULL; // check header if (data_len < sizeof(struct dataproto_header)) { BLog(BLOG_WARNING, "no dataproto header"); goto out; } struct dataproto_header header; memcpy(&header, data, sizeof(header)); data += sizeof(header); data_len -= sizeof(header); uint8_t flags = ltoh8(header.flags); peerid_t from_id = ltoh16(header.from_id); int num_ids = ltoh16(header.num_peer_ids); // check destination ID if (!(num_ids == 0 || num_ids == 1)) { BLog(BLOG_WARNING, "wrong number of destinations"); goto out; } peerid_t to_id = 0; // to remove warning if (num_ids == 1) { if (data_len < sizeof(struct dataproto_peer_id)) { BLog(BLOG_WARNING, "missing destination"); goto out; } struct dataproto_peer_id id; memcpy(&id, data, sizeof(id)); to_id = ltoh16(id.id); data += sizeof(id); data_len -= sizeof(id); } // check remaining data if (data_len > device->device_mtu) { BLog(BLOG_WARNING, "frame too large"); goto out; } // inform sink of received packet if (peer->dp_sink) { DataProtoSink_Received(peer->dp_sink, !!(flags & DATAPROTO_FLAGS_RECEIVING_KEEPALIVES)); } if (num_ids == 1) { // find source peer if (!(src_peer = find_peer(device, from_id))) { BLog(BLOG_INFO, "source peer %d not known", (int)from_id); goto out; } // is frame for device or another peer? if (device->have_peer_id && to_id == device->peer_id) { // let the frame decider analyze the frame FrameDeciderPeer_Analyze(src_peer->decider_peer, data, data_len); // pass frame to device local = 1; } else { // check if relaying is allowed if (!peer->is_relay_client) { BLog(BLOG_WARNING, "relaying not allowed"); goto out; } // provided source ID must be the peer sending the frame if (src_peer != peer) { BLog(BLOG_WARNING, "relay source must be the sending peer"); goto out; } // find destination peer DPReceivePeer *dest_peer = find_peer(device, to_id); if (!dest_peer) { BLog(BLOG_INFO, "relay destination peer not known"); goto out; } // destination cannot be source if (dest_peer == src_peer) { BLog(BLOG_WARNING, "relay destination cannot be the source"); goto out; } relay_dest_peer = dest_peer; } } out: // accept packet PacketPassInterface_Done(&o->recv_if); // pass packet to device if (local) { o->device->output_func(o->device->output_func_user, data, data_len); } // relay frame if (relay_dest_peer) { DPRelayRouter_SubmitFrame(&device->relay_router, &src_peer->relay_source, &relay_dest_peer->relay_sink, data, data_len, device->relay_flow_buffer_size, device->relay_flow_inactivity_time); } }
static int run_command (const char *cmd) { BLog(BLOG_INFO, "run: %s", cmd); return system(cmd); }
int BProcess_Init2 (BProcess *o, BProcessManager *m, BProcess_handler handler, void *user, const char *file, char *const argv[], struct BProcess_params params) { // init arguments o->m = m; o->handler = handler; o->user = user; // count fds size_t num_fds; for (num_fds = 0; params.fds[num_fds] >= 0; num_fds++); // block signals // needed to prevent parent's signal handlers from being called // in the child sigset_t sset_all; sigfillset(&sset_all); sigset_t sset_old; if (sigprocmask(SIG_SETMASK, &sset_all, &sset_old) < 0) { BLog(BLOG_ERROR, "sigprocmask failed"); goto fail0; } // fork pid_t pid = fork(); if (pid == 0) { // this is child // restore signal dispositions for (int i = 1; i < NSIG; i++) { struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_handler = SIG_DFL; sa.sa_flags = 0; sigaction(i, &sa, NULL); } // unblock signals sigset_t sset_none; sigemptyset(&sset_none); if (sigprocmask(SIG_SETMASK, &sset_none, NULL) < 0) { abort(); } // copy fds array int *fds2 = malloc((num_fds + 1) * sizeof(fds2[0])); if (!fds2) { abort(); } memcpy(fds2, params.fds, (num_fds + 1) * sizeof(fds2[0])); // find maximum file descriptors int max_fd = sysconf(_SC_OPEN_MAX); if (max_fd < 0) { abort(); } // close file descriptors for (int i = 0; i < max_fd; i++) { // if it's one of the given fds, don't close it if (fds_contains(fds2, i, NULL)) { continue; } close(i); } const int *orig_fds_map = params.fds_map; // map fds to requested fd numbers while (*fds2 >= 0) { // resolve possible conflict size_t cpos; if (fds_contains(fds2 + 1, *params.fds_map, &cpos)) { // dup() the fd to a new number; the old one will be closed // in the following dup2() if ((fds2[1 + cpos] = dup(fds2[1 + cpos])) < 0) { abort(); } } if (*fds2 != *params.fds_map) { // dup fd if (dup2(*fds2, *params.fds_map) < 0) { abort(); } // close original fd close(*fds2); } fds2++; params.fds_map++; } // make sure standard streams are open open_standard_streams(); // make session leader if requested if (params.do_setsid) { setsid(); } // assume identity of username, if requested if (params.username) { long bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); if (bufsize < 0) { bufsize = 16384; } char *buf = malloc(bufsize); if (!buf) { abort(); } struct passwd pwd; struct passwd *res; getpwnam_r(params.username, &pwd, buf, bufsize, &res); if (!res) { abort(); } if (initgroups(params.username, pwd.pw_gid) < 0) { abort(); } if (setgid(pwd.pw_gid) < 0) { abort(); } if (setuid(pwd.pw_uid) < 0) { abort(); } } execv(file, argv); abort(); } // restore original signal mask ASSERT_FORCE(sigprocmask(SIG_SETMASK, &sset_old, NULL) == 0) if (pid < 0) { BLog(BLOG_ERROR, "fork failed"); goto fail0; } // remember pid o->pid = pid; // add to processes list LinkedList2_Append(&o->m->processes, &o->list_node); DebugObject_Init(&o->d_obj); DebugError_Init(&o->d_err, BReactor_PendingGroup(m->reactor)); return 1; fail0: return 0; }
static void client_handler_error (void *user) { BLog(BLOG_ERROR, "client error"); BReactor_Quit(&reactor, 1); }
void send_handler_done (BSocksClient *o) { DebugObject_Access(&o->d_obj); ASSERT(o->buffer) switch (o->state) { case STATE_SENDING_HELLO: { BLog(BLOG_DEBUG, "sent hello"); // allocate buffer for receiving hello bsize_t size = bsize_fromsize(sizeof(struct socks_server_hello)); if (!reserve_buffer(o, size)) { goto fail; } // receive hello start_receive(o, (uint8_t *)o->buffer, size.value); // set state o->state = STATE_SENT_HELLO; } break; case STATE_SENDING_REQUEST: { BLog(BLOG_DEBUG, "sent request"); // allocate buffer for receiving reply bsize_t size = bsize_add( bsize_fromsize(sizeof(struct socks_reply_header)), bsize_max(bsize_fromsize(sizeof(struct socks_addr_ipv4)), bsize_fromsize(sizeof(struct socks_addr_ipv6))) ); if (!reserve_buffer(o, size)) { goto fail; } // receive reply header start_receive(o, (uint8_t *)o->buffer, sizeof(struct socks_reply_header)); // set state o->state = STATE_SENT_REQUEST; } break; case STATE_SENDING_PASSWORD: { BLog(BLOG_DEBUG, "send password"); // allocate buffer for receiving reply bsize_t size = bsize_fromsize(2); if (!reserve_buffer(o, size)) { goto fail; } // receive reply header start_receive(o, (uint8_t *)o->buffer, size.value); // set state o->state = STATE_SENT_PASSWORD; } break; default: ASSERT(0); } return; fail: report_error(o, BSOCKSCLIENT_EVENT_ERROR); }
void recv_handler_done (BSocksClient *o, int data_len) { ASSERT(data_len >= 0) ASSERT(data_len <= o->control.recv_total - o->control.recv_len) DebugObject_Access(&o->d_obj); o->control.recv_len += data_len; if (o->control.recv_len < o->control.recv_total) { do_receive(o); return; } switch (o->state) { case STATE_SENT_HELLO: { BLog(BLOG_DEBUG, "received hello"); struct socks_server_hello imsg; memcpy(&imsg, o->buffer, sizeof(imsg)); if (ntoh8(imsg.ver) != SOCKS_VERSION) { BLog(BLOG_NOTICE, "wrong version"); goto fail; } size_t auth_index; for (auth_index = 0; auth_index < o->num_auth_info; auth_index++) { if (o->auth_info[auth_index].auth_type == ntoh8(imsg.method)) { break; } } if (auth_index == o->num_auth_info) { BLog(BLOG_NOTICE, "server didn't accept any authentication method"); goto fail; } const struct BSocksClient_auth_info *ai = &o->auth_info[auth_index]; switch (ai->auth_type) { case SOCKS_METHOD_NO_AUTHENTICATION_REQUIRED: { BLog(BLOG_DEBUG, "no authentication"); auth_finished(o); } break; case SOCKS_METHOD_USERNAME_PASSWORD: { BLog(BLOG_DEBUG, "password authentication"); if (ai->password.username_len == 0 || ai->password.username_len > 255 || ai->password.password_len == 0 || ai->password.password_len > 255 ) { BLog(BLOG_NOTICE, "invalid username/password length"); goto fail; } // allocate password packet bsize_t size = bsize_fromsize(1 + 1 + ai->password.username_len + 1 + ai->password.password_len); if (!reserve_buffer(o, size)) { goto fail; } // write password packet char *ptr = o->buffer; *ptr++ = 1; *ptr++ = ai->password.username_len; memcpy(ptr, ai->password.username, ai->password.username_len); ptr += ai->password.username_len; *ptr++ = ai->password.password_len; memcpy(ptr, ai->password.password, ai->password.password_len); ptr += ai->password.password_len; // start sending PacketPassInterface_Sender_Send(o->control.send_if, (uint8_t *)o->buffer, size.value); // set state o->state = STATE_SENDING_PASSWORD; } break; default: ASSERT(0); } } break; case STATE_SENT_REQUEST: { BLog(BLOG_DEBUG, "received reply header"); struct socks_reply_header imsg; memcpy(&imsg, o->buffer, sizeof(imsg)); if (ntoh8(imsg.ver) != SOCKS_VERSION) { BLog(BLOG_NOTICE, "wrong version"); goto fail; } if (ntoh8(imsg.rep) != SOCKS_REP_SUCCEEDED) { BLog(BLOG_NOTICE, "reply not successful"); goto fail; } int addr_len; switch (ntoh8(imsg.atyp)) { case SOCKS_ATYP_IPV4: addr_len = sizeof(struct socks_addr_ipv4); break; case SOCKS_ATYP_IPV6: addr_len = sizeof(struct socks_addr_ipv6); break; default: BLog(BLOG_NOTICE, "reply has unknown address type"); goto fail; } // receive the rest of the reply start_receive(o, (uint8_t *)o->buffer + sizeof(imsg), addr_len); // set state o->state = STATE_RECEIVED_REPLY_HEADER; } break; case STATE_SENT_PASSWORD: { BLog(BLOG_DEBUG, "received password reply"); if (o->buffer[0] != 1) { BLog(BLOG_NOTICE, "password reply has unknown version"); goto fail; } if (o->buffer[1] != 0) { BLog(BLOG_NOTICE, "password reply is negative"); goto fail; } auth_finished(o); } break; case STATE_RECEIVED_REPLY_HEADER: { BLog(BLOG_DEBUG, "received reply rest"); // free buffer BFree(o->buffer); o->buffer = NULL; // free control I/O free_control_io(o); // init up I/O init_up_io(o); // set state o->state = STATE_UP; // call handler o->handler(o->user, BSOCKSCLIENT_EVENT_UP); return; } break; default: ASSERT(0); } return; fail: report_error(o, BSOCKSCLIENT_EVENT_ERROR); }
void connector_handler (BSocksClient* o, int is_error) { DebugObject_Access(&o->d_obj); ASSERT(o->state == STATE_CONNECTING) // check connection result if (is_error) { // PSIPHON // BLog(BLOG_ERROR, "connection failed"); BLog(BLOG_WARNING, "connection failed"); goto fail0; } // init connection if (!BConnection_Init(&o->con, BConnection_source_connector(&o->connector), o->reactor, o, (BConnection_handler)connection_handler)) { BLog(BLOG_ERROR, "BConnection_Init failed"); goto fail0; } BLog(BLOG_DEBUG, "connected"); // init control I/O init_control_io(o); // check number of methods if (o->num_auth_info == 0 || o->num_auth_info > 255) { BLog(BLOG_ERROR, "invalid number of authentication methods"); goto fail1; } // allocate buffer for sending hello bsize_t size = bsize_add( bsize_fromsize(sizeof(struct socks_client_hello_header)), bsize_mul( bsize_fromsize(o->num_auth_info), bsize_fromsize(sizeof(struct socks_client_hello_method)) ) ); if (!reserve_buffer(o, size)) { goto fail1; } // write hello header struct socks_client_hello_header header; header.ver = hton8(SOCKS_VERSION); header.nmethods = hton8(o->num_auth_info); memcpy(o->buffer, &header, sizeof(header)); // write hello methods for (size_t i = 0; i < o->num_auth_info; i++) { struct socks_client_hello_method method; method.method = hton8(o->auth_info[i].auth_type); memcpy(o->buffer + sizeof(header) + i * sizeof(method), &method, sizeof(method)); } // send PacketPassInterface_Sender_Send(o->control.send_if, (uint8_t *)o->buffer, size.value); // set state o->state = STATE_SENDING_HELLO; return; fail1: free_control_io(o); BConnection_Free(&o->con); fail0: report_error(o, BSOCKSCLIENT_EVENT_ERROR); return; }