static void ss_forward_pkt(redudp_client *client, struct sockaddr * destaddr, void *data, size_t pktlen) { ss_client *ssclient = (void*)(client + 1); ss_instance * ss = (ss_instance *)(client->instance+1); struct sockaddr_in * relayaddr = &client->instance->config.relayaddr; struct msghdr msg; struct iovec io[1]; ssize_t outgoing; int rc; ss_header_ipv4 header; size_t len = 0; size_t fwdlen = 0; void * buff = client->instance->shared_buff; /* build and send header */ // TODO: Better implementation and IPv6 Support header.addr_type = ss_addrtype_ipv4; header.addr = ((struct sockaddr_in *)destaddr)->sin_addr.s_addr; header.port = ((struct sockaddr_in *)destaddr)->sin_port; if (enc_ctx_init(&ss->info, &ss->e_ctx, 1)) { redudp_log_error(client, LOG_ERR, "Shadowsocks UDP failed to initialize encryption context."); return; } rc = ss_encrypt(&ss->e_ctx, (char *)&header, sizeof(header), buff, &len); if (rc) { if (len + pktlen < MAX_UDP_PACKET_SIZE) rc = ss_encrypt(&ss->e_ctx, (char *)data, pktlen, buff+len, &fwdlen); else rc = 0; } enc_ctx_free(&ss->e_ctx); if (!rc) { redudp_log_error(client, LOG_DEBUG, "Can't encrypt packet, dropping it"); return; } fwdlen += len; memset(&msg, 0, sizeof(msg)); msg.msg_name = relayaddr; msg.msg_namelen = sizeof(*relayaddr); msg.msg_iov = io; msg.msg_iovlen = SIZEOF_ARRAY(io); io[0].iov_base = buff; io[0].iov_len = fwdlen; outgoing = sendmsg(event_get_fd(&ssclient->udprelay), &msg, 0); if (outgoing == -1) { redudp_log_errno(client, LOG_DEBUG, "sendmsg: Can't forward packet, dropping it"); return; } else if (outgoing != fwdlen) { redudp_log_error(client, LOG_DEBUG, "sendmsg: I was sending %zd bytes, but only %zd were sent.", fwdlen, outgoing); return; } }
static void ss_pkt_from_server(int fd, short what, void *_arg) { redudp_client *client = _arg; ss_client *ssclient = (void*)(client + 1); ss_instance * ss = (ss_instance *)(client->instance+1); ss_header_ipv4 * header; ssize_t pktlen; size_t fwdlen; struct sockaddr_in udprelayaddr; int rc; void * buff = client->instance->shared_buff; void * buff2 = ss->buff; assert(fd == event_get_fd(&ssclient->udprelay)); pktlen = red_recv_udp_pkt(fd, buff, MAX_UDP_PACKET_SIZE, &udprelayaddr, NULL); if (pktlen == -1) return; if (enc_ctx_init(&ss->info, &ss->d_ctx, 0)) { redudp_log_error(client, LOG_ERR, "Shadowsocks UDP failed to initialize decryption context."); return; } rc = ss_decrypt(&ss->d_ctx, buff, pktlen, buff2, &fwdlen); enc_ctx_free(&ss->d_ctx); if (!rc) { redudp_log_error(client, LOG_DEBUG, "Can't decrypt packet, dropping it"); return; } header = (ss_header_ipv4 *)buff2; // We do not verify src address, but at least, we need to ensure address type is correct. if (header->addr_type != ss_addrtype_ipv4) { redudp_log_error(client, LOG_DEBUG, "Got address type #%u instead of expected #%u (IPv4).", header->addr_type, ss_addrtype_ipv4); return; } struct sockaddr_in pktaddr = { .sin_family = AF_INET, .sin_addr = { header->addr }, .sin_port = header->port, }; if (fwdlen < sizeof(*header)) { redudp_log_error(client, LOG_DEBUG, "Packet too short."); return; } fwdlen -= sizeof(*header); redudp_fwd_pkt_to_sender(client, buff2 + sizeof(*header), fwdlen, &pktaddr); }
static void ss_client_fini(redsocks_client *client) { ss_client *sclient = (void*)(client + 1); enc_ctx_free(&sclient->e_ctx); enc_ctx_free(&sclient->d_ctx); }