#include #include #include #include #include #include #include #include #include #include #include int main(int argc, char **argv) { int ret; if (argc < 2) { fprintf(stderr, "Usage: csumtest \n"); exit(1); } struct sockaddr_in addr; socklen_t addrLen = sizeof(addr); addr.sin_family = AF_INET; addr.sin_addr.s_addr = inet_addr("127.0.0.1"); addr.sin_port = htons(0); int listen = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (listen < 0) { fprintf(stderr, "failed to create listening socket (err=%d: %s)\n", errno, strerror(errno)); exit(1); } ret = bind(listen, (struct sockaddr *) &addr, addrLen); if (ret != 0) { fprintf(stderr, "failed to bind listening socket socket (err=%d: %s)\n", errno, strerror(errno)); exit(1); } ret = getsockname(listen, (struct sockaddr *) &addr, &addrLen); if (ret != 0) { fprintf(stderr, "getsockname failed for listening socket socket (err=%d: %s)\n", errno, strerror(errno)); exit(1); } else { printf("listening on port %d\n", ntohs(addr.sin_port)); } // Send a packet with deliberately bad checksum char rawBuf[4096]; memset(rawBuf, 0, 4096); struct udphdr *udph = (struct udphdr *) rawBuf; // Send as UDP data the string "BAD DATA", repeated as necessary // to fill the number of bytes requested on the command-line char *data = rawBuf + sizeof(struct udphdr); int badBytes = atoi(argv[1]); int i; for (i = 0; i < badBytes; i += 8) { strncpy(data + i, "BAD DATA", 8); } // UDP headers contain a bogus checksum, but are otherwise reasonable udph->check = htons(0xbadd); udph->source = htons(18); udph->dest = addr.sin_port; udph->len = htons(sizeof(struct udphdr) + badBytes); int raw = socket(AF_INET, SOCK_RAW, IPPROTO_UDP); ret = sendto(raw, rawBuf, sizeof(struct udphdr) + badBytes, 0, (struct sockaddr *) &addr, addrLen); if (ret < 0) { fprintf(stderr, "raw send failed (err=%d: %s)\n", errno, strerror(errno)); exit(1); } // Send a second, legitimate UDP packet int cooked = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); char *second = "Good data"; ret = sendto(cooked, second, strlen(second), 0, (struct sockaddr *) &addr, addrLen); if (ret < 0) { fprintf(stderr, "second cooked send failed (err=%d: %s)\n", errno, strerror(errno)); exit(1); } // Read what's queued up for us. while (1) { struct msghdr msg; struct iovec iov; char readBuf[4096]; ssize_t bytes; memset(readBuf, 0, 4096); iov.iov_base = readBuf; iov.iov_len = sizeof(readBuf); msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = NULL; msg.msg_controllen = 0; msg.msg_flags = 0; bytes = recvmsg(listen, &msg, 0); if (bytes < 0) { fprintf(stderr, "getsockname failed for listening socket socket (err=%d: %s)\n", errno, strerror(errno)); exit(1); } printf("recvmsg returned %ld bytes: %s\n", bytes, readBuf); if (bytes == 9) break; } }