Implement without following RFC1928.Only for interest.
共有五个函数,main,parse_args,init_daemon,do_proxy,error_quit.
parse_args : 处理命令行参数,初始化一些变量,即代理服务器本身端口proxy_port,
代理的远端主机sockaddr结构变量hostaddr.
init_daemon : 使用fork变成守护进程。
error_quit : 由于守护进程把stdin,stdout,stderr都关了,so need a function
to display error message on the console.
do_proxy : 代理处理。客户与代理服务器建立连接(usersockfd),代理服务器与客户
请求的服务器建立连接(remote_sockfd),所以此函数把一个socket的输出送到另一个
socket的输入,相反亦是如此。
1 /*
2 A simple proxy server
3 Copyright (C) 2005 by kf_701
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
19 The author can be reached as follows:
20 E_mail: kf_701@21cn.com
21 Address: hefei of china
22 Phone: 0551-2150103
23 */
24 #include <stdio.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include <ctype.h>
28 #include <errno.h>
29 #include <signal.h>
30 #include <unistd.h>
31 #include <sys/stat.h>
32 #include <sys/param.h>
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <sys/ioctl.h>
36 #include <.netinet/in.h>
37 #include <arpa/inet.h>
38 #include <sys/wait.h>
39 #include <netdb.h>
40
41 #define TCP_PROTO "tcp"
42 #define MAXFD 64
43
44 unsigned short proxy_port;
45 struct sockaddr_in hostaddr; /* remote host addr */
46
47 void parse_args(int argc,char **argv); /* deal with arguments */
48 void init_daemon(void); /* become daemon */
49 void do_proxy(int usersockfd); /* main proxy process */
50 void error_quit(char *msg); /* print error message for daemon */
51
52 int main(int argc,char **argv)
53 {
54 int clilen;
55 int childpid;
56 int sockfd,newsockfd;
57 struct sockaddr_in servaddr,cliaddr;
58
59 parse_args(argc,argv);
60 init_daemon();
61
62 /* prepare servaddr for listening client */
63 bzero((char*)&servaddr,sizeof(servaddr));
64 servaddr.sin_family = AF_INET;
65 servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
66 servaddr.sin_port = proxy_port;
67
68 /* socket,bind,listen */
69 if((sockfd = socket(AF_INET,SOCK_STREAM,0))<0)
70 error_quit("failed to create server socket");
71 if(bind(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr))<0)
72 error_quit("failed to bind server socket");
73 listen(sockfd,5);
74
75 while(1){
76 clilen = sizeof(cliaddr);
77 newsockfd = aclearcase/" target="_blank" >ccept(sockfd,(struct sockaddr *)&cliaddr,&clilen);
78 if(newsockfd<0 && errno == EINTR)
79 continue;
80 else if(newsockfd < 0)
81 error_quit("failed to accept connection");
82
83 if((childpid = fork()) == 0){
84 close(sockfd);
85 do_proxy(newsockfd); /* proxy main process */
86 exit(0);
87 }
88 /* if fork failed,close connection */
89 close(newsockfd);
90 }
91 }
92
93 void parse_args(int argc,char **argv)
94 {
95 int i;
96 struct hostent *hostp;
97 struct servent *servp;
98 unsigned long inaddr;
99 struct{
100 char proxy_port[16];
101 char isolated_host[64];
102 char service_name[32];
103 }pargs;
104
105 /* invalid arguments */
106 if(argc<4){
107 printf("usage: %s <proxy_port><host><service_name|port_number>\n",argv[0]);
108 exit(1);
109 }
110
111 /* save arguments to pargs struct */
112 strcpy(pargs.proxy_port,argv[1]);
113 strcpy(pargs.isolated_host,argv[2]);
114 strcpy(pargs.service_name,argv[3]);
115
116 /* check argv[1] and set global proxy_port */
117 for(i=0;i<strlen(pargs.proxy_port);i++)
118 if(!isdigit(*(pargs.proxy_port+i)))
119 break;
120 if(i == strlen(pargs.proxy_port))
121 proxy_port = htons(atoi(pargs.proxy_port));
122 else{
123 printf("%s: invalid proxy port\n",pargs.proxy_port);
124 exit(1);
125 }
126
127 /* set global hostaddr */
128 bzero(&hostaddr,sizeof(hostaddr));
129 hostaddr.sin_family = AF_INET;
130 /* set sin_addr for hostaddr */
131 if((inaddr = inet_addr(pargs.isolated_host)) != INADDR_NONE)
132 bcopy(&inaddr,&hostaddr.sin_addr,sizeof(inaddr));
133 else if((hostp = gethostbyname(pargs.isolated_host)) != NULL)
134 bcopy(hostp->h_addr,&hostaddr.sin_addr,hostp->h_length);
135 else{
136 printf("%s:unknown host\n",pargs.isolated_host);
137 exit(1);
138 }
139 /* set sin_port for hostaddr */
140 if((servp = getservbyname(pargs.service_name,TCP_PROTO)) != NULL)
141 hostaddr.sin_port = servp->s_port;
142 else if(atoi(pargs.service_name) > 0)
143 hostaddr.sin_port = htons(atoi(pargs.service_name));
144 else{
145 printf("%s:invalid/unknown service name or port number\n",pargs.service_name);
146 exit(1);
147 }
148 }
149
150 void init_daemon(void)
151 {
152 pid_t pid;
153 int i;
154
155 if((pid = fork())) /*exit terminal*/
156 exit(0);
157 else if(pid<0)
158 exit(1);
159
160 setsid(); /*become session leader*/
161
162 /* when session leader terminate,all
163 process of session will receive SIGHUP */
164 if(signal(SIGHUP,SIG_IGN) == SIG_ERR)
165 exit(1);
166
167 if((pid=fork())) /*prevent daemon opening terminal*/
168 exit(0);
169 else if(pid<0)
170 exit(1);
171
172 for(i=0;i<MAXFD;++i) /*close fds opened by parent*/
173 {
174 close(i);
175 }
176
177 chdir("/"); /*leave working dir*/
178
179 umask(0); /*create file mask*/
180
181 return;
182 }
183
184 void do_proxy(int usersockfd)
185 {
186 int remote_sockfd;
187 fd_set rdfdset;
188 int conn;
189 int iolen;
190 char buf[2048];
191
192 /* connect remote server for the client */
193 if((remote_sockfd = socket(AF_INET,SOCK_STREAM,0))<0)
194 error_quit("failed to create socket to host");
195 conn = connect(remote_sockfd,(struct sockaddr *)&hostaddr,sizeof(hostaddr));
196 switch(conn){
197 case 0: /* successed */
198 break;
199 case -1: /* bad luck */
200 strcpy(buf,strerror(errno));
201 strcat(buf,"\r\n");
202 write(usersockfd,buf,strlen(buf));
203 close(usersockfd);
204 exit(1);
205 break;
206 default:
207 error_quit("failed to connect to host");
208 }
209
210 /* all right,start real work now */
211 while(1){
212 FD_ZERO(&rdfdset);
213 FD_SET(usersockfd,&rdfdset);
214 FD_SET(remote_sockfd,&rdfdset);
215
216 if(select(FD_SETSIZE,&rdfdset,NULL,NULL,NULL)<0)
217 error_quit("select failed");
218
219 /* detect data from client and send it to server */
220 if(FD_ISSET(usersockfd,&rdfdset)){
221 if((iolen = recv(usersockfd,buf,sizeof(buf),0))<=0)
222 break;
223 send(remote_sockfd,buf,iolen,0);
224 }
225
226 /* detect data from server and send it to client */
227 if(FD_ISSET(remote_sockfd,&rdfdset)){
228 if((iolen = recv(remote_sockfd,buf,sizeof(buf),0))<=0)
229 break;
230 send(usersockfd,buf,iolen,0);
231 }
232 }
233
234 close(remote_sockfd);
235 close(usersockfd);
236 }
237
238 void error_quit(char *msg)
239 {
240 FILE *console;
241 console = fopen("/dev/console","a");
242 fprintf(console,"proxyd:%s\r\n",msg);
243 fclose(console);
244 exit(1);
245 }