The expanses of WolfWings' land
scratched on the wall for all to see


April 15th, 2008
April 15th, 2008
April 15th, 2008
April 15th, 2008
April 15th, 2008

[User Picture]12:18 pm - Well I'm making progress on a stand-alone 'ad blocking' DNS/Web server-combo.
I have a non-forking, select-based and mostly-1.0-complient HTTP server that uses almost no memory, is only about a hundred lines of code, and works with all the web-browsers I've thrown at it nicely. It cheats horribly since it's specifically meant to be used to hijack arbitrary HTTP servers by using DNS to point back at your local machine, so it utterly ignores all incoming bytes until it gets the 'blank line' sequence indicating the client isn't sending any more headers. Then it sends back a fixed 83-byte buffer, closes the socket, and goes back to listening for more connections.

Now, to make it handle DNS requests as well, and in effect filter them... that will be harder, but it's about time I learned stuff like file-modification monitoring and the like. Long-term? I'd love to port this stuff to Windows as a Service, but that would require all KINDS of junk I'd rather not consider just yet.

If anyone wants to see the code so far,
#define PORT 8080

char message[] =
{'H','T','T','P','/','1','.','0',' ','2','0','0',' ','O','K','\n',
 'C','o','n','t','e','n','t','-','T','y','p','e',':',' ','i','m',
 'a','g','e','/','g','i','f','\n','\n','G','I','F','8','9','a',
   1,  0,  1,  0,128,  0,  0,  0,  0,  0,255,255,255, 33,249,  4,
   1,  0,  0,  1,  0, 44,  0,  0,  0,  0,  1,  0,  1,  0,  0,  2,
   1, 76,  0, 59 };

char localhost[] = {127,0,0,1};

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>

#include <netinet/in.h>
#include <arpa/inet.h>

int main(void) {
    fd_set          master;	// master file descriptor list
    fd_set          read_fds;	// temp file descriptor list for select()
    fd_set          stage1;	// +1 when set for a fd
    fd_set          stage2;	// +2 when set for a fd
    struct sockaddr_in myaddr;	// server address
    struct sockaddr_in remoteaddr;	// client address
    int             fdmax;	// maximum file descriptor number
    int             listener;	// listening socket descriptor
    int             newfd;	// newly accept()ed socket descriptor
    char            buffer;	// buffer for client data
    int             nbytes;
    int             yes = 1;	// for setsockopt() SO_REUSEADDR, below
    socklen_t       addrlen;
    int             i,
                    j;

    FD_ZERO(&master);		// clear the master and temp sets
    FD_ZERO(&read_fds);
    FD_ZERO(&stage1);
    FD_ZERO(&stage2);

    // get the listener
    if ((listener = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
	exit(1);
    }
    // lose the pesky "address already in use" error message
    if (setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int))
	== -1) {
	exit(1);
    }
    // bind
    myaddr.sin_family = AF_INET;
    myaddr.sin_addr.s_addr = (*(in_addr_t *)(void *)localhost);
    myaddr.sin_port = htons(PORT);
    memset(myaddr.sin_zero, '\0', sizeof myaddr.sin_zero);
    if (bind(listener, (struct sockaddr *) &myaddr, sizeof myaddr) == -1) {
	exit(1);
    }
    // listen
    if (listen(listener, 10) == -1) {
	exit(1);
    }
    // add the listener to the master set
    FD_SET(listener, &master);

    // keep track of the biggest file descriptor
    fdmax = listener;		// so far, it's this one

    // main loop
    for (;;) {
	read_fds = master;	// copy it
	if (select(fdmax + 1, &read_fds, NULL, NULL, NULL) == -1) {
	    exit(1);
	}
	// run through the existing connections looking for data to read
	for (i = 0; i <= fdmax; i++) {
	    if (FD_ISSET(i, &read_fds)) {	// we got one!!
		if (i == listener) {
		    // handle new connections
		    addrlen = sizeof remoteaddr;
		    if ((newfd =
			 accept(listener, (struct sockaddr *) &remoteaddr,
				&addrlen)) == -1) {
		    } else {
			FD_SET(newfd, &master);	// add to master set
			if (newfd > fdmax) {	// keep track of the
						// maximum
			    fdmax = newfd;
			}
		    }
		} else {
		    // handle data from a client
		    if ((nbytes = recv(i, &buffer, 1, 0)) <= 0) {
			close(i);	// bye!
			FD_CLR(i, &master);	// remove from master set
		    } else {
			j = 0;
			if (FD_ISSET(i, &stage1)) {
			    j = 1;
			}
			if (FD_ISSET(i, &stage2)) {
			    j += 2;
			}
			switch (buffer) {
			case '\r':
			    if (j == 2) {
				FD_SET(i, &stage1);
				continue;
			    }
			    if (j & 2)
				FD_CLR(i, &stage2);
			    if (!(j & 1))
				FD_SET(i, &stage1);
			    continue;
			case '\n':
			    if (j == 3) {
				// Send the canned response, and GTFO!
				send(i, message, sizeof message, 0);
				close(i);	// bye!
				FD_CLR(i, &master);	// remove from
							// master set
				FD_CLR(i, &stage1);
				FD_CLR(i, &stage2);
				continue;
			    }
			    if (j == 1) {
				FD_CLR(i, &stage1);
				FD_SET(i, &stage2);
				continue;
			    }
			}
			if (j & 1)
			    FD_CLR(i, &stage1);
			if (j & 2)
			    FD_CLR(i, &stage2);
			continue;
		    }
		}
	    }
	}
    }

    return 0;
}
0 commentsLeave a comment
?

Log in

No account? Create an account