1 /* Socks Server 5
2  * Copyright (C) 2002 - 2011 by Matteo Ricchetti - <matteo.ricchetti@libero.it>
3 
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17  */
18 
19 
20 #include"SS5Main.h"
21 #include"SS5Mod_dump.h"
22 #include"SS5Utils.h"
23 
24 char *ss5ver=SS5_VERSION;
25 
InitModule(struct _module * m)26 UINT InitModule( struct _module *m )
27 {
28   m->AddDump     = AddDump;
29   m->FreeDump    = FreeDump;
30   m->GetDump     = GetDump;
31   m->OpenDump    = OpenDump;
32   m->WritingDump = WritingDump;
33   m->CloseDump   = CloseDump;
34   m->SrvDump     = SrvDump;
35   m->ListDump    = ListDump;
36 
37   return OK;
38 }
39 
ListDump(UINT s)40 UINT ListDump( UINT s)
41 {
42   UINT count;
43 
44   struct _S5DumpNode *node, *lnode;
45 
46   char buf[53];
47 
48   for(count = 0;count < MAXDUMPLIST; count++) {
49     if( (node=S5DumpList[count]) != NULL) {
50 
51       lnode=node;
52       do {
53         if(lnode != NULL ) {
54           snprintf(buf,sizeof(buf),"%16lu\n%2u\n%16lu\n%5u\n%5u\n%1u\n%1u\n", lnode->DstAddr,lnode->Mask,lnode->DstPort,
55              lnode->DstRangeMin,lnode->DstRangeMax,lnode->DumpDir,lnode->DumpMode);
56           lnode=lnode->next;
57         }
58 
59         if( send(s,buf,sizeof(buf),0) == -1) {
60           perror("Send err:");
61           return ERR;
62         }
63 
64       } while( lnode != NULL );
65     }
66   }
67   return OK;
68 }
69 
SrvDump(struct _SS5ClientInfo * ci,struct _SS5Socks5Data * sd)70 INT SrvDump( struct _SS5ClientInfo *ci, struct _SS5Socks5Data *sd )
71 {
72   UINT dstMask,sdr,dct;
73 
74   char da[64],dp[16],dc[1],dm[1], srvResponse[16];
75 
76   if( STREQ(sd->MethodRequest,"ET /list=DUMP HTTP/1.",sizeof("ET /list=DUMP HTTP/1.") - 1) ) {
77     ListDump(ci->Socket);
78     return OK;
79   }
80   else if( STREQ(sd->MethodRequest,"DD /dump=",sizeof("DD /dump=") - 1) ) {
81 
82     sscanf(sd->MethodRequest,"DD /dump=%64s\n%16s\n%1s\n%1s\n",da,dp,dc,dm);
83 
84     dstMask=S5GetNetmask(da);
85 
86     switch(dm[0]) {
87       case 'r':     sdr=0;     break;
88       case 't':     sdr=1;     break;
89       case 'b':     sdr=2;     break;
90       default:      sdr=0;     break;
91     }
92 
93     switch(dc[0]) {
94       case 's':     dct=0;     break;
95       case 'd':     dct=1;     break;
96       default:      dct=0;     break;
97     }
98 
99     if( da[0] > 64 ) {
100       if( AddDump(ONLINE,S5StrHash(da),S5GetRange(dp),dct,sdr,32-dstMask) && (NDumpList < MAXDUMPLIST)) {
101         strncpy(srvResponse,"OK\0",sizeof("OK\0"));
102         NDumpList++;
103         SS5SocksOpt.IsDump = OK;
104       }
105       else
106         strncpy(srvResponse,"ERR\0",sizeof("ERR\0"));
107     }
108     else {
109       if( AddDump(ONLINE,inet_network(da),S5GetRange(dp),dct,sdr,32-dstMask) && (NDumpList < MAXDUMPLIST)) {
110         strncpy(srvResponse,"OK\0",sizeof("OK\0"));
111         NDumpList++;
112         SS5SocksOpt.IsDump = OK;
113       }
114       else
115         strncpy(srvResponse,"ERR\0",sizeof("ERR\0"));
116     }
117 
118     if( send(ci->Socket,srvResponse,strlen(srvResponse),0) == -1) {
119       perror("Send err:");
120       return ERR;
121     }
122     return OK;
123   }
124   else if( STREQ(sd->MethodRequest,"DEL /dump=",sizeof("DEL /dump=") - 1) ) {
125 
126     sscanf(sd->MethodRequest,"DEL /dump=%64s\n%16s\n%1s\n",da,dp,dm);
127 
128     dstMask=S5GetNetmask(da);
129 
130     if( da[0] > 64 ) {
131       if( DelDump(S5StrHash(da),S5GetRange(dp),32-dstMask) && (NDumpList < MAXDUMPLIST)) {
132         strncpy(srvResponse,"OK\0",sizeof("OK\0"));
133         NDumpList++;
134         SS5SocksOpt.IsDump = OK;
135       }
136       else
137         strncpy(srvResponse,"ERR\0",sizeof("ERR\0"));
138     }
139     else {
140       if( DelDump(inet_network(da),S5GetRange(dp),32-dstMask) && (NDumpList < MAXDUMPLIST)) {
141         strncpy(srvResponse,"OK\0",sizeof("OK\0"));
142         NDumpList++;
143         SS5SocksOpt.IsDump = OK;
144       }
145       else
146         strncpy(srvResponse,"ERR\0",sizeof("ERR\0"));
147     }
148 
149     if( send(ci->Socket,srvResponse,strlen(srvResponse),0) == -1) {
150       perror("Send err:");
151       return ERR;
152     }
153     return OK;
154   }
155 
156   return ERR_SRV_REQUEST;
157 }
158 
159 UINT
WritingDump(FILE * df,struct _SS5ProxyData * pd,UINT dumpMode)160 WritingDump( FILE *df, struct _SS5ProxyData *pd, UINT dumpMode )
161 {
162   char headerTitle[128];
163 
164   static UINT tx=0;
165   static UINT rx=0;
166 
167   /*
168    * TX
169    */
170   if( pd->Fd == 0 ) {
171     if( (dumpMode == TX) || (dumpMode == RTX) ) {
172       if( tx == 0 ) {
173         sprintf(headerTitle,"\n------------------------------ TX SEGMENT ------------------------------\n");
174         fwrite(headerTitle,sizeof(char),strlen(headerTitle),df);
175         tx++;
176         rx = 0;
177       }
178 
179       fwrite(pd->Recv,sizeof(char),pd->TcpRBufLen,df);
180     }
181   }
182   /* RX */
183   else {
184     if( (dumpMode == RX) || (dumpMode == RTX) ) {
185       if( rx == 0 ) {
186         sprintf(headerTitle,"\n------------------------------ RX SEGMENT ------------------------------\n");
187         fwrite(headerTitle,sizeof(char),strlen(headerTitle),df);
188         rx++;
189         tx = 0;
190       }
191 
192       fwrite(pd->Recv,sizeof(char),pd->TcpRBufLen,df);
193     }
194   }
195   return OK;
196 }
197 
198 UINT
OpenDump(FILE ** df,struct _SS5ClientInfo * ci)199 OpenDump( FILE **df, struct _SS5ClientInfo *ci )
200 {
201   char logString[128];
202   char dumpFileName[64];
203   char timeLog[32];
204 
205   pid_t pid;
206 
207   time_t now;
208   now = time(NULL);
209 
210   /*
211    *    Get child/thread pid
212    */
213   if( NOTTHREADED() )
214     pid=getpid();
215   else
216     pid=(UINT)(uintmax_t)pthread_self();
217 
218   strftime(timeLog,sizeof(timeLog),"%d-%b-%Y-%H-%M-%S",localtime(&now));
219 
220   sprintf(dumpFileName,"%s/ss5.%s.%u.%s.trc",S5TracePath,timeLog,pid,ci->Username);
221 
222   if( (*df = fopen(dumpFileName,"wb")) == NULL ) {
223     ERRNO(pid)
224     return ERR;
225   }
226   else
227     return OK;
228 }
229 
230 UINT
CloseDump(FILE * df)231 CloseDump( FILE *df )
232 {
233 
234   fflush(df);
235   fclose(df);
236 
237   return OK;
238 }
239 
240 /* ***************************** HASH for DUMP **************************** */
S5DumpHash(ULINT da,UINT dp)241 inline UINT S5DumpHash( ULINT da, UINT dp )
242 {
243   register int idx;
244   register int len;
245 
246   register long int hashVal = 0;
247 
248   char s[32];
249 
250   snprintf(s,sizeof(s) - 1,"%lu%u",da,dp);
251 
252   len = strlen(s);
253   for(idx = 0; idx < len; idx++)
254     hashVal = 37*hashVal + s[idx];
255 
256   hashVal %= MAXDUMPLIST;
257   if(hashVal < 0)
258     hashVal += MAXDUMPLIST;
259 
260   return hashVal;
261 
262 }
263 
GetDump(ULINT sa,UINT sp,ULINT da,UINT dp,struct _SS5DumpInfo * di)264 UINT GetDump(ULINT sa, UINT sp, ULINT da, UINT dp, struct _SS5DumpInfo *di)
265 {
266   register UINT index,nm;
267 
268   register ULINT n_da;
269 
270   struct _S5DumpNode *node;
271 
272   /* Look for SRC DUMP */
273 
274   for(nm=0;nm<=32;nm++) {
275     if( nm < 32)
276       n_da=((sa >> nm) << nm);
277     else
278       n_da=0;
279 
280     index=S5DumpHash( n_da, sp );
281 
282     if( S5DumpList[index]!= NULL ) {
283       node=S5DumpList[index];
284       do {
285         if( (node->DstAddr == n_da) && (node->Mask == (nm)) && (node->DstPort == sp) && (node->DumpDir == SRC_DUMP) ) {
286           di->DumpMode=node->DumpMode;
287           di->DumpDir=node->DumpDir;
288           return OK;
289         }
290         node=node->next;
291       } while(node != NULL );
292     }
293   }
294 
295   for(nm=0;nm<=32;nm++) {
296     if( nm < 32)
297       n_da=((sa >> nm) << nm);
298     else
299       n_da=0;
300 
301     index=S5DumpHash( n_da, 0 );
302 
303     if( S5DumpList[index]!= NULL ) {
304       node=S5DumpList[index];
305       do {
306         if( (node->DstAddr == n_da) && (node->Mask == (nm)) && (sp >= node->DstRangeMin) && (sp <= node->DstRangeMax) && (node->DumpDir == SRC_DUMP) ) {
307           di->DumpMode=node->DumpMode;
308           di->DumpDir=node->DumpDir;
309           return OK;
310         }
311         node=node->next;
312       } while(node != NULL );
313     }
314   }
315 
316   /* Look for DST DUMP */
317 
318   for(nm=0;nm<=32;nm++) {
319     if( nm < 32)
320       n_da=((da >> nm) << nm);
321     else
322       n_da=0;
323 
324     index=S5DumpHash( n_da, dp );
325 
326     if( S5DumpList[index]!= NULL ) {
327       node=S5DumpList[index];
328       do {
329         if( (node->DstAddr == n_da) && (node->Mask == (nm)) && (node->DstPort == dp) && (node->DumpDir == DST_DUMP) ) {
330           di->DumpMode=node->DumpMode;
331           di->DumpDir=node->DumpDir;
332           return OK;
333         }
334         node=node->next;
335       } while(node != NULL );
336     }
337   }
338 
339   for(nm=0;nm<=32;nm++) {
340     if( nm < 32)
341       n_da=((da >> nm) << nm);
342     else
343       n_da=0;
344 
345     index=S5DumpHash( n_da, 0 );
346 
347     if( S5DumpList[index]!= NULL ) {
348       node=S5DumpList[index];
349       do {
350         if( (node->DstAddr == n_da) && (node->Mask == (nm)) && (dp >= node->DstRangeMin) && (dp <= node->DstRangeMax) && (node->DumpDir == DST_DUMP) ) {
351           di->DumpMode=node->DumpMode;
352           di->DumpDir=node->DumpDir;
353           return OK;
354         }
355         node=node->next;
356       } while(node != NULL );
357     }
358   }
359 
360   return ERR;
361 }
362 
DelDump(ULINT da,ULINT dp,UINT mask)363 UINT DelDump(ULINT da, ULINT dp, UINT mask )
364 {
365   int index;
366   struct _S5DumpNode *node, *prevnode=NULL;
367 
368   if( dp > 65535 )
369     index=S5DumpHash( da, 0 );
370   else
371     index=S5DumpHash( da, dp );
372 
373 
374   node=S5DumpList[index];
375 
376   if( node == NULL )
377     return ERR;
378 
379   if( (node->DstAddr == da) && (node->Mask == mask) && (dp == node->DstPort) ) {
380     if( node->next == NULL ) {
381 
382       free(node);
383       S5DumpList[index]=NULL;
384       return OK;
385     }
386     else {
387       S5DumpList[index]=node->next;
388       free(node);
389       return OK;
390     }
391   }
392 
393   while( node->next != NULL ) {
394     prevnode=node;
395     node=node->next;
396 
397     if( (node->DstAddr == da) && (node->Mask == mask) && (dp == node->DstPort) ) {
398       if( node->next != NULL )
399         prevnode->next=node->next;
400       else
401         prevnode->next=NULL;
402 
403       free(node);
404       node=NULL;
405 
406       return OK;
407     }
408   }
409   return ERR;
410 }
411 
412 
AddDump(UINT ctx,ULINT da,ULINT dp,UINT dumpDir,UINT dumpMode,UINT mask)413 UINT AddDump(UINT ctx, ULINT da, ULINT dp, UINT dumpDir, UINT dumpMode, UINT mask )
414 {
415   int index;
416   struct _S5DumpNode *node, *prevnode;
417 
418   if( dp > 65535 )
419     index=S5DumpHash( da, 0 );
420   else
421     index=S5DumpHash( da, dp );
422 
423   if( ctx == OFFLINE )
424     node=_tmp_S5DumpList[index];
425   else
426     node=S5DumpList[index];
427 
428   if( node == NULL ) {
429     if( (node=(struct _S5DumpNode *)calloc(1,sizeof(struct _S5DumpNode))) == NULL )
430       return ERR;
431 
432     node->Mask=mask;
433     node->DstAddr=da;
434 
435     if( dp > 65535 ) {
436       node->DstPort=dp;
437       node->DstRangeMax=dp;
438       node->DstRangeMax >>= 16;
439       node->DstRangeMax <<= 16;
440       node->DstRangeMin = dp - node->DstRangeMax;
441       node->DstRangeMax >>= 16;
442 
443     }
444     else
445       node->DstPort=dp;
446 
447     node->DumpDir=dumpDir;
448     node->DumpMode=dumpMode;
449     node->next=NULL;
450 
451     if( ctx == OFFLINE )
452       _tmp_S5DumpList[index]=node;
453     else
454       S5DumpList[index]=node;
455   }
456   else {
457     if( ctx == OFFLINE )
458       node=_tmp_S5DumpList[index];
459     else
460       node=S5DumpList[index];
461 
462     do {
463       if( (node->DstAddr == da) && (node->Mask == mask) && (node->DstPort == dp) ) {
464         return ERR;
465       }
466       prevnode=node;
467       node=node->next;
468 
469     } while(node != NULL );
470 
471     if( (node=(struct _S5DumpNode *)calloc(1,sizeof(struct _S5DumpNode))) == NULL )
472       return ERR;
473 
474     node->Mask=mask;
475     node->DstAddr=da;
476 
477   if( dp > 65535 ) {
478       node->DstPort=dp;
479       node->DstRangeMax=dp;
480       node->DstRangeMax >>= 16;
481       node->DstRangeMax <<= 16;
482       node->DstRangeMin = dp - node->DstRangeMax;
483       node->DstRangeMax >>= 16;
484     }
485     else
486       node->DstPort=dp;
487 
488     node->DumpMode=dumpMode;
489     node->DumpDir=dumpDir;
490     node->next=NULL;
491 
492     prevnode->next=node;
493   }
494   return OK;
495 }
496 
FreeDump(struct _S5DumpNode ** node)497 UINT FreeDump( struct _S5DumpNode **node )
498 {
499   struct _S5DumpNode *lnode;
500   struct _S5DumpNode *lnode_prev=NULL;
501 
502   lnode=*node;
503 
504   if( lnode != NULL ) {
505     do {
506       while( lnode->next != NULL ) {
507         lnode_prev=lnode;
508         lnode=lnode->next;
509       }
510       free(lnode);
511       if( lnode_prev != NULL ) {
512         lnode_prev->next=NULL;
513         lnode=lnode_prev;
514         lnode_prev=NULL;
515       }
516       else
517         lnode=NULL;
518     } while( (lnode) != NULL );
519   }
520   *node=NULL;
521 
522   return OK;
523 
524 }
525 
526