#include #include #include #include #include #include #include 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. }