Back

--------------------------

(TCP) Socket programming basics (I)

--------------------------

...and how to build a port scanner

Hi, there! Already packed with delicious cookies &coffee, and ready to dive into networking? Good, good! let the dark-side flow through you. I suppose you also have around a piece of old hardware running Linux on it. Since I am a comfortable person, and I like to youtube like a pro, I am a big fan of Ubuntu. I put the apt in aptitude, l3l!. I hope you are familiar with Docker containers and /proc filesystem, (if not, links are provided at the ending of the zine for a nice and smooth beginning) <<-----Containers, containers, containers Trust me, Docker will make your life easier, and you can fool around with code without harming your physical machine (well, not so often, at least xD ) Arritee then! Let's install docker: nullQ@tr0n:/home$ sudo apt-get install docker.io easy, aye?! Create a folder somewhere, and write your first Dockerfile. Add below content: nullQ@tr0n:/home/test/waah$ cat Dockerfile FROM ubuntu:14.04 RUN apt-get update RUN apt-get upgrade -y RUN apt-get -y install gcc mono-mcs RUN apt-get -y install libpcap0.8-dev COPY . /home WORKDIR /home RUN gcc test.c -o test EXPOSE 8667 8990 23423 So easy to understand. Yes, the C code is already compiled once the container is created. Now, build the container (as root user): root@tr0n:/home/test/waah# docker build -t ahaha . Check if it has been created: root@tr0n:/home/test/waah# docker images | sed -n '/ahaha/{;p}' ahaha latest 6a15fd6b2030 About an hour ago 360 MB root@tr0n:/home/test/waah# ...now run it while opening just one port, get access to the container, and list what's underb/home directory as a check root@tr0n:/home/test/waah# docker run -p 8990:8990 -ti ahaha /bin/bash root@6a15fd6b2030:/home# root@6a15fd6b2030:/home# ls -ltr total 36 -rw-r--r-- 1 root root 1287 Jan 11 02:27 test.c -rwxr-xr-x 1 root root 9256 Jan 11 02:27 test -rw-r--r-- 1 root root 218 Jan 12 22:22 Dockerfile We'll leave this here, for a moment. [------from the physical host For now, let's focus on the physical machine, and check if there's something running on port 8990: root@tr0n:/home/test/waah# lsof -i :8990 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME docker-pr 17731 root 4u IPv6 464043 0t0 TCP *:clc-build-daemon (LISTEN) Let's find out more about this process: root@tr0n:/home/test/waah# ls -ltr /proc/`lsof -i :8990 | awk ' FNR == 2 {print $2}'`/fd/ total 0 lrwx------ 1 root root 64 ian 13 00:28 9 -> socket:[24341] lr-x------ 1 root root 64 ian 13 00:28 8 -> net:[4026531957] lrwx------ 1 root root 64 ian 13 00:28 5 -> anon_inode:[eventpoll] lrwx------ 1 root root 64 ian 13 00:28 4 -> socket:[464043] l-wx------ 1 root root 64 ian 13 00:28 2 -> /dev/null lrwx------ 1 root root 64 ian 13 00:28 10 -> socket:[24342] l-wx------ 1 root root 64 ian 13 00:28 1 -> /dev/null lr-x------ 1 root root 64 ian 13 00:28 0 -> /dev/null root@tr0n:/home/test/waah# It looks like socket`s inode 464043 is the same as the ID of column DEVICE from our previous lsof output. Curious about that 464043? Good, let's go deeper, and see what else we can find... root@tr0n:/proc# grep -ri 464043 /proc/ /proc/net/tcp6: 1: 00000000000000000000000000000000:231E 00000000000000000000000000000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 464043 1 ffff90875fd07700 100 0 0 10 0 /proc/net/tcp6 file providing decent (&hex'ed) information about existent TCP connections. A part of the above output for 464043 inode can be understood as below: Take [0000*] as 00000000000000000000000000000000 in below scheme: 1: [0000*]:231E [0000*]:0000 0A | | | | | |-----> connection state | | | | |-----------> remote TCP port number | | | |----------------> remote IPv6 address | | |-----------------------> local TCP port number | |------------------------------> local IPv6 address |--------------------------------------> number of entry If you convert 231E (from hex to decimal), you`ll get 8990 which is exactly the port on which our socket is listening (0A) on address :: (00000000000000000000000000000000) So, what is a socket, after all? - nothing more than a just a file And how does that work us, from a server-client side point of view? To use a socket, the server has to invoke socket() - this will allow the socket to exist in a name space, returning a socket descriptor (now you understand all that fuss about fd and inode?!) The server then bind()'s the socket to be associated with its local address, and keeps listen()'ing for incoming connections, eventually accept()'ing them. A client also uses socket(), but only to have its socket connect()'ed to a remote address, allowing the client to read()/write() from/to a server, send()/recv() to/from a server. As every logic human being out-there, I will not force you to cover all these notions in just one zine - instead, I`ll provide just enough details to create a port scanner. What do we have to do? 1. Create a socket: #include <sys/socket.h> int socky(int domain, int type, int protocol); Useful example: int socky; socky = socket(AF_INET, SOCK_STREAM, 0); if(sockfd .small sign. 0) { perror("Error opening socket"); } 2. Know thy structure sockaddr_in struct sockaddr_in { sa_family_t sin_family; /* address family: AF_INET */ in_port_t sin_port; /* port in network byte order */ struct in_addr sin_addr; /* internet address */ }; Useful example: struct sockaddr_in serv_addr; bzero((char *) &serv_addr, sizeof(serv_addr)); serv_addr.sin_family=AF_INET; bcopy((char *)server->h_addr,(char *)&serv_addr.sin_addr.s_addr, server->h_length); 3) Try to connect() to every opened port #include <sys/socket.h> int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); Useful example: serv_addr.sin_port=htons(portno); if (connect(socky, (struct sockaddr *)&serv_addr, sizeof(serv_addr))<0){ printf("Port is closed\n"); }else{ printf("port is active\n"); } For a port scanner, loops come quite in handy at this stage ;-) 4)...and close() the socket: #include int close(int fd); Useful example: close(socky); How do we put all that together? Glad you've asked! This is the code that we will run inside the container: #include<stdio.h> /* * container's test.c code, under /home directory */ #include<stdlib.h> #include<unistd.h> #include<string.h> #include<sys/types.h> #include<sys/socket.h> #include<netinet/in.h> #include<netdb.h> int main(int argc, char *argv[]) { struct hostent *host; int i ,start , end; char hostname[100]; int sockfd; struct sockaddr_in serv_addr; struct hostent *server; printf("Provide hostname or IP : "); gets(hostname); printf("\nStart scanning process with port: "); scanf("%d" , &start); printf("\n...and end scanning process with port: "); scanf("%d" , &end); server =gethostbyname(hostname); if(server==NULL) { fprintf(stderr, "ERROR, no such host\n"); exit(0); } bzero((char *) &serv_addr, sizeof(serv_addr)); serv_addr.sin_family=AF_INET; bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length); for( i = start ; i <= end ; i++) { serv_addr.sin_port=htons(i); sockfd = socket(AF_INET, SOCK_STREAM, 0); if(sockfd < 0) { error("Error opening socket"); } if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr))<0) { fflush(stdout); } else{ printf("%-5d open\n", i); } close(sockfd); } printf("\n"); return 0; } <<----------- Back to container As we have previously noticed, the program is already compiled inside the container. I like fast deployment, and I cannot lie Anywayz, the tricky part with container for running this code is to find the gateway IP (why do we provide the docker's gateway IP for the scanning program? this is homework for you!) root@6a15fd6b2030:/home# netstat -rna | grep '^0\.0\.0\.0' | sed 's/[^ ]* *//;s/ .*//;q' 172.17.0.1 Let's give it a go: root@6a15fd6b2030:/home# ./test Provide hostname or IP : 172.17.0.1 Start scanning process with port: 12 ...and end scanning process with port: 32555 8990 open root@6a15fd6b2030:/home# Nice, working! ......and what can we do from here on?! I guess we shall see next time, you knowledge junkie! ========================= Until then, read a bit about socket material, and dockers. POSIX self-learning is always welcome, too! http://www.tcpipguide.com/ http://man7.org/linux/man-pages/man2/socket.2.html http://man7.org/linux/man-pages/man2/connect.2.html http://man7.org/linux/man-pages/man2/bind.2.html https://github.com/wsargent/docker-cheat-sheet http://man7.org/linux/man-pages/man5/proc.5.html -------EOF---------