#include #include #include #include #include #include #include #include #include #include #include #include #include #include "sockfromto.h" int listenudp(char *service, int family, char *bindaddr); void usage(void); int main(int argc, char *argv[]); int listenudp(service, family, bindaddr) char *service; int family; char *bindaddr; { int s; struct addrinfo hints; struct addrinfo *res; int rc, on; s = socket(family, SOCK_DGRAM, 0); on = 1; setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); memset(&hints, 0, sizeof(hints)); hints.ai_family = family; hints.ai_flags = AI_PASSIVE; hints.ai_socktype = SOCK_DGRAM; rc = getaddrinfo(bindaddr, service, &hints, &res); if (rc) { errx(1, "getaddrinfo: %s: %s", service, gai_strerror(rc)); exit(1); } rc = bind(s, (struct sockaddr *)res->ai_addr, res->ai_addrlen); if (rc < 0) { shutdown(s, 2); close(s); err(1, "bind"); } return s; } void usage() { printf("usage: listen [opt] listen-port\n"); printf(" -4 Use IPv4 only\n"); printf(" -6 Use IPv6 only\n"); exit(0); } int opt_4; int opt_6; int main(argc, argv) int argc; char *argv[]; { int ch; int socket4, socket6, client; char *portp; while ((ch = getopt(argc, argv, "46")) != -1) { switch (ch) { case '4': opt_4 = 1; break; case '6': opt_6 = 1; break; case '?': default: usage(); } } argc -= optind; argv += optind; if (argc != 1) usage(); portp = argv[0]; if (!(opt_4 || opt_6)) opt_4 = opt_6 = 1; socket4 = socket6 = 0; if (opt_4) { socket4 = listenudp(portp, AF_INET, NULL); printf("starting UDP: listening port %s\n", portp); } if (opt_6) { socket6 = listenudp(portp, AF_INET6, NULL); printf("starting UDP6: listening port %s\n", portp); } if (setsockoptfromto(socket4) < 0) err(1, "setsockopt"); if (setsockoptfromto(socket6) < 0) err(1, "setsockopt"); while (1) { int nfds, nfound; fd_set readfds; #define max(a, b) (((a) > (b)) ? (a) : (b)) nfds = max(socket4, socket6) + 1; for (;;) { FD_ZERO(&readfds); if (opt_4) FD_SET(socket4, &readfds); if (opt_6) FD_SET(socket6, &readfds); nfound = select(nfds, &readfds, NULL, NULL, NULL); if (nfound < 0) err(1, "select: "); if (FD_ISSET(socket4, &readfds)) { client = socket4; break; } if (FD_ISSET(socket6, &readfds)) { client = socket6; break; } } { char buf[1024]; struct sockaddr_storage remote; struct sockaddr_storage local; socklen_t remote_len = sizeof(remote); socklen_t local_len = sizeof(local); int rc; memset(&remote, 0, sizeof(remote)); memset(&local, 0, sizeof(local)); if (1) { rc = recvfromto(client, (void*)buf, sizeof(buf), 0, (struct sockaddr *)&remote, &remote_len, (struct sockaddr *)&local, &local_len); if (rc > 0) buf[rc] = '\0'; printf("recvfromto: %d bytes received (\"%s\")\n", rc, buf); printf(" : from %s\n", remote_len ? strsockaddr((struct sockaddr *)&remote) : "unknown"); printf(" : to %s\n", local_len ? strsockaddr((struct sockaddr *)&local) : "unknown"); if (rc > 0) { rc = sendfromto(client, buf, rc, 0, (struct sockaddr *)&local, (struct sockaddr *)&remote); if (rc < 0) err(1, "sendfromto: "); } } } } return 0; }