summaryrefslogtreecommitdiff
path: root/src/libexec
diff options
context:
space:
mode:
Diffstat (limited to 'src/libexec')
-rw-r--r--src/libexec/socks4a-proxy.c105
1 files changed, 105 insertions, 0 deletions
diff --git a/src/libexec/socks4a-proxy.c b/src/libexec/socks4a-proxy.c
new file mode 100644
index 0000000..a179d40
--- /dev/null
+++ b/src/libexec/socks4a-proxy.c
@@ -0,0 +1,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.
+}