#ifdef NDEBUG # undef NDEBUG #endif #include #include #include #include #include #include #include #include #include #define LOG(fmt, ...) fprintf(stderr, "[%jd] " __FILE__ ": " fmt "\n", \ (intmax_t)getpid(), __VA_ARGS__) struct mxc_hello { uint8_t hdr; uint8_t src; uint16_t dst; }; struct mxc_sess { uint8_t secret; uint32_t key; struct mxc_hello self_hello[1]; struct mxc_hello peer_hello[1]; }; static int mxc_socket(int argc, char * const *argv) { static const int reuseaddr = 1; const char *progname; struct sockaddr_in sin; uint16_t port; int fd; progname = *argv; argc--; argv++; assert(argc == 1); port = (uint16_t)atoi(*argv); fd = socket(PF_INET, SOCK_STREAM, 0); assert(fd != -1); assert(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof reuseaddr) == 0); (void)memset(&sin, 0, sizeof sin); sin.sin_family = AF_INET; sin.sin_port = htons(port); if (strstr(progname, "client")) { assert(connect(fd, (void *)&sin, sizeof sin) == 0); } else if (strstr(progname, "server")) { assert(bind(fd, (void *)&sin, sizeof sin) == 0); assert(listen(fd, 1) == 0); } else { LOG("unknown program: %s", progname); } return (fd); } static uint16_t mxc_port(int fd) { struct sockaddr_in sin; struct sockaddr *sa; socklen_t sl; sa = (void *)&sin; sl = sizeof sin; (void)memset(&sin, 0, sl); assert(getsockname(fd, sa, &sl) == 0); assert(sa->sa_family = AF_INET); return (ntohs(sin.sin_port)); } static void mxc_sess_init(struct mxc_sess *sess) { assert(sess != NULL); (void)memset(sess, 0, sizeof *sess); sess->secret = (uint8_t)random(); } static void mxc_sess_key(struct mxc_sess *sess) { assert(sess != NULL); assert(sess->self_hello->hdr != '\0'); assert(sess->peer_hello->hdr != '\0'); sess->key = sess->peer_hello->dst * sess->secret; } static void mxc_sess_crypt(struct mxc_sess *sess, uint8_t *buf, size_t len) { assert(sess != NULL); assert(sess->self_hello->hdr != '\0'); assert(sess->peer_hello->hdr != '\0'); assert(buf != NULL); assert(len > 0); while (len > 0) { #ifndef MXC_CLEAR *buf ^= (uint8_t)sess->key; #endif buf++; len--; } } static void mxc_sess_send(struct mxc_sess *sess, int fd, uint8_t *buf, size_t len) { ssize_t wr; assert(sess != NULL); if (len > 0) { mxc_sess_crypt(sess, buf, len); wr = write(fd, buf, len); assert(wr == len); } } static ssize_t mxc_sess_recv(struct mxc_sess *sess, int fd, uint8_t *buf, size_t len) { ssize_t rd; assert(sess != NULL); rd = read(fd, buf, len); assert(rd >= 0); if (rd > 0) mxc_sess_crypt(sess, buf, rd); return (rd); } static void mxc_hello_client(struct mxc_sess *sess) { assert(sess != NULL); assert(sess->self_hello->hdr == '\0'); assert(sess->peer_hello->hdr == '\0'); sess->self_hello->hdr = 'C'; sess->self_hello->src = (uint8_t)random(); sess->self_hello->dst = sess->self_hello->src * sess->secret; } static void mxc_hello_server(struct mxc_sess *sess) { assert(sess != NULL); assert(sess->self_hello->hdr == '\0'); assert(sess->peer_hello->hdr == 'C'); sess->self_hello->hdr = 'S'; sess->self_hello->src = sess->peer_hello->src; sess->self_hello->dst = sess->self_hello->src * sess->secret; mxc_sess_key(sess); } static void mxc_hello_send(struct mxc_sess *sess, int fd) { ssize_t wr; assert(sess != NULL); assert(sess->self_hello->hdr != '\0'); wr = write(fd, sess->self_hello, sizeof sess->self_hello); assert(wr == sizeof sess->self_hello); } static void mxc_hello_recv(struct mxc_sess *sess, int fd) { ssize_t rd; assert(sess != NULL); assert(sess->peer_hello->hdr == '\0'); rd = read(fd, sess->peer_hello, sizeof sess->peer_hello); assert(rd == sizeof sess->peer_hello); }