int red_recv_udp_pkt(int fd, char *buf, size_t buflen, struct sockaddr_in *inaddr, struct sockaddr_in *toaddr) { socklen_t addrlen = sizeof(*inaddr); ssize_t pktlen; struct msghdr msg; struct iovec io; char control[1024]; memset(&msg, 0, sizeof(msg)); msg.msg_name = inaddr; msg.msg_namelen = sizeof(*inaddr); msg.msg_iov = &io; msg.msg_iovlen = 1; msg.msg_control = control; msg.msg_controllen = sizeof(control); io.iov_base = buf; io.iov_len = buflen; pktlen = recvmsg(fd, &msg, 0); if (pktlen == -1) { log_errno(LOG_WARNING, "recvfrom"); return -1; } if (toaddr) { memset(toaddr, 0, sizeof(*toaddr)); for (struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { if ( cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_ORIGDSTADDR && cmsg->cmsg_len >= CMSG_LEN(sizeof(*toaddr)) ) { struct sockaddr_in* cmsgaddr = (struct sockaddr_in*)CMSG_DATA(cmsg); memcpy(toaddr, cmsgaddr, sizeof(*toaddr)); } else { log_error(LOG_WARNING, "unexepcted cmsg (level,type) = (%d,%d)", cmsg->cmsg_level, cmsg->cmsg_type); } } if (toaddr->sin_family != AF_INET) { log_error(LOG_WARNING, "(SOL_IP, IP_ORIGDSTADDR) not found"); return -1; } } if (addrlen != sizeof(*inaddr)) { log_error(LOG_WARNING, "unexpected address length %u instead of %zu", addrlen, sizeof(*inaddr)); return -1; } if (pktlen >= buflen) { char buf[RED_INET_ADDRSTRLEN]; log_error(LOG_WARNING, "wow! Truncated udp packet of size %zd from %s! impossible! dropping it...", pktlen, red_inet_ntop(inaddr, buf, sizeof(buf))); return -1; } return pktlen; }
static int ss_instance_init(struct redudp_instance_t *instance) { ss_instance * ss = (ss_instance *)(instance+1); const redudp_config *config = &instance->config; char buf1[RED_INET_ADDRSTRLEN]; int valid_cred = ss_is_valid_cred(config->login, config->password); if (!valid_cred || (ss->method = enc_init(&ss->info, config->password, config->login), ss->method == -1)) { log_error(LOG_ERR, "Invalided encrytion method or password."); return -1; } else { log_error(LOG_INFO, "%s @ %s: encryption method: %s", instance->relay_ss->name, red_inet_ntop(&instance->config.bindaddr, buf1, sizeof(buf1)), config->login); } // An additional buffer is allocated for each instance for encryption/decrption. ss->buff = malloc(MAX_UDP_PACKET_SIZE); if (!ss->buff) { log_error(LOG_ERR, "Out of memory."); return -1; } return 0; }