Skip to content

Instantly share code, notes, and snippets.

Created April 13, 2014 12:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/10581479 to your computer and use it in GitHub Desktop.
Save anonymous/10581479 to your computer and use it in GitHub Desktop.
/*
* 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