Introduction to Information Security Networking
Transmission Control Protocol (aka TCP) Most widely used protocol A TCP Connection is based on 6 crucial parmeters: o Source IP o Destination IP o Source port o Destination port o Source byte counter o Destination byte counter
TCP/IP Continued In order to establish a tcp connection a 3-way handshake occurs. Once the handshake is establish and the connection is up and running tcp ensures: o Delivery of _all_ packets o Delivery of in order o Delivery with no errors.
Server implementation The server listens on a specific port (aka the destination port) Once a connection is established, the server can accept more connections while handling the first connection. Establish multi processing of connections can be gained by: o Fork() – Multi process solution. o Multi-Threaded solutions. o Select() – Single process solutions o Other OS specific solutions.
Client implementation Usually handles only one connection at a time. (extreme contrary example: uTorrent). Source port is randomized by operating system.
Network Programming Most popular guide ever released for network programming is beej’s guide which is a very good starter reference o
Server implementation in C (taken from beej) - includes /* ** server.c - a stream socket server demo */ #include
C-Server Cleanup and defines #define MYPORT 3490 // the port users will be connecting to #define BACKLOG 10 // how many pending connections queue will hold //Cleaning up dead child processes: void sigchld_handler(int s) { while(waitpid(-1, NULL, WNOHANG) > 0); }
C-Server main int main(void) { int sockfd, new_fd; // listen on sock_fd, new connection on new_fd struct sockaddr_in my_addr; // my address information struct sockaddr_in their_addr; // connector’s address information socklen_t sin_size; struct sigaction sa; int yes=1; if (( sockfd = socket(AF_INET, SOCK_STREAM, 0) ) == -1) { perror("socket"); exit(1); } if (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) { perror("setsockopt"); exit(1); } my_addr.sin_family = AF_INET; // host byte order my_addr.sin_port = htons(MYPORT); // short, network byte order my_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP memset(&(my_addr.sin_zero), '\0', 8); // zero the rest of the struct
C-Server continued if ( bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr) )== -1) { perror("bind"); exit(1); } if ( listen(sockfd, BACKLOG) == -1) { perror("listen"); exit(1); } sa.sa_handler = sigchld_handler; // reap all dead processes sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; if (sigaction(SIGCHLD, &sa, NULL) == -1) { perror("sigaction"); exit(1); }
C-Server continued while(1) { // main accept() loop sin_size = sizeof(struct sockaddr_in); if (( new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size) ) == -1) { perror("accept"); continue; } printf("server: got connection from %s\n", inet_ntoa(their_addr.sin_addr)); if (! fork() ) { // this is the child process close(sockfd) ; // child doesn't need the listener if ( send(new_fd, "Hello, world!\n", 14, 0) == -1) perror("send"); close(new_fd) ; exit(0); } close(new_fd) ; // parent doesn't need this } return 0; }
C-Client - includes /* ** client.c - a stream socket client demo */ #include #define PORT 3490 // the port client will be connecting to #define MAXDATASIZE 100 // max number of bytes we can get at once
C-Client main int main(int argc, char *argv[]) { int sockfd, numbytes; char buf[MAXDATASIZE]; struct hostent *he; struct sockaddr_in their_addr; // connector's address information if (argc != 2) { fprintf(stderr,"usage: client hostname\n"); exit(1); } if ((he=gethostbyname(argv[1])) == NULL) { // get the host info perror("gethostbyname"); exit(1); } if (( sockfd = socket(AF_INET, SOCK_STREAM, 0) ) == -1) { perror("socket"); exit(1); }
C-Client main continued their_addr.sin_family = AF_INET; // host byte order their_addr.sin_port = htons(PORT); // short, network byte order their_addr.sin_addr = *((struct in_addr *)he->h_addr); memset(&(their_addr.sin_zero), 8); // zero the rest of the struct if ( connect(sockfd, (struct sockaddr *)&their_addr, sizeof(struct sockaddr) ) == -1) { perror("connect"); exit(1); } if (( numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0) ) == -1) { perror("recv"); exit(1); } buf[numbytes] = '\0'; printf("Received: %s",buf); close(sockfd); return 0; }
Python client #!usr/bin/python from socket import * PORT = 3490 def main(): sock = socket(AF_INET, SOCK_STREAM) sock.connect((" ", PORT)) res = sock.recv(1000) # 1000 = Maximum number of bytes to # receive, however, it may return with less bytes # than expected print res sock.close() if __name__ == '__main__': main()
Python server example #!usr/bin/python from socket import * PORT = 3490 def main(): sock = socket(AF_INET, SOCK_STREAM) sock.bind((" ", PORT)) sock.listen(10) # set backlog while 1: (clisock, addr) = sock.accept() print "Got incoming connection..." res = clisock.send("Hello, World!") clisock.close() sock.close() if __name__ == '__main__': main()
File descriptors Serially assigned to process and can be shared between processes. Reference based (file closes when the last descriptor closes) Popular descriptors: o 0 – stdin o 1 – stdout o 2 – stderr o 3 – graphics Can be dup()licated using dup() and dup2()
dup2() Using dup2() can be used to easily connect processes inputs and outputs to an existing TCP connection! Assuming sockfd is an already created and connected file descriptor we run: dup2(sockfd, 0); // dup standard input dup2(sockfd,1); // dup standard output dup2(sockfd,2); // dup standard error output Now we can run: execv(“someprocess”, NULL)