Пример #1
0
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;
}
Пример #2
0
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;
}
Пример #3
0
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;
}
Пример #4
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;
    }
}
Пример #5
0
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;
}
Пример #6
0
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;
}
Пример #7
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;
    }
}
Пример #8
0
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;
}
Пример #9
0
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;
}
Пример #10
0
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;
    }
}
Пример #11
0
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;
}
Пример #12
0
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;
}
Пример #13
0
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++;
}
Пример #14
0
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);
    }
}
Пример #15
0
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);
}
Пример #16
0
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;
}
Пример #17
0
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;
}
Пример #18
0
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);
}
Пример #19
0
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;
}
Пример #20
0
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;
}
Пример #21
0
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;
    }
}
Пример #22
0
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;
}
Пример #23
0
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;
}
Пример #24
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);
    }
}
Пример #25
0
static int run_command (const char *cmd)
{
    BLog(BLOG_INFO, "run: %s", cmd);
    
    return system(cmd);
}
Пример #26
0
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;
}
Пример #27
0
static void client_handler_error (void *user)
{
    BLog(BLOG_ERROR, "client error");

    BReactor_Quit(&reactor, 1);
}
Пример #28
0
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);
}
Пример #29
0
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);
}
Пример #30
0
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;
}