aboutsummaryrefslogtreecommitdiffstats
path: root/src/libexec/socks4a-proxy.c
blob: a179d402a8c52909c759008e6f067e6eb51992f1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#include <stdio.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <errno.h>
#include <sys/wait.h>
#include <syslog.h>
#include <netdb.h>

int main(int argc,char *argv[]) {
 unsigned char vn;//version
 unsigned char cd;//command
 unsigned short dstport;
 unsigned int dstip;
 unsigned char in;
 int i;
 int status;
 char *name[5];
 char user[256];
 char sport[10];//10 is more than enough. it is converted from a short with %d
 char host[256];//https://blogs.msdn.microsoft.com/oldnewthing/20120412-00/?p=7873/
 read(0,&vn,1);
 //fprintf(stderr,"version number: %d\n",vn);
 if(vn != 4) {
   //fprintf(stderr,"received wrong version number. needs to be 4.\n");
   write(1,"\x00\x5b\xde\xca\xf0\xc0\xff\xee",8);//the decaf0coffee is supposed to be ignored by clients.
   return 1;
 }
 read(0,&cd,1);
 //fprintf(stderr,"command code: %d\n",cd);
 if(cd != 1) {
   //fprintf(stderr,"only going to implement command code 1 (connect) atm.\n");
   write(1,"\x00\x5b\xde\xca\xf0\xc0\xff\xee",8);//the response is in the same format as the request. vn+cd+port+ip
   return 2;
 }
 read(0,&dstport,2);
 //fprintf(stderr,"dstport: %d\n",ntohs(dstport));
 read(0,&dstip,4);
 //fprintf(stderr,"dstip: %d\n",ntohl(dstip));
 for(i=0;i<254;i++) {
  read(0,user+i,1);
  if(!user[i]) break;//we read a null, let's hop out.
 }
 if(user[i]) {//we didn't read the whole thing. truncate and just ignore the rest.
  user[i]=0;
  while(read(0,&in,1) > 0) {
   if (in == 0) break;
  }
 }
 //fprintf(stderr,"user: %s\n",user);
 //do some sort of auth here...
 //pass it off to a script?
 if(argc>2) {//we have an argument for the script to run auth against.
  //what do we need to pass? the port we're on, the port they connected from
  switch(fork()) {
   case -1:
    return errno;
   case 0://child.
    name[0]=argv[2];
    name[1]=user;
    name[2]=0;
    execv(name[0],name);
    return errno;
   default:
    break;
  }
  wait(&status);
 }
 if(WEXITSTATUS(status)) {//anything but 0 is an error.
  write(1,"\x00\x5b\xde\xca\xf0\xc0\xff\xee",8);
  return 3;
 }
 if(ntohl(dstip) < 256) { //this should match for an address that is 0.0.0.x where x could be anything.
  //do what we did for user, but with a hostname now.
  for(i=0;i<254;i++) {
   read(0,host+i,1);
   if(!host[i]) break;
  }
  if(host[i]) {//we didn't read the whole thing. truncate and just ignore the rest.
   host[i]=0;
   while(read(0,&in,1) > 0) {
    if (in == 0) break;
   }
  }
  //fprintf(stderr,"host: %s\n",host);
 }
 struct sockaddr_in6 sa6;
 unsigned int sl=sizeof(sa6);
 char h[NI_MAXHOST], s[NI_MAXSERV];
 if(getpeername(argc>1?atoi(argv[1]):0,(struct sockaddr *)&sa6,&sl) == -1) return 1;
 if(getnameinfo((struct sockaddr *)&sa6,sl,h,sizeof(h),s,sizeof(s),NI_NUMERICHOST|NI_NUMERICSERV)) return 2;

 syslog(LOG_WARNING,"proxy request: %s@%s:%s => %s:%d",user,h,s,host,ntohs(dstport));
 //fprintf(stderr,"got passed all that shit...\n");
 write(1,"\x00\x5a\xde\xca\xf0\xc0\xff\xee",8);
 snprintf(sport,sizeof(sport)-1,"%u",ntohs(dstport));//%u because ports are unsigned.
 name[0]=argc>1?argv[1]:"/usr/pkg/bin/nc";//if you want the arguments in a different order either change this sauce or use a script.
 name[1]=host;//WARNING: these two arguments aren't sanitized. they may contain flags set by the proxy's user that could wreak havok!
 name[2]=sport;//not sure how many programs can be messed up using just a number though.
 name[3]=0;
 //fprintf(stderr,"running: %s %s %s %s\n",name[0],name[1],name[2],name[3]);
 execv(name[0],name);
 //fprintf(stderr,"execv failed. :/");
 //perror("execv");
 return errno;//if we get here something failed so we might as well return errno.
}