• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
KiranNFreddyFinalReport.doc
 

KiranNFreddyFinalReport.doc

on

  • 1,144 views

 

Statistics

Views

Total Views
1,144
Views on SlideShare
1,144
Embed Views
0

Actions

Likes
0
Downloads
2
Comments
0

0 Embeds 0

No embeds

Accessibility

Categories

Upload Details

Uploaded via as Microsoft Word

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    KiranNFreddyFinalReport.doc KiranNFreddyFinalReport.doc Document Transcript

    • TCP and UDP Migration: Communication across firewalls Kiran Mukesh Misra (A30214824) and Freddy Kharoliwalla (A30790087) {misrakir, kharoliw}@msu.edu December 7th, 2001 Abstract: The Internet today is going through a high degree of transformation, new generations of innovative and fast applications like, e-commerce, video streaming, transfer of medical-transcripts etc. are placing high performance demands as well as posing serious challenges in protecting the various corporate networks. The high concern for security and protection has brought about the implementations of firewalls and use of private networks. Due to limited IP addresses and the use of firewall, two machines behind two different firewalls cannot talk to each other as both of them use a private IP address. This causes much trouble to real-time communication applications. If there is an agent with a known global IP, both machines can connect to the agent. The agent can then connect them together. Here we look at how clients behind firewalls can be made to communicate using the technique of HTTP Tunneling and using SOCKS proxy servers. Introduction The word firewall is used to describe any kind of security measure taken to limit types of Internet traffic that can come in and go out of your local network. Today, any corporate network serious about their network security will have some sort of firewall installed. Private networks have firewalls to prevent the Internet-related fire from entering. Firewalls are primarily used to allow restricted access to a private network and to keep mischief-mongers out of private networks. The most commonly used type of firewall is the packet-filtering firewall. These firewalls allow considerable liberty for the traffic moving inside the private network, and going out of the network. But they treat traffic coming into the network with a lot of 1
    • suspicion. The firewall blocks any incoming packet, which does not meet a certain, set of rules or looks malicious. The two most commonly used Internet transport layer protocols are TCP (Transmission Control Protocol) and UDP. TCP provides the most reliable data transfer because of its high-level of error checking, and because it retransmits dropped packets. UDP provides more timely data delivery at the expense of reliability. UDP tends to use dynamic port assignment. It is a massive task to adjust these port ranges in real time. To overcome these port assignments a number of applications, such as Real Audio and Real video tend to use TCP or HTTP based streaming. However, this is at the cost of efficiency and playback quality. UDP imposes a number of challenges in implementing secure, effective firewalls. It is difficult to filter UDP application data using packet filtering or routing policy techniques, as each packet is an isolated event1. Also UDP applications can set up connections from servers to clients behind firewalls. In such cases, the firewall must pretend to be the client to receive the connection from the server. To overcome most of these difficulties of UDP communication across firewalls we used the SOCKS5 proxy server (based on RFC19282). SOCKS offers unique advantages in the complex and difficult area of UDP streaming application policy management and security. SOCKS v5 securely and simply handles UDP. As a policy many administrators would like to monitor HTTP traffic going out of their network. This would ensure that company time is not spent on idly browsing the web; at the same time the administrators do not want to block communication between on-line customer service representatives and the clientele. They generally achieve this using a proxy HTTP server. However an HTTP proxy has very loose security and an experienced hacker can take advantage of it. A SOCKS 5 server is a powerful tool in the hands of the network administrator. It can act like a firewall, which can request authentication, monitor/ban traffic and provide secure TCP connections. Administrators can establish a SOCKS 2
    • environment in their network by either supplying every user with a SOCKS based client like telnet, ftp etc. or by proxying requests from these clients to a proxy which then behaves like a SOCKS client to the SOCKS server. System administrators generally do not implement port forwarding in their firewalls. What this implies is that the firewall processes incoming traffic only on ports, which are commonly used for applications like web browsing (HTTP port 80, TCP), however they block packets coming on any other port. The world of networking is in a state of constant flux and new applications giving different services come out every day. These applications may use non-standard ports for communication, unknown to the firewall. This results in firewalls unwittingly blocking incoming communication related to these applications. A more interesting problem is that of mobile devices. Mobile devices that access the Internet may lie behind firewalls, and the firewall will simply drop all Mobile IP packets coming from the base station. As always people have devised ingenious ways to overcome this problem. One of the solutions proposes the use of a proxy server. The earliest examples of such proxies used a different protocol for each application based on their requirements. An attempt was made to standardize communication with such proxies and this lead to the development of SOCKS Protocol Version 5 (RFC 1928). This protocol required the implementation of a SOCKS sever and a slight modification of the applications termed as “SOCKSification” of the client. Related Work The corporate firewall can be considered as a double-edged sword. It helps prevent unauthorized access to the corporate Web services, but can disable access for legitimate clients also. In order to provide access to the to these clients a sort of proxy is to be implemented to get across the firewall. The most basic way of getting around the firewall today is using HTTP Tunneling. Technologies such as SOAP 3 (Simple 3
    • Object Access Protocol) have been developed to provide safe and reliable access through firewall Figure 1: The servlet and servlet container protection, using the HTTP mechanism. Another alternative to the SOAP technology is the use of JAVA objects to go across these firewalls using the same HTTP mechanism. The use of JAVA objects using is done using servlets. Servlets are a server-side mechanism for receiving and responding, among other things, to HTTP requests. A servlet cannot operate on its own - it only operates in the context of a servlet container, as shown in Figure 1. Another methology of going across firewalls is using SOCKS4 Servers. Socks5 provides a simple way to implement firewall security. Socks5 offers many of the benefits of traditional packet filtering firewalls, without introducing complicated inter-domain routing issues into your network's already complex routing structure. It's is basically a proxy server. Specifically, it's a generic circuit proxy that can be configured to proxy as many or as few TCP/IP ports as your users need. Using the Socks5 version, we are able to add strong authentication and offer a limited number of incoming connections. The basic features incorporated in the Socks5 are: • Secure firewall traversal. • Support for User Datagram Protocol (UDP) as well as Transmission Control Protocol (TCP) applications. • Support for a range of authentication, encryption, tunneling and key management schemes. 4
    • • Extremely flexible access controls. • Unified and coherent policy management. These benefits apply to a variety of Internet border control solutions, such as: • Client/server applications • Firewalls • Virtual private networks (VPNs) • Proxy and cache servers • And the ever popular ICQ Objectives The aim of the project is to build SOCKSified clients and setup a SOCKS 5 server to enable communication across firewalls. Tunneling is a popular approach used in traversing firewalls. Here popular protocols like HTTP are used as a transport layer to carry information. As part of the project we implement client/servers using the HTTP tunneling. The project aims at comparing the performance of directly connected sockets, SOCKSified applications and applications using HTTP tunneling. Based upon our results we intend to discover an efficient way for communicating across firewalls. The entire development is proposed to be carried out on Linux machines, using C/C++ and JAVA. Methodology The project required the following setup. Mandrake Linux v8.1 (kernel v2.4.8) was installed on a machine. The source code for SOCKS5 server implemented by NEC5 and available for educational use was obtained and installed. The server was configured to accept requests from test machines. Generally SOCKS5 servers are configured to authenticate clients. We turned this feature OFF to simplify implementation. The configuration file for SOCKS5 is attached as Appendix A.1 (socks5.conf). All our 5
    • observations are based on measurements of time required by the client to perform a particular task. A graph was plotted to aid in visualizing the benefits of one architecture Vs the other. Design Rationale Our focus was on TCP applications so we started first with a normal TCP client/server. The client sent the server 3 strings; in return the server sends 3 strings to the client (source code Appendix A.2a and A.2b). The setup is illustrated in Figure 2. SERVER CLIENT Figure 2: Direct connection between client and server Next the client was SOCKSified (source code Appendix A.2c). What this implies is the client makes its request via the SOCKS server. First the client has to setup a connection with the SOCKS server and authenticate itself. The client then has to send a CONNECT (refer RFC 1928) command to the SOCKS server along with the address of the server (SERVERi)say the client wants to connect to. The SOCKS server establishes a connection with SERVERi, if successful the SOCKS server informs the client. The client can now treat the socket connection to the SOCKS server as direct connection to SERVERi. Reads and writes are proxied. The setup is illustrated in Figure 3. FIREWALL SOCKS5 SERVERi SERVER CLIENT Figure 3: Client connecting to a server from behind the Firewall 6
    • Here the assumption is that even if SERVERi is behind a firewall its service port is open. If this is not the case we can resort to approaches like tunneling to setup a communication channel with SERVERi. There are 3 different ways to SOCKSify an existing client: 1. Modify the code of the client to make a call to the SOCKS library and recompile the code. This approach is simple but does not guarantee that it will work. Your client needs to be written in a particular fashion for this approach to work. (For more information please refer http://www.socks.nec.com) 2. Modify the code to pass the appropriate negotiation messages before the client uses the socket for communication. This is ideal if a code is being written from scratch. 3. Using runsocks: runsocks is a shell script that loads the shared library of SOCKSv5 Reference Implementation. If your operating system supports shared libraries, runsocks dynamically allows the application to use the SOCKSified networking function calls in the shread libraries of SOCKSv5 Reference Implementation instead of the standard networking function calls. We were building client applications from scratch so we chose approach 2 as it facilitated ease in debugging and also afforded a better understanding of the SOCKS5 architecture. Next we implemented a client/server to transfer files. This is significant as it gives an idea on the impact of SOCKS5 Server on transfer speed. This has major implications on real-time systems, which have strict timing constraints for delivery/receipt of data. This also allows us to analyze timings for different sizes of data. The client server was initially tested with a direct connection as shown in Figure 2. Files having sizes 100KB, 1MB, 10MB and 100MB was used for transfer. The time required by the client for the entire transaction i.e. sending the request and receiving the file is noted (Table 1). Next we SOCKSified the file transfer client and again observed the transaction time to download the file for the setup shown in Figure 3. This time the transaction also included the negotiation time with the SOCKS5 server. 7
    • As mentioned earlier the introduction of SOCKS to an existing network threatens to break all existing clients. We can work around this situation by replacing all the existing clients with SOCKS compliant versions of the client. This needs all the clients to be located at one place otherwise the administrator may miss some of the files. If the files are not centrally located or cannot be easily replaced we can use another approach. Here a proxy server is setup for the service and all the requests are transmitted via this proxy server. This proxy server is a SOCKS client making requests to the SOCKS server. To compare the performance of these two methods we built the following applications. The coding was done in JAVA. The client/server mimic a HTTP Server/Client(Appendix A.4a and A.4b). A proxy server was built in C. Originally the Client and Server communicated directly with each other and the client downloaded files having sizes 100KB, 1MB, 10MB and 100MB. The time required for the transaction was noted as a measure of performance (Figure 2 represents the setup). Next the client was setup to make its request through the proxy (Appendix A.5a), which decoded the request and retrieved the file for the client. Again the same files were downloaded and the transaction times noted. The setup is illustrated in Figure 4. FIREWALL HTTP HTTP SERVER PROXY CLIENT Figure 4: HTTP CLIENT communicating with the HTTP SERVER via PROXY Next the PROXY was SOCKSified (Appendix A.5b) and all the PROXY requests are made via the SOCKS server. The client needs to be modified to make suitable requests to proxy (source Appendix A.4c). The setup is illustrated in Figure 5 FIREWALL 8
    • HTTP SOCKS5 HTTP SERVER SERVER PROXY CLIENT Figure 5: HTTP CLIENT communicating with the HTTP SERVER via SOCKSifed PROXY Finally we had a look at the TUNNELING approach. We blocked all ports on our machine except port 80 (using iptables). Next we setup the pre-routing table to forward any request coming at port 80 to our server. The client/server we used were the HTTP client/server in appendix A.4a and A.4b. The setup is illustrated in Figure 6 FIREWALL HTTP HTTP CLIENT SERVER 80 FORWARDED Figure 6: Tunneling using port forwarding For UDP client/server (Appendix A.6a and A.6b) applications we have only implemented the architecture used in Figure 3. When a socks-enabled client application wants to receive or send UDP packets, the client initiates a TCP-based control connection with the SOCKS v5 server. Through the control connection, the client and server exchange information that might include user authentication, domain name, IP address, and port number. Using this information and the network management policies defined by the network administrator, the SOCKS v5 server determines if it should accept or deny the client's request. If the SOCKS v5 server allows the request, it temporarily, dynamically opens a UDP port on the server to receive incoming UDP packets for the client from the application server. The SOCKS v5 server relays these packets to the client. When the communication finishes, SOCKS v5 server automatically 9
    • closes the TCP control connection and the UDP relay port. The SOCKS v5 server discards all unauthorized incoming and outbound UDP packets after closing the port. The aim of the project is to determine the best way for communicating across firewalls. As a result we have considered the most popular architectures. Tunneling is the most popular architecture prevalent today, whereas SOCKS is fast becoming popular. A combination of the two could give a lot of flexibility and power to the administrators. In our implementations we have not hidden the server behind firewalls. It is assumed that tunneling can be used to communicate with any server lying behind a firewall. Technical Results and Analysis To perform a comparison of the various architectures used in traversing firewalls a simple task was assigned to clients using the different architectures. The time taken to complete the task was noted as a measure of performance. Table 1: FILE TRANSFER (+ strings) (all timing considerations are in milliseconds): Type of connection / File Size 100KB 1MB 10MB 100MB strings Direct (Figure 2) 17.71 70.088 423.446 4827.64 20.898 Direct to SOCKS (Figure 3) 17.753 127.435 1066.412 10881.521 46.674 Table 2: JAVA: HTTP Client/Server (+tunneling) (all timing considerations are in milliseconds): Type of connection / File 100KB 1MB 10MB 100MB Java Size Tunneling Direct (Figure 2) 62 109 492 18909 126 Via Proxy (Figure 4) 88 216 732 18955 128 Via SOCKS proxy (Figure 5) 180 450 1521 39021 265 Appendix B.1 and B.2 contain the plots for the above values. We can clearly see that the advantage of security we gain due to SOCKS is at the cost of performance. Since all writes/reads are proxied via the SOCKS server the SOCKS server can become a performance 10
    • bottleneck for the network. A proper load distribution amongst several SOCKS servers can ensure the smooth working of the network. Future Work UDP deserves a more comprehensive study/analysis. The project does not do full justice to communication across firewalls for applications using UDP. Also SOCKS servers can be chained together to communicate across several firewalls. This topic has not been extensively studied in this project. A more detailed analysis of chaining SOCKS servers presents future scope for the project. Summary The advantage of security we gain due to SOCKS is at the cost of performance. Since all writes/reads are proxied via the SOCKS server the SOCKS server can become a performance bottleneck for the network. A proper load distribution amongst several SOCKS servers can ensure the smooth working of the network. The same holds true for tunneling which uses other protocols like HTTP as a transport layer. On doing analysis of the various architectures used for communicating across firewalls we can conclude that there are several tradeoffs involved in every architecture. SOCKS provides better functionality as it acts in the application layer, but this is at the cost of performance. Where security is a priority SOCKS is the better choice. If security is not of great importance tunneling can be used instead. 11
    • Appendix A A.1 socks.conf # /etc/socks5.conf set SOCKS5_MAXCHID 3 set SOCKS5_NOIDENT set SOCKS5_TIMEOUT 5 #auth 35.8.18.199 - - noproxy 35.8.18.199 - 35.8.18.199:8080 permit - - 35.8.18.199 - - - - deny - - - - - - - 12
    • A.2a client.c /* * This is a normal TCP client which sends 3 strings over to the server * and receives 3 strings from the user. The 3 strings are displayed to * the user. */ #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/time.h> #include <unistd.h> #include <netinet/in.h> #include <inttypes.h> #include <arpa/inet.h> #include <stdio.h> #include <stdlib.h> #define NSTRS 3 /* no. of strings */ /* * Strings we send to the server. */ char *strs[NSTRS] = { "This is the first string from the client.n", "This is the second string from the client.n", "This is the third string from the client.n" }; main(int argc, char *argv[]) { char c; FILE *fp; register int i, s, len; struct sockaddr_in sain; char tmp_str[50]; struct timeval start, end; if (argc!=3) { printf("usage: %s <serverIP> <serverPort>n", argv[0]); exit(0); } gettimeofday(&start, NULL); /* 13
    • * Get a socket to work with. This socket will * be in the UNIX domain, and will be a * stream socket. */ if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("client: socket"); return(1); } /* * Create the address we will be connecting to. */ sain.sin_family = AF_INET; sain.sin_addr.s_addr = inet_addr(argv[1]); sain.sin_port = htons(atoi(argv[2])); /* * Try to connect to the address. For this to * succeed, the server must already have bound * this address, and must have issued a listen() * request. * * The third argument indicates the "length" of * the structure, not just the length of the * socket name. */ len = sizeof(sain); if (connect(s, (struct sockaddr *)&sain, len) < 0) { perror("client: connect"); return(1); } /* * We'll use stdio for reading * the socket. */ fp = fdopen(s, "r"); /* * First we read some strings from the server * and print them out. */ for (i = 0; i < NSTRS; i++) { while ((c = fgetc(fp)) != EOF) { putchar(c); if (c == 'n') break; } 14
    • } /* * Now we send some strings to the server. */ for (i = 0; i < NSTRS; i++) send(s, strs[i], strlen(strs[i]), 0); gettimeofday(&end, NULL); printf("Time Taken:%f msn", ( (double) end.tv_sec-start.tv_sec)*1000+((double)end.tv_usec- start.tv_usec)/1000.0); /* * We can simply use close() to terminate the * connection, since we're done with both sides. */ close(s); return(0); } 15
    • A.2b Server.c /* * This program is a test TCP Server * Usage: server <IpToBind> <PortToBind> * It sends 3 strings to the client. * And displays 3 strings it receives from the client */ #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <unistd.h> #include <netinet/in.h> #include <inttypes.h> #include <arpa/inet.h> #include <stdio.h> #include <stdlib.h> #define NSTRS 3 /* no. of strings */ /* * Strings we send to the client. */ char *strs[NSTRS] = { "This is the first string from the server.n", "This is the second string from the server.n", "This is the third string from the server.n" }; main(int argc, char *argv[]) { char c; FILE *fp; int fromlen; register int i, s, ns, len; struct sockaddr_in sain, fsain; if (argc!=3) { printf("usage: %s <serverIP> <portNumber>n", argv[0]); exit(0); } /* * Get a socket to work with. This socket will * be in the UNIX domain, and will be a 16
    • * stream socket. */ if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("server: socket"); return(1); } /* * Create the address we will be binding to. */ sain.sin_family = AF_INET; sain.sin_addr.s_addr = inet_addr(argv[1]); //sain.sin_port = htons(PORT); sain.sin_port = htons(atoi(argv[2])); /* * Try to bind the address to the socket. We * unlink the name first so that the bind won't * fail. * * The third argument indicates the "length" of * the structure, not just the length of the * socket name. */ len = sizeof(sain); if (bind(s, (struct sockaddr *) &sain, len) < 0) { perror("server: bind"); return(1); } /* * Listen on the socket. */ if (listen(s, 5) < 0) { perror("server: listen"); return(1); } /* * Accept connections. When we accept one, ns * will be connected to the client. fsain will * contain the address of the client. */ if ((ns = accept(s, (struct sockaddr *) &fsain, (socklen_t *)&fromlen)) < 0) { perror("server: accept"); return(1); } 17
    • /* * We'll use stdio for reading the socket. */ fp = fdopen(ns, "r"); /* * First we send some strings to the client. */ for (i = 0; i < NSTRS; i++) send(ns, strs[i], strlen(strs[i]), 0); /* * Then we read some strings from the client and * print them out. */ for (i = 0; i < NSTRS; i++) { while ((c = fgetc(fp)) != EOF) { putchar(c); if (c == 'n') break; } } /* * We can simply use close() to terminate the * connection, since we're done with both sides. */ close(s); return(0); } 18
    • A.2c Sock_client.c /* * This a SOCKSified version of the TCP client that sends 3 strings * to the server, and in return receives 3 test strings and displays * it to the user * Assumptions: * usage: %0 socksIP socksPort serverIP serverPORT * IP Address: 4 byte long */ #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/time.h> #include <unistd.h> #include <netinet/in.h> #include <inttypes.h> #include <arpa/inet.h> #include <stdio.h> #include <stdlib.h> #define NSTRS 3 /* no. of strings */ /* * Strings we send to the server. */ char *strs[NSTRS] = { "This is the first string from the client.n", "This is the second string from the client.n", "This is the third string from the client.n" }; struct supported_methods { char ver; // 4 if you want SOCKSv4, 5 if you require UDP char num_methods; // I'll talk about 2 methods char methods[2]; // 0 is NO AUTHENTICATION, and 2 is USERNAME/PASSWORD } first_msg_to_server; struct command { char ver; // same as above char cmd; // 1=CONNECT, 2=TCP BIND, 3=UDP BIND char reserved; // must be 0 char address_type; // 1=4 byte IP address, 3=domain name, 4=6 byte IP address //char address_data[4]; // depends on address type in_addr_t address_data; unsigned short port; // should be in BIG ENDIAN format! } command_to_server; 19
    • struct authenticate_me { char ver; // authentication version not proxy version unsigned char user_name_length; // 1..255 char uname[4]; // not NULL terminated! unsigned char password_length; char pword[8]; // not NULL terminated! } authentication_msg_to_server; struct command_reply { char ver; // same as above char reply; // 0=success, 1-9 are error messages char reserved; char address_type; // 1=4 byte IP address, 3=domain name, 4=6 byte IP address char bind_address_data[4]; // depends on above unsigned short bind_port; // BIG ENDIAN format! } reply_from_server; main(int argc, char *argv[]) { char c; FILE *fp; register int i, s, len; struct sockaddr_in sain; struct timeval start, end; if(argc!=5) { printf("usage: %s <sockIP> <sockPort> <serverIP> <serverPort>n", argv[0]); exit(0); } gettimeofday(&start, NULL); /* * Structure intializations */ first_msg_to_server.ver=5; first_msg_to_server.num_methods=2; first_msg_to_server.methods[0]=0; first_msg_to_server.methods[1]=2; command_to_server.ver=5; command_to_server.reserved=0; authentication_msg_to_server.ver=1; authentication_msg_to_server.user_name_length=strlen("user"); strcpy(authentication_msg_to_server.uname,"user"); authentication_msg_to_server.password_length=strlen("password"); 20
    • strcpy(authentication_msg_to_server.pword,"password"); /* * Get a socket to work with. This socket will * be in the UNIX domain, and will be a * stream socket. For communicating with SOCKS5 server */ if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("client: socket"); return(1); } /* * Create the address we will be connecting to. */ sain.sin_family = AF_INET; sain.sin_addr.s_addr = inet_addr(argv[1]); sain.sin_port = htons(atoi(argv[2])); /* * Try to connect to the address. For this to * succeed, the server must already have bound * this address, and must have issued a listen() * request. * * The third argument indicates the "length" of * the structure, not just the length of the * socket name. */ len = sizeof(sain); if (connect(s, (struct sockaddr *)&sain, len) < 0) { perror("client: connect"); return(1); } /* * Tell the proxy server which authentication methods you support */ send(s, &first_msg_to_server, sizeof(first_msg_to_server), 0); /* * We'll use stdio for reading * the socket. */ fp = fdopen(s, "r"); /* 21
    • * Read the 2 byte response from server */ c=fgetc(fp); printf("SOCKS server version:%dn", c); c=fgetc(fp); if (c==0) { printf("Authentication not requiredn"); } else { printf("Sending authentication message to servern"); send(s, &authentication_msg_to_server, sizeof(authentication_msg_to_server), 0); } /* * Send a request to connect to SERVICE PROVIDER */ command_to_server.cmd = 1; /* TCP connect */ command_to_server.address_type = 1; /* 4 byte IP address */ /* 35.8.18.199 */ command_to_server.address_data=inet_addr(argv[3]); command_to_server.port=htons(atoi(argv[4])); send(s, &command_to_server, sizeof(command_to_server), 0); /* * Read reply from server */ printf("Reading command-reply from servern"); fread(&reply_from_server, sizeof(reply_from_server), 1, fp); if (reply_from_server.reply==0) { printf("SUCCESSFULLY setup connection with service providern"); /* * First we read some strings from the server * and print them out. */ for (i = 0; i < NSTRS; i++) { while ((c = fgetc(fp)) != EOF) { putchar(c); if (c == 'n') break; } } /* * Now we send some strings to the server. */ for (i = 0; i < NSTRS; i++) send(s, strs[i], strlen(strs[i]), 0); } else { printf("Connection with service provider FAILEDn"); } 22
    • /* * We can simply use close() to terminate the * connection, since we're done with both sides. */ close(s); gettimeofday(&end, NULL); printf("Time Taken:%f msn", ( (double) end.tv_sec-start.tv_sec)*1000+((double)end.tv_usec- start.tv_usec)/1000.0); return(0); } 23
    • A.3a Txclient.c /* * This program is a normal TCP client used to download a file mentioned at * command line */ #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <unistd.h> #include <netinet/in.h> #include <inttypes.h> #include <arpa/inet.h> #include <stdio.h> #include <stdlib.h> #include <sys/time.h> main(int argc, char *argv[]) { char c; FILE *fp, *out; register int i, s, len; struct sockaddr_in sain; char tmp_str[50]; int tmpint; char fileName[200], fileLength[10], buf[500]; off_t remainingFile; struct timeval start, end; if (argc!=5) { printf("usage: %s <serverIP> <serverPort> <sourceFileName> <destfileName>n",argv[0]); exit(0); } gettimeofday(&start, NULL); /* * Get a socket to work with. This socket will * be in the UNIX domain, and will be a * stream socket. */ if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("client: socket"); return(1); } 24
    • /* * Create the address we will be connecting to. */ sain.sin_family = AF_INET; sain.sin_addr.s_addr = inet_addr(argv[1]); //sain.sin_port = htons(PORT); sain.sin_port = htons(atoi(argv[2])); /* * Try to connect to the address. For this to * succeed, the server must already have bound * this address, and must have issued a listen() * request. * * The third argument indicates the "length" of * the structure, not just the length of the * socket name. */ len = sizeof(sain); if (connect(s, (struct sockaddr *)&sain, len) < 0) { perror("client: connect"); return(1); } /* * Send message containing file name to server */ printf("Sending file Namen"); strcpy(fileName, argv[3]); send(s, fileName, 200, 0); //send(s, argv[3], strlen(argv[3]), 0); /* * We'll use stdio for reading * the socket. */ //out = fdopen(s, "r"); fp = fopen(argv[4], "w"); printf("Reading file lengthn"); recv(s, fileLength, 10, 0); printf("File Length:%sn", fileLength); sscanf(fileLength, "%d", &remainingFile); while(remainingFile>500) { recv(s, buf, 500, 0); fwrite(buf, 1, 500, fp); remainingFile-=500; } if (remainingFile>0) { 25
    • recv(s, buf, remainingFile, 0); fwrite(buf, 1, remainingFile, fp); remainingFile=0; } printf("End of readn"); /* * We can simply use close() to terminate the * connection, since we're done with both sides. */ close(s); //fclose(out); fclose(fp); gettimeofday(&end, NULL); printf("Time Taken:%f msn", ( (double) end.tv_sec-start.tv_sec)*1000+((double)end.tv_usec- start.tv_usec)/1000.0); return(0); } 26
    • A.3b Txserver.c /* * This program is a normal TCP server and services sends back any file * requested by a client */ #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/socket.h> #include <fcntl.h> #include <unistd.h> #include <netinet/in.h> #include <inttypes.h> #include <arpa/inet.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> main(int argc, char *argv[]) { char c; int in, index, fromlen; register int i, s, ns, len; struct sockaddr_in sain, fsain; char fileName[200], fileLength[10], buf[500]; struct stat fileDtls; off_t remainingFile; if (argc!=3) { printf("usage: %s <serverIP> <serverPort>n", argv[0]); exit(0); } /* * Get a socket to work with. This socket will * be in the UNIX domain, and will be a * stream socket. */ if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("server: socket"); return(1); } /* * Create the address we will be binding to. */ 27
    • sain.sin_family = AF_INET; sain.sin_addr.s_addr = inet_addr(argv[1]); sain.sin_port = htons(atoi(argv[2])); /* * Try to bind the address to the socket. We * unlink the name first so that the bind won't * fail. * * The third argument indicates the "length" of * the structure, not just the length of the * socket name. */ len = sizeof(sain); if (bind(s, (struct sockaddr *) &sain, len) < 0) { perror("server: bind"); return(1); } /* * Listen on the socket. */ if (listen(s, 5) < 0) { perror("server: listen"); return(1); } /* * Accept connections. When we accept one, ns * will be connected to the client. fsain will * contain the address of the client. */ if ((ns = accept(s, (struct sockaddr *) &fsain, (socklen_t *)&fromlen)) < 0) { perror("server: accept"); return(1); } recv(ns, fileName, 200, 0); /* * Remove any leading NULL characters sent by SOCKS 5 server */ i=0; while((int)fileName[i]==0) i++; for (index=i; index<200; index++) fileName[index-i]=fileName[index]; 28
    • printf("Transferring: %sn", fileName); in=open(fileName, O_RDONLY); fstat(in, &fileDtls); sprintf(fileLength,"%d", fileDtls.st_size); printf("fileLength:%sn", fileLength); printf("Sending file lengthn"); send(ns, fileLength, 10, 0); printf("Sending filen"); remainingFile=fileDtls.st_size; while(remainingFile>500) { recv(in, buf, 500, 0); remainingFile-=500; send(ns, buf, 500, 0); } if (remainingFile>0) { recv(in, buf, remainingFile, 0); send(ns, buf, remainingFile, 0); remainingFile=0; } printf("Done sendingn"); close(ns); close(s); close(in); return(0); } 29
    • A.3c Sock_txclient.c /* * This is a SOCKSified version of the TCP client used to download files * It directly communicates with the SOCKS server */ #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <unistd.h> #include <netinet/in.h> #include <inttypes.h> #include <arpa/inet.h> #include <stdio.h> #include <stdlib.h> #include <sys/time.h> struct supported_methods { char ver; // 4 if you want SOCKSv4, 5 if you require UDP char num_methods; // I'll talk about 2 methods char methods[2]; // 0 is NO AUTHENTICATION, and 2 is USERNAME/PASSWORD } first_msg_to_server; struct command { char ver; // same as above char cmd; // 1=CONNECT, 2=TCP BIND, 3=UDP BIND char reserved; // must be 0 char address_type; // 1=4 byte IP address, 3=domain name, 4=6 byte IP address //char address_data[4]; // depends on address type in_addr_t address_data; unsigned short port; // should be in BIG ENDIAN format! } command_to_server; struct authenticate_me { char ver; // authentication version not proxy version unsigned char user_name_length; // 1..255 char uname[4]; // not NULL terminated! unsigned char password_length; char pword[8]; // not NULL terminated! } authentication_msg_to_server; struct command_reply { char ver; // same as above char reply; // 0=success, 1-9 are error messages char reserved; char address_type; // 1=4 byte IP address, 3=domain name, 4=6 byte IP address char bind_address_data[4]; // depends on above 30
    • unsigned short bind_port; // BIG ENDIAN format! } reply_from_server; main(int argc, char *argv[]) { char c; FILE *fp, *out; register int i, s, len; struct sockaddr_in sain; char tmp_str[50]; int tmpint; char fileName[200], fileLength[10], buf[500]; off_t remainingFile; struct timeval start, end; if (argc!=7) { printf("usage: %s <sockServerIP> <sockServerPort> <serverIP> <serverPort> <sourceFileName> <destfileName>n",argv[0]); exit(0); } gettimeofday(&start, NULL); /* * Structure intializations */ first_msg_to_server.ver=5; first_msg_to_server.num_methods=2; first_msg_to_server.methods[0]=0; first_msg_to_server.methods[1]=2; command_to_server.ver=5; command_to_server.reserved=0; authentication_msg_to_server.ver=1; authentication_msg_to_server.user_name_length=strlen("user"); strcpy(authentication_msg_to_server.uname,"user"); authentication_msg_to_server.password_length=strlen("password"); strcpy(authentication_msg_to_server.pword,"password"); /* * Get a socket to work with. This socket will * be in the UNIX domain, and will be a * stream socket. */ if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("client: socket"); return(1); 31
    • } /* * Create the address we will be connecting to. */ sain.sin_family = AF_INET; sain.sin_addr.s_addr = inet_addr(argv[1]); sain.sin_port = htons(atoi(argv[2])); /* * Try to connect to the address. For this to * succeed, the server must already have bound * this address, and must have issued a listen() * request. * * The third argument indicates the "length" of * the structure, not just the length of the * socket name. */ len = sizeof(sain); if (connect(s, (struct sockaddr *)&sain, len) < 0) { perror("client: connect"); return(1); } /* * Tell the proxy server which authentication methods you support */ send(s, &first_msg_to_server, sizeof(first_msg_to_server), 0); /* * We'll use stdio for reading * the socket. */ fp = fdopen(s, "r"); /* * Read the 2 byte response from server */ c=fgetc(fp); printf("SOCKS server version:%dn", c); c=fgetc(fp); if (c==0) { printf("Authentication not requiredn"); } else { printf("Sending authentication message to servern"); send(s, &authentication_msg_to_server, sizeof(authentication_msg_to_server), 0); } 32
    • /* * Send a request to connect to SERVICE PROVIDER */ command_to_server.cmd = 1; /* TCP connect */ command_to_server.address_type = 1; /* 4 byte IP address */ command_to_server.address_data=inet_addr(argv[3]); command_to_server.port=htons(atoi(argv[4])); send(s, &command_to_server, sizeof(command_to_server), 0); /* * Read reply from server */ printf("reading command-reply from servern"); fread(&reply_from_server, sizeof(reply_from_server), 1, fp); if (reply_from_server.reply==0) { printf("SUCCESSFULLY setup connection with service providern"); /* * Send message containing file name to server */ strcpy(fileName, argv[5]); printf("Sending file Name:%sn", fileName); send(s, fileName, 200, 0); /* * Opening destination file */ fp = fopen(argv[6], "w"); printf("Reading file lengthn"); recv(s, fileLength, 10, 0); printf("File Length:%sn", fileLength); sscanf(fileLength, "%d", &remainingFile); while(remainingFile>500) { recv(s, buf, 500, 0); fwrite(buf, 1, 500, fp); remainingFile-=500; } if (remainingFile>0) { recv(s, buf, remainingFile, 0); fwrite(buf, 1, remainingFile, fp); remainingFile=0; } fclose(fp); printf("End of readn"); } else { printf("Connection with service provider FAILEDn"); } /* * We can simply use close() to terminate the 33
    • * connection, since we're done with both sides. */ close(s); gettimeofday(&end, NULL); printf("Time Taken:%f msn", ( (double) end.tv_sec-start.tv_sec)*1000+((double)end.tv_usec- start.tv_usec)/1000.0); return(0); } 34
    • A.4a httpServer.java /* * This program is a test http server * Usage: java httpServer <port> * It accepts a connection and checks whether the required file is there in its folder * If file present returns the file else returns a 404 not found error */ import java.net.*; import java.io.*; import java.util.*; import java.lang.*; public class httpServer { public static void main(String args[]) { int port; ServerSocket server_socket; try { port = Integer.parseInt(args[0]); } catch (Exception e) { port = 1500; } try { server_socket = new ServerSocket(port); System.out.println("httpServer running on port " + server_socket.getLocalPort()); // server infinite loop while(true) { Socket socket = server_socket.accept(); System.out.println("New connection accepted " + socket.getInetAddress() + ":" + socket.getPort()); // Construct handler to process the HTTP request message. try { httpRequestHandler request = new httpRequestHandler(socket); // Create a new thread to process the request. Thread thread = new Thread(request); 35
    • // Start the thread. thread.start(); } catch(Exception e) { System.out.println(e); } } } catch (IOException e) { System.out.println(e); } } } class httpRequestHandler implements Runnable { final static String CRLF = "rn"; Socket socket; InputStream input; OutputStream output; BufferedReader br; // Constructor public httpRequestHandler(Socket socket) throws Exception { this.socket = socket; this.input = socket.getInputStream(); this.output = socket.getOutputStream(); this.br = new BufferedReader(new InputStreamReader(socket.getInputStream())); } // Implement the run() method of the Runnable interface. public void run() { try { processRequest(); } catch(Exception e) { System.out.println(e); } } private void processRequest() throws Exception { while(true) { String data = br.readLine(); if(data.equals(CRLF) || data.equals("")) break; /* Remove any leading NULL characters introduced by SOCKS server */ byte[] tmpStr = data.getBytes(); 36
    • int iter=0; while (tmpStr[0]==0) { for (int index=0; index<tmpStr.length-iter-1; index++) tmpStr[index]=tmpStr[index+1]; iter++; } String headerLine; if (tmpStr.length-iter>0) { byte [] newTmpStr = new byte[tmpStr.length-iter]; for (int index=0; index<newTmpStr.length; index++) newTmpStr[index]=tmpStr[index]; headerLine = new String(newTmpStr); } else { headerLine = new String(data); } System.out.println("$" + headerLine + "$"); tmpStr = headerLine.getBytes(); for (int i=0; i<tmpStr.length; i++) { System.out.print((int)tmpStr[i]); } System.out.print("n"); System.out.println("Tokenizingn"); StringTokenizer s = new StringTokenizer(headerLine); System.out.println("Number of tokens:" + s.countTokens()); System.out.println("Getting next tokenn"); String temp = s.nextToken(); System.out.println("Got next tokenn"); System.out.print("n"); System.out.println ("checking temp:$" + temp + "$ for GET"); if(temp.equals("GET")) { System.out.println ("entered GET"); String fileName = s.nextToken(); System.out.println ("Extracted filename:" + fileName); fileName = "." + fileName ; if(fileName.equals("")) { fileName ="./index.html"; } // Open the requested file. FileInputStream fis = null ; boolean fileExists = true ; try { System.out.println("Opening file:" + fileName); fis = new FileInputStream( fileName ) ; } catch ( FileNotFoundException e ) { System.out.println("ERROR Opening file:" + fileName); fileExists = false ; } // Construct the response message. 37
    • String serverLine = "Server: fpont simple java httpServer"; String statusLine = null; String contentTypeLine = null; String entityBody = null; String contentLengthLine = "error"; System.out.println("Reading file"); if ( fileExists ) { statusLine = "HTTP/1.0 200 OK" + CRLF ; contentTypeLine = "Content-type: " + contentType( fileName ) + CRLF ; contentLengthLine = "Content-Length: " + (new Integer(fis.available())).toString() + CRLF; } else { statusLine = "HTTP/1.0 404 Not Found" + CRLF ; contentTypeLine = "text/html" ; entityBody = "<HTML>" + "<HEAD><TITLE>404 Not Found</TITLE></HEAD>" + "<BODY>404 Not Found" +"<br>usage:http://yourHostName:port/" +"fileName.html</BODY></HTML>" ; } System.out.println("StatusLine"); // Send the status line. output.write(statusLine.getBytes()); System.out.println("ServerLine"); // Send the server line. output.write(serverLine.getBytes()); System.out.println("contentTypeLine"); // Send the content type line. output.write(contentTypeLine.getBytes()); System.out.println("contentLengthLine"); // Send the Content-Length output.write(contentLengthLine.getBytes()); System.out.println("CRLF"); // Send a blank line to indicate the end of the header lines. output.write(CRLF.getBytes()); // Send the entity body. if (fileExists) { System.out.println("SENDBYTES"); sendBytes(fis, output) ; fis.close(); } else { 38
    • output.write(entityBody.getBytes()); } } } try { output.close(); br.close(); socket.close(); } catch(Exception e) {} } private static void sendBytes(FileInputStream fis, OutputStream os) throws Exception { // Construct a 1K buffer to hold bytes on their way to the socket. byte[] buffer = new byte[1024] ; int bytes = 0 ; // Copy requested file into the socket's output stream. while ((bytes = fis.read(buffer)) != -1 ) { os.write(buffer, 0, bytes); } } private static String contentType(String fileName) { if (fileName.endsWith(".htm") || fileName.endsWith(".html")) { return "text/html"; } return ""; } } 39
    • A.4b HttpClient.java /* * This program is a test HTTP Client * Usage: java HttpClient <URL> [<Filename>] * It only supports http transfers */ import java.io.*; import java.net.*; import java.util.*; import java.lang.System; import java.lang.NoSuchMethodError; public class HttpClient { public static void get(String in, OutputStream out) throws Exception { String protocol, local, host, filename; int port; long sendtime; long recvtime; // use the URL class to parse the input URL url = new URL(in); protocol = url.getProtocol(); if (! protocol.equals("http")) // only support http throw new IllegalArgumentException("Only support HTTP protocol."); if ((host = url.getHost()) == null) throw new IllegalArgumentException("Invalid host specified."); // if no port, use the default HTTP port if ((port = url.getPort()) == -1) port = 80; // if no filename, request root directory index if((filename = url.getFile()) == "") filename = "/"; // open a network socket sendtime = System.currentTimeMillis(); Socket socket = new Socket(host, port); // get input and output streams from the socket InputStream from = socket.getInputStream(); PrintWriter to = new PrintWriter(socket.getOutputStream()); // send the HTTP GET v1.0 commands to the web server to.print("GET " + filename + " HTTP/1.0n"); System.out.println(filename); to.print("User-Agent: nonenn"); System.out.println("nTime Sent:"+sendtime); 40
    • to.flush(); // read server response and write it to the specified output stream byte[] buf = new byte[4096]; int bytes_read; while((bytes_read = from.read(buf)) != -1) out.write(buf, 0, bytes_read); recvtime = System.currentTimeMillis(); long timediff = recvtime - sendtime; System.out.println("Time taken by request:"+ timediff +" millisecondsn"); // close the server and file streams socket.close(); out.close(); } public static void main(String[] args) { String usage = "Usage: java HttpClient <URL> [<filename>]"; OutputStream out; try { // verify command line if ((args.length != 1) && (args.length != 2)) { System.err.println(usage); System.exit(-1); } // determine output stream if (args.length == 2) out = new FileOutputStream(args[1]); else out = System.out; // get the url HttpClient.get(args[0], out); } catch (Exception e) { System.err.println(e); System.err.println(usage); } } } 41
    • A.4c Kclient.java /* * This program is a test HTTP Client * Usage: java kclient <URL>/[<filename>] <ProxyIP> <ProxyPort> [<DestFile>] * It only supports http transfers */ import java.io.*; import java.net.*; import java.util.*; import java.lang.System; import java.lang.NoSuchMethodError; public class kclient { public static void get(String in, String proxyIP, String proxyPort, OutputStream out) throws Exception { String protocol, local, host, filename; int port; long sendtime; long recvtime; // use the URL class to parse the input URL url = new URL(in); protocol = url.getProtocol(); if (! protocol.equals("http")) // only support http throw new IllegalArgumentException("Only support HTTP protocol."); if ((host = url.getHost()) == null) throw new IllegalArgumentException("Invalid host specified."); // if no port, use the default HTTP port if ((port = url.getPort()) == -1) port = 80; // if no filename, request root directory index if((filename = url.getFile()) == "") filename = "/"; Integer pport = new Integer(proxyPort); sendtime = System.currentTimeMillis(); // open a network socket Socket socket = new Socket(proxyIP, pport.intValue()); // get input and output streams from the socket InputStream from = socket.getInputStream(); PrintWriter to = new PrintWriter(socket.getOutputStream()); // send the HTTP GET v1.0 commands to the web server to.print("GET " + in + " HTTP/1.0n"); to.flush(); System.out.println("nTime Sent:"+sendtime); 42
    • // read server response and write it to the specified output stream byte[] buf = new byte[4096]; int bytes_read; while((bytes_read = from.read(buf)) != -1) out.write(buf, 0, bytes_read); recvtime = System.currentTimeMillis(); long timediff = recvtime - sendtime; System.out.println("Time taken by Request:"+ timediff +" millisecondsn"); // close the server and file streams socket.close(); out.close(); } public static void main(String[] args) { String usage = "Usage: java kclient <URL>/[<filename>] <ProxyIP> <ProxyPort> [<DestFile>]"; OutputStream out; try { // verify command line if ((args.length != 3 && args.length != 4)) { System.err.println(usage); System.exit(-1); } if (args.length == 4) out = new FileOutputStream(args[3]); else out = System.out; // get the url kclient.get(args[0], args[1], args[2], out); } catch (Exception e) { System.err.println(e); System.err.println(usage); } } } 43
    • A.5a Proxy.c /* * This is a TCP proxy program. It proxies HTTP requests.Originally we intended * it to run as daemon, but due to some difficulties in designing clients which * were to be used for SOCKS implementation we have commented out the while * loop and the proxy services only one http request currently */ #include <sys/types.h> #include <sys/socket.h> #include <sys/time.h> #include <netinet/in.h> #include <netdb.h> #include <arpa/inet.h> #include <ctype.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> #define URLSIZE 1024 #define BUFSIZE 5120 main(int argc, char *argv[]) { int status; struct servent *servp; struct sockaddr_in proxySvr, remote; int proxySock, clientSock; int remoteNameLen; if (argc != 2) { /* the right command line should be like: % proxy 2200 */ (void) fprintf(stderr, "usage: %s service.n", argv[0]); exit(1); } /* proxy creat a socket to listen to browsers' requests */ if ((proxySock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { perror("Can't creat a socket.n"); exit(1); } if (isdigit(argv[1][0])) { static struct servent s; servp = &s; s.s_port = htons((u_short) atoi(argv[1])); } else if ((servp = getservbyname(argv[1], "tcp")) == 0) { 44
    • fprintf(stderr, "%s: unknown servicen"); exit(1); } memset((void*) &proxySvr, 0, sizeof proxySvr); proxySvr.sin_family = AF_INET; proxySvr.sin_addr.s_addr = INADDR_ANY; proxySvr.sin_port = servp->s_port; if (bind(proxySock, (struct sockaddr*) &proxySvr, sizeof proxySvr) < 0) { perror("bind"); exit(1); } if (listen(proxySock, SOMAXCONN) < 0) { perror("listen"); exit(1); } printf(" @@@@@ Proxy Server @@@@@n"); /* Service only one request */ //while(1) { remoteNameLen = sizeof(remote); clientSock = accept(proxySock, (struct sockaddr*) &remote, &remoteNameLen); if (clientSock < 0) { perror("Accept error.n"); exit(1); } if (fork() == 0) {/* hand over the handling to a child process */ //close(proxySock); /* close parent socket in child process */ handleRequest(clientSock); close (clientSock); exit(0); } //} //close(clientSock);/* close the new socket in parent process */ close(proxySock); exit(EXIT_SUCCESS); } /* end of the main founction */ int handleRequest(int sock) { struct sockaddr_in realServer; struct hostent *hostp; /* to save the items parsed from request string */ char host[URLSIZE], path[URLSIZE], url[URLSIZE], protocol[100], method[100]; char buf[BUFSIZE]; /* proxy buffer */ 45
    • char sendInfo[URLSIZE]; int bytesRead; int port, toServer; FILE *fp; char c; /* read browser's request string to buffer */ bytesRead=0; fp = fdopen(sock, "r"); while ((c = fgetc(fp)) != EOF) { putchar(c); buf[bytesRead]=c; bytesRead++; if (c == 'n') break; } if (bytesRead < 0) { perror("Read from client Error. n"); } printf ("Message read: %.*sn", bytesRead, buf); /* parse request string */ if (sscanf(buf, "%[^ ] %[^ ] %[^ ]", method, url, protocol) != 3) { perror("400, bad request. Can't parse request.n"); exit(1); } if (url == (char*) 0) { perror("400, bad request. Null URLn"); exit(1); } if (strncmp(url, "http://", 7) == 0) { /* confirm it's http request */ if (sscanf(url, "http://%[^:/]:%d%s", host, &port, path) == 3) ; else if (sscanf(url, "http://%[^/]%s", host, path) == 2) port = 80; else if (sscanf(url, "http://%[^:/]:%d", host, &port) == 2) *path = '0'; else if (sscanf(url, "http://%[^/]", host) == 1) { port = 80; *path = '0'; } else { perror("400, bad request.Can't parse URL.n" ); exit(1); } } else exit(1); /* exit if the request isn't http */ 46
    • /* proxy creat another socket for handing over browser's request to destination server */ if ((toServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { perror("From proxy to real server error. n"); exit(1); } memset((void *) &realServer, 0, sizeof realServer); realServer.sin_family = AF_INET; realServer.sin_port = htons(port); if ((hostp = gethostbyname(host)) == NULL) { fprintf(stderr, "Can't get server's address.n"); exit(1); } memcpy((char *) &realServer.sin_addr, hostp->h_addr, hostp->h_length); /* connect to destination server */ if (connect(toServer, (struct sockaddr *)&realServer, sizeof realServer) < 0) { (void) close(toServer); perror("Error in connecting to the real server.n"); exit(1); } /* /* request string--sendInfo="GET /path/doc.html HTTP/1.0" to destination server */ sprintf(sendInfo, "%s %s %snn", method, path, protocol); if (write(toServer, sendInfo, sizeof(sendInfo)) < 0) { perror("Can't send to server.n"); exit(1); } if (write(toServer, "User-Agent: nonenn",20) < 0) { perror("Can't send to server.n"); exit(1); } printf("Request is: %s", sendInfo); /* read response content to client buffer */ while ((bytesRead = read(toServer, buf, sizeof(buf))) > 0) { if (write(sock, buf, bytesRead) < 0) { perror("Writing to Client error.n"); exit(1); } } close(toServer); return 0; } 47
    • A.5b Sock_proxy.c /* * This program is a SOCKSified version of the HTTP proxy. It processes * only one request. The advantage of a socksified proxy is that you do not * have to break the clients. Only the proxy needs to be modified * SOCKS + TCP */ #include <sys/types.h> #include <sys/socket.h> #include <sys/time.h> #include <netinet/in.h> #include <netdb.h> #include <arpa/inet.h> #include <ctype.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> #define URLSIZE 1024 #define BUFSIZE 5120 #define SOCKS5_PORT 1080 #define SOCKS5_IP "35.8.18.199" struct supported_methods { char ver; // 4 if you want SOCKSv4, 5 if you require UDP char num_methods; // I'll talk about 2 methods char methods[2]; // 0 is NO AUTHENTICATION, and 2 is USERNAME/PASSWORD } first_msg_to_server; struct command { char ver; // same as above char cmd; // 1=CONNECT, 2=TCP BIND, 3=UDP BIND char reserved; // must be 0 char address_type; // 1=4 byte IP address, 3=domain name, 4=6 byte IP address in_addr_t address_data; unsigned short port; // should be in BIG ENDIAN format! } command_to_server; struct authenticate_me { char ver; // authentication version not proxy version unsigned char user_name_length; // 1..255 char uname[4]; // not NULL terminated! unsigned char password_length; char pword[8]; // not NULL terminated! } authentication_msg_to_server; struct command_reply { 48
    • char ver; // same as above char reply; // 0=success, 1-9 are error messages char reserved; char address_type; // 1=4 byte IP address, 3=domain name, 4=6 byte IP address in_addr_t bind_address_data; // depends on above address_type unsigned short bind_port; // BIG ENDIAN format! } reply_from_server; int handleRequest(int sock); main(int argc, char *argv[]) { int status; struct servent *servp; struct sockaddr_in proxySvr, remote; int proxySock, clientSock; int remoteNameLen; /* * Structure intializations */ first_msg_to_server.ver=5; first_msg_to_server.num_methods=2; first_msg_to_server.methods[0]=0; first_msg_to_server.methods[1]=2; command_to_server.ver=5; command_to_server.reserved=0; authentication_msg_to_server.ver=1; authentication_msg_to_server.user_name_length=strlen("user"); strcpy(authentication_msg_to_server.uname,"user"); authentication_msg_to_server.password_length=strlen("password"); strcpy(authentication_msg_to_server.pword,"password"); if (argc != 2) { /* the right command line should be like: % proxy 2200 */ (void) fprintf(stderr, "usage: %s service.n", argv[0]); exit(1); } /* proxy creat a socket to listen to browsers' requests */ if ((proxySock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { perror("Can't creat a socket.n"); exit(1); } if (isdigit(argv[1][0])) { static struct servent s; servp = &s; s.s_port = htons((u_short) atoi(argv[1])); } 49
    • else if ((servp = getservbyname(argv[1], "tcp")) == 0) { fprintf(stderr, "%s: unknown servicen"); exit(1); } memset((void*) &proxySvr, 0, sizeof proxySvr); proxySvr.sin_family = AF_INET; proxySvr.sin_addr.s_addr = INADDR_ANY; proxySvr.sin_port = servp->s_port; if (bind(proxySock, (struct sockaddr*) &proxySvr, sizeof proxySvr) < 0) { perror("bind"); exit(1); } if (listen(proxySock, SOMAXCONN) < 0) { perror("listen"); exit(1); } printf(" @@@@@ Proxy Server @@@@@n"); //while(1) { remoteNameLen = sizeof(remote); clientSock = accept(proxySock, (struct sockaddr*) &remote, &remoteNameLen); if (clientSock < 0) { perror("Accept error.n"); exit(1); } if (fork() == 0) {/* hand over the handling to a child process */ handleRequest(clientSock); close (clientSock); exit(0); } //} close(proxySock); exit(EXIT_SUCCESS); } /* end of the main founction */ int handleRequest(int sock) { struct sockaddr_in SOCKS5Server; struct hostent *hostp; /* to save the items parsed from request string */ char host[URLSIZE], path[URLSIZE], url[URLSIZE], protocol[100], method[100]; char buf[BUFSIZE]; /* proxy buffer */ char sendInfo[URLSIZE]; int bytesRead,i; 50
    • int port, toSOCKS5Server; FILE *fp, *fpSOCKS5; char c, cSOCKS5; /* read browser's request string to buffer */ bytesRead=0; fp = fdopen(sock, "r"); while ((c = fgetc(fp)) != EOF) { putchar(c); buf[bytesRead]=c; bytesRead++; if (c == 'n') break; } if (bytesRead < 0) { perror("Read from client Error. n"); } printf ("Message read: %.*sn", bytesRead, buf); /* parse request string */ if (sscanf(buf, "%[^ ] %[^ ] %[^ ]", method, url, protocol) != 3) { perror("400, bad request. Can't parse request.n"); exit(1); } if (url == (char*) 0) { perror("400, bad request. Null URLn"); exit(1); } if (strncmp(url, "http://", 7) == 0) { /* confirm it's http request */ if (sscanf(url, "http://%[^:/]:%d%s", host, &port, path) == 3) ; else if (sscanf(url, "http://%[^/]%s", host, path) == 2) port = 80; else if (sscanf(url, "http://%[^:/]:%d", host, &port) == 2) *path = '0'; else if (sscanf(url, "http://%[^/]", host) == 1) { port = 80; *path = '0'; } else { perror("400, bad request.Can't parse URL.n" ); exit(1); } } else exit(1); /* exit if the request isn't http */ /* proxy creat another socket for handing over browser's request to destination server */ 51
    • if ((toSOCKS5Server = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("From proxy to real server error. n"); exit(1); } SOCKS5Server.sin_family = AF_INET; SOCKS5Server.sin_port = htons(SOCKS5_PORT); SOCKS5Server.sin_addr.s_addr=inet_addr(SOCKS5_IP); /* connect to destination server */ if (connect(toSOCKS5Server, (struct sockaddr *)&SOCKS5Server, sizeof (SOCKS5Server)) < 0) { (void) close(toSOCKS5Server); perror("Error in connecting to the real server.n"); exit(1); } printf ("Connection Established SUCCESSFULLYn"); printf ("SENDING first messagen"); /* * Tell the proxy server which authentication methods you support */ send(toSOCKS5Server, &first_msg_to_server, sizeof(first_msg_to_server), 0); printf ("first message SENTn"); /* * We'll use stdio for reading * the socket. */ fpSOCKS5 = fdopen(toSOCKS5Server, "r"); /* * Read the 2 byte response from server */ cSOCKS5=fgetc(fpSOCKS5); printf("SOCKS server version:%dn", cSOCKS5); cSOCKS5=fgetc(fpSOCKS5); if (cSOCKS5==0) { printf("Authentication not requiredn"); } else { printf("Sending authentication message to servern"); send(toSOCKS5Server, &authentication_msg_to_server, sizeof(authentication_msg_to_server), 0); } /* * Send a request to connect to SERVICE PROVIDER */ command_to_server.cmd = 1; /* TCP connect */ command_to_server.address_type = 1; /* 4 byte IP address */ command_to_server.address_data=inet_addr(host); 52
    • command_to_server.port=htons(port); send(toSOCKS5Server, &command_to_server, sizeof(command_to_server), 0); /* * Read reply from server */ fread(&reply_from_server, sizeof(reply_from_server), 1, fpSOCKS5); if (reply_from_server.reply==0) { printf("SUCCESSFULLY setup connection with service providern"); } else { printf ("connection with service provider FAILEDn"); exit(0); } /* /* request string--sendInfo="GET /path/doc.html HTTP/1.0" to destination server */ sprintf(sendInfo, "%s %s %snUser-Agent: nonenn", method, path, protocol); i=0; while (sendInfo[i]!=0) { printf("%d",sendInfo[i]); i++; } printf("n"); if (write(toSOCKS5Server, sendInfo, sizeof(sendInfo)) < 0) { perror("Can't send to server.n"); exit(1); } printf("Request is: %s", sendInfo); /* read response content to client buffer */ while ((bytesRead = read(toSOCKS5Server, buf, sizeof(buf))) > 0) { if (write(sock, buf, bytesRead) < 0) { perror("Writing to Client error.n"); exit(1); } } close(toSOCKS5Server); return 0; } 53
    • Appendix B B.1 Chart for Table 1: Comparing SOCKS performance to direct socket connection 12000 10000 8000 time (ms) Direct (Figure 2) 6000 Direct to SOCKS (Figure 3) 4000 2000 0 100KB 1MB 10MB 100MB strings File Size 54
    • B.2 Chart for Table 2: Comparing SOCKSification of clients Vs SOCKSification of proxy (+ Java based Tunneling) 45000 40000 35000 30000 25000 time (ms) Direct (Figure 2) Via Proxy (Figure 4) 20000 Via SOCKS proxy (Figure 5) 15000 10000 5000 0 100KB 1MB 10MB 100MB Java Tunneling File sizes 55
    • References 56
    • 1 “Firewall Vulnerability and Network Protection for Streamin and Emerging UDP Appliactions” Network Systems Laboratory, NEC USA, Inc. 2 http://www.socks.nec.com/rfc/rfc1928.txt “SOCKS Protocol Version 5”, M. Leech, M. Ganis, Y. Lee, R. Kuris, D. Koblas, L. Jones 3 Web Services – Beyond HTTP Tunneling Patrick Thompson, Rogue Wave Software http://www.w3.org/2001/03/WSWS-popa/paper35 4 http://www.sparkplug.com/portfolio/nec/site/about/product-summary.html 5 http://www.socks.nec.com 6 http://jonathanclark.com/diary/firewalls/ “Making your game work with Firewalls”, Jonathan Clark 7 http://www.socks.nec.com/guidelines.html “Guidelines for networking applications in the SOCKS v5 environment” 8 http://www.socks.nec.com/how2socksify.html “How to SOCKSify clients” 9 http://www.linuxdoc.org/HOWTO/Firewall-HOWTO.html “Firewall and Proxy Server HOWTO”, Mark Grennan 10 http://developer.java.sun.com/developer/technicalArticles/InnerWorkings/Burrowing/index.html “Burrowing Through Firewalls” Venkat Rao, JavaSoft and Mary Aline