Created
April 13, 2014 12:15
-
-
Save anonymous/10581479 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Scl - The Stupid Content Listener: | |
* | |
* Compile: | |
* gcc -Wall -Wextra -O2 scl.c -o scl | |
* | |
* Run: | |
* SCL_IP_MODE="<mode>" ./scl | |
* where <mode> is either "4", "6" or "46" for IPv4, IPv6 or dual mode IPv6. | |
* If SCL_IP_MODE is not set, it defaults to "46". | |
* | |
* Drive: | |
* Use netcat to send stupidites to the program, for example: | |
* printf "123456\n" | nc.openbsd ::1 8086 | |
* printf "123456" | nc.openbsd 127.0.0.1 8086 | |
* printf "123456\0" | nc.openbsd 127.0.0.1 8086 | |
*/ | |
#include <stdio.h> | |
#include <string.h> | |
#include <stdlib.h> | |
#include <netdb.h> | |
#include <errno.h> | |
#include <unistd.h> | |
#include <stdarg.h> | |
#include <sys/types.h> | |
#include <sys/socket.h> | |
#include <netinet/in.h> | |
static void die(char* msg) { | |
fprintf(stderr, "%s: %s\n", msg, strerror(errno)); | |
exit(1); | |
} | |
static int isModeEnvSane(char* modeEnv) { | |
return strstr(modeEnv, "4") != NULL || strstr(modeEnv, "6") != NULL; | |
} | |
static char* assertModeEnvSane(char* modeEnv) { | |
if(!isModeEnvSane(modeEnv)) { | |
fprintf(stderr, "SCL_IP_MODE should be set to '4', '6' or '46' only.\n"); | |
exit(1); | |
} | |
return modeEnv; | |
} | |
static char* getModeEnv() { | |
char* ret = getenv("SCL_IP_MODE"); | |
if(ret == NULL) | |
ret = "46"; | |
return assertModeEnvSane(ret); | |
} | |
static int useIpv4() { | |
return strstr(getModeEnv(), "4") != NULL; | |
} | |
static int useIpv6() { | |
return strstr(getModeEnv(), "6") != NULL; | |
} | |
static int useIpv6Only() { | |
return useIpv6() && !useIpv4(); | |
} | |
static int useIpv4Only() { | |
return useIpv4() && !useIpv6(); | |
} | |
static int getSocketDomain() { | |
if(useIpv4Only()) | |
return AF_INET; | |
return AF_INET6; | |
} | |
static struct sockaddr_storage createServerAddr() { | |
struct sockaddr_storage ret; | |
memset(&ret, 0, sizeof(ret)); | |
if(useIpv4Only()) { | |
struct sockaddr_in* ret4 = (struct sockaddr_in*) &ret; | |
ret4->sin_family = getSocketDomain(); | |
ret4->sin_port = htons(8086); | |
ret4->sin_addr.s_addr = INADDR_ANY; | |
} else { | |
struct sockaddr_in6* ret6 = (struct sockaddr_in6*) &ret; | |
ret6->sin6_family = getSocketDomain(); | |
ret6->sin6_port = htons(8086); | |
ret6->sin6_addr = in6addr_any; | |
} | |
return ret; | |
} | |
static void configureSocket(int sock) { | |
const int cfgYes = 1; | |
const int cfgNo = 0; | |
if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &cfgYes, sizeof(cfgYes)) < 0) | |
die("Error setting SO_REUSEADDR"); | |
if(useIpv6()) { | |
const int* ipv6Only = (useIpv6Only() ? &cfgYes : &cfgNo); | |
if(setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, ipv6Only, sizeof(*ipv6Only)) < 0) | |
die("Error setting IPV6_V6ONLY"); | |
} | |
} | |
static int createSocket() { | |
int ret = socket(getSocketDomain(), SOCK_STREAM, 0); | |
if(ret < 0) | |
die("Error creating socket"); | |
configureSocket(ret); | |
return ret; | |
} | |
static int createAndBindSocket(struct sockaddr_storage* serverAddr) { | |
int sockDesc = createSocket(); | |
if(bind(sockDesc, (struct sockaddr*) serverAddr, sizeof(*serverAddr)) < 0) | |
die("Error binding socket"); | |
return sockDesc; | |
} | |
static int readLine(char* buf, ssize_t off, size_t len) { | |
char *p; | |
buf[len] = 0; | |
p = strstr(buf + off, "\n"); | |
if(p != NULL) { | |
*p = 0; | |
return 1; | |
} | |
return 0; | |
} | |
static int contains(char c, char* buf, ssize_t off, size_t len) { | |
size_t i; | |
for(i = off; i < len; ++i) { | |
if(buf[i] == c) | |
return 1; | |
} | |
return 0; | |
} | |
static int containsNull(char* buf, ssize_t off, size_t len) { | |
return contains('\0', buf, off, len); | |
} | |
static int handleConnection(int sock) { | |
const ssize_t BUF_SIZE = 8; | |
char buf[BUF_SIZE + 1]; | |
int lineRead = 0; | |
int nullFound = 0; | |
ssize_t i = 0; | |
while(i < BUF_SIZE) { | |
ssize_t n = read(sock, buf + i, BUF_SIZE - i); | |
ssize_t tmp = i; | |
if(n < 0) | |
die("Error reading from socket"); | |
i += n; | |
if(n == 0 || (nullFound = containsNull(buf, tmp, i)) || (lineRead = readLine(buf, tmp, i))) | |
break; | |
} | |
if(nullFound) | |
printf("Ignoring illegal input containing NULL character.\n"); | |
else if(i == 0) | |
printf("Received EOF\n"); | |
else if(lineRead) | |
printf("Received line: %s\n", buf); | |
else if(i == BUF_SIZE) | |
printf("Received maximum number of bytes: %s\n", buf); | |
else | |
printf("Received: %s\n", buf); | |
return strncmp("end", buf, 3) == 0; | |
} | |
int main() { | |
struct sockaddr_storage serverAddr = createServerAddr(); | |
int listenSocket = createAndBindSocket(&serverAddr); | |
listen(listenSocket, 50); | |
printf("StupidContentListener is ready and waiting for stupdities...\n"); | |
while(1) { | |
int connSocket = accept(listenSocket, NULL, NULL); | |
int endLoop; | |
if(connSocket < 0) | |
die("Error accepting connection"); | |
endLoop = handleConnection(connSocket); | |
if(close(connSocket) < 0) | |
die("Error closing socket"); | |
if(endLoop) | |
break; | |
} | |
close(listenSocket); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment