/*****************************************************************************
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see
*
*****************************************************************************
*
* Sockcheck.c By BigDawg dawg@nuthin.nu - [ http://www.rootshell.com/ ]
* Use: put a list of ips (one per line) in ips.in then run sockcheck.
* The list of unsecure socks servers will be saved to ips.out
* Compile: gcc sockcheck.c -o sockcheck
*
* [20:01] put my name in the source ;)
*
* I'd like to say thanks to all who have helped me throughout the past years.
*
*****************************************************************************
* Notes from Mr.HinkyDink 8/24/2007
*
* There were a few things I didn't like about the original.
*
* I'd rather be able to put the IP & port on the command line
* and script the list than hassle with this infile/outfile crap.
*
* For example...
*
* for ADDR in $(
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define _GNU_SOURCE
#define DEFAULTWAIT (unsigned short)10
#define HTTPlen 8192
#define TMPlen 1024
#define GETlen 512
#define VIAMAX 64
typedef struct Sreq
{
char vers;
char command;
unsigned short port;
char addr[4];
char name[16];
} Sreq;
typedef struct S5req
{
char vers;
char command;
char rsv;
char atyp;
char addr[4]; // IPv4 addresses only : (
unsigned short port;
} S5req;
typedef struct S5resp
{
char vers;
char rep;
char rsv;
char atyp;
char baddr[4];
unsigned short bport;
} S5resp;
char *S5error[10]={
"GRANTED",
"general SOCKS server failure",
"connection not allowed by ruleset",
"network unreachable",
"host unreachable",
"connection refused",
"TTL expired",
"command not supported",
"address type not supported",
"unassigned"
};
int sockcheck(char *host, unsigned short port, char *dhost, unsigned short dport);
static int sockfd2;
static int aflag, killsock;
void sigalrm_handler3(int sig)
{
if( killsock ) {
killsock=0;
close(sockfd2);
}
aflag++;
}
// memmem is part of the GNU C library
// Copyright (C) 1991,92,93,94,96,97,98,2000 Free Software Foundation, Inc.
void *
memmem(const void *block, size_t blen, const void *pat, size_t plen)
{
const unsigned char *bp, *pp, *endp;
if (plen == 0)
return NULL;
if (blen < plen)
return NULL;
bp = block;
pp = pat;
endp = bp + (blen - plen) + 1;
while (bp < endp) {
if ((*bp == *pp) && (memcmp(bp, pp, plen) == 0))
return (void *)bp;
bp++;
}
return NULL;
}
// end of memmem
void findVIA( char *a, char *via )
{
while( (*a!='\r') ) {
if(*a==',') break;
*via++ = *a++;
}
*via=0;
}
int main(int argc, char **argv)
{
char sockip[32];
char destip[32];
short sockport;
short destport;
char *p;
sockport=destport=0;
destip[0]='\0';
if( argc<2 || argc>3 )
{
printf("\n=============================\n");
printf("sockcheck 0.4 by Mr.HinkyDink\n");
printf(" based on sockcheck 0.3\n");
printf(" by BigDawg\n");
printf("=============================\n\n");
printf("Useage:\n");
printf(" sockcheck SOCKSSERVER<:port> >\n\n");
printf("Default SOCKS port = 1080\n");
printf("Default TARGET port = 80\n");
printf("Default TARGET = www.google.com\n");
return 1;
}
strcpy( sockip, argv[1] );
if( (p=strchr(sockip,':'))==NULL)
sockport=1080;
else {
sockport=(unsigned short)atoi((const char*)p+1);
*p='\0';
}
sockport=sockport==0?1080:sockport;
if ( argv[2]==NULL )
{
return sockcheck( sockip, sockport, "www.google.com\0", 80 );
}
else
{
strcpy( destip, argv[2] );
if( (p=strchr(destip,':'))==NULL )
destport=80;
else {
destport=(unsigned short)atoi((const char*)p+1);
*p='\0';
}
destport=destport==0?80:destport;
return sockcheck( sockip, sockport, destip, destport );
}
}
int sockcheck(char *host, unsigned short port, char *dhost, unsigned short dport)
{
int d,e,f,retcode,idx,pos;
struct Sreq S;
struct S5req S5;
struct S5resp S5r;
char tmpstr2[TMPlen];
char HTTP_buffer[HTTPlen];
char HTTP[GETlen]="GET / HTTP/1.1\xd\xaHost: \0";
char GETcheck[]="(12202)"; // not prone to language issues
char VIAcheck[]="Via:";
char S5ask[3] = "\x5\x1\0";
char S5tell[2] = "\0\0";
fd_set gateset;
struct timeval tv;
struct hostent *he;
struct sockaddr_in sin;
unsigned short sockwait;
char *env;
char conDios[VIAMAX]="UNKNOWN\0";
void *p;
if( dport==80 ){
strncat(HTTP, dhost, GETlen-strlen(HTTP));
strncat(HTTP, "\xd\xa\xd\xa\0", GETlen-strlen(HTTP));
}
aflag=killsock=0;
if ( (env=getenv("SOCKWAIT"))==NULL)
sockwait=DEFAULTWAIT;
else
sockwait=(unsigned short)atoi((const char*)env);
sockwait=sockwait?sockwait:DEFAULTWAIT;
sockfd2 = socket(AF_INET, SOCK_STREAM, 0);
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
sin.sin_addr.s_addr = inet_addr(host);
if(sin.sin_addr.s_addr == INADDR_NONE)
{
he = gethostbyname(host);
if(!he)
{
close(sockfd2);
printf("DNS error - can't resolve \"%s\"!\n", host);
return 0;
}
memcpy(&sin.sin_addr, he->h_addr, he->h_length);
}
signal(SIGALRM, (void*)sigalrm_handler3);
alarm(sockwait); killsock=1; // SIGALRM closes sockfd2
e = connect(sockfd2, (struct sockaddr *)&sin, sizeof(sin));
if ( aflag ) {
printf("%s:%u - connect killed by SIGALRM", host, port);
if (sockwait==DEFAULTWAIT)
printf("\n");
else
printf(" (SOCKWAIT = %d sec.)\n", sockwait);
return 0;
}
if (e < 0)
{
printf("%s:%u - %s\n", host, port, strerror(errno));
//perror("connect");
close(sockfd2);
return 1;
}
alarm(sockwait);
FD_ZERO(&gateset);
FD_SET(sockfd2, &gateset);
tv.tv_sec = 10;
tv.tv_usec = 0;
d = select(sockfd2+1, NULL, &gateset, NULL, &tv);
if(d == 0 || aflag!=0 ) // seems to be dead code here, never dies on select
{
printf("%s:%d - %s\n", host, port, strerror(errno));
close(sockfd2);
return 1;
}
memset( &S, 0, sizeof(struct Sreq));
memset( &S5, 0, sizeof(struct S5req));
memset( &S5r, 0, sizeof(struct S5resp));
S.vers=4; S5.vers=5;
S.command=S5.command=1;
S.port=S5.port=htons(dport);
S5.rsv=0;
S5.atyp=1;
if ( (he = gethostbyname(dhost))==NULL )
{
printf("Can't resolve destination host \"%s\"\n", dhost);
close( sockfd2 );
return 1;
}
memcpy( &S.addr, he->h_addr, he->h_length );
memcpy( &S5.addr, he->h_addr, he->h_length );
strcpy(S.name,"BathHouseJohn\0"); // YOUR NAME HERE
memset( tmpstr2, 0, 1024);
send(sockfd2, &S, sizeof(struct Sreq), 0);
tv.tv_sec = 10;
tv.tv_usec = 0;
f = select(sockfd2+2, &gateset, NULL, NULL, &tv);
if(f>=0)
{
alarm(sockwait); killsock=1; // SIGALRM closes sockfd2
idx=pos=0;
read(sockfd2, tmpstr2, TMPlen);
if( aflag ) {
printf("%s:%u - Read killed by SIGALRM (connect successful)\n", host, port);
return 1;
}
if ( tmpstr2[0]==0x00 )
{
switch (tmpstr2[1])
{
case 0x5a: // check for ISA server - toss out a GET request
if (dport==80){
memset( HTTP_buffer, 0, HTTPlen);
e=send(sockfd2, &HTTP, strlen(HTTP), 0);
idx=pos=0;
do {
idx=read(sockfd2, HTTP_buffer+pos, HTTPlen-pos);
if ( idx<0 ) break;
pos+=idx;
}
while(idx);
if (e<0) {
printf("%s:%u - %s (after access granted)\n", host, port, strerror(errno));
retcode=1;
break;
}
p=memmem((const void*)HTTP_buffer,(size_t)HTTPlen,(const void*)GETcheck, (size_t)strlen(GETcheck));
if ( p==NULL ){
printf("%s:%u - ****GRANTED anonymous SOCKSv4 request****\n",host,port );
retcode=0;
}
else {
p=memmem((const void*)HTTP_buffer,(size_t)HTTPlen,(const void*)VIAcheck, (size_t)strlen(VIAcheck));
if(p) findVIA(p+8,conDios);
printf("%s:%u - ISA 2000 server \"%s\" denied http request (other ports may work)\n",host,port,conDios );
retcode=1;
}
}
else {
printf("%s:%u - ****GRANTED anonymous SOCKSv4 request to port %d****\n",host,port,dport );
retcode=0;
}
break;
// A note on ISA Server:
// =====================
// You really have to go out of your way to expose
// an ISA 2004/2006 server to the Internet. I was surprised
// to find as many as I did. The problem with http & ISA
// SOCKS support is you can't run the Web (http) proxy at the
// same time. It eats up all the "Web" ports. However, you
// can use SOCKS for any other TCP ports the ISA server allows
// unauthenticated access to. These could be substantial
// since if an ISA admin is stupid enough to expose the
// server to the Internet, he has very likely also created an
// "any port anywhere" rule.
// -- Mr.HinkyDink
case 0x5b: printf("%s:%u - returned explicit FAIL/DENY\n",host,port);
retcode=1;
break;
case 0x5c: printf("%s:%u - requires identd (not anonymous).\n",host,port);
retcode=2;
break;
case 0x5d: printf("%s:%u - returned SUX2BU (bad user ID).\n",host,port);
retcode=3;
break;
default: if ( errno )
printf("%s:%d - %s after SOCKS request.\n",host,port,strerror(errno));
else
printf("%s:%u - Got JUNK (0x00,0x%0.2X,0x%0.2X).\n", host, port,(unsigned char)tmpstr2[1],(unsigned char)tmpstr2[2]);
retcode=4;
break;
}
close(sockfd2);
return retcode;
}
else
{
if ( tmpstr2[0]==0x05 && tmpstr2[1]==0x01 && tmpstr2[2]==0x00 && tmpstr2[3]==0x01 ) {
close(sockfd2);
// server will have FIN'd us by now
// can't use same connection, so make it new
// no SIGALRM stuff because been there, done that, and I'm lazy
// SOCKS 5 packets previously stuffed just in case
sockfd2 = socket(AF_INET, SOCK_STREAM, 0);
connect(sockfd2, (struct sockaddr *)&sin, sizeof(sin));
FD_ZERO(&gateset);
FD_SET(sockfd2, &gateset);
tv.tv_sec = 10;
tv.tv_usec = 0;
select(sockfd2+1, NULL, &gateset, NULL, &tv);
send(sockfd2, &S5ask, 3, 0); // SOCKS 5 greeting
read(sockfd2, &S5tell, 2 ); // SOCKS 5 response
if (S5tell[1]==0) {
send(sockfd2, &S5, sizeof(struct S5req), 0);
read(sockfd2, &S5r, sizeof(struct S5resp) );
if ( S5r.rep > 9 ) S5r.rep=9;
printf("%s:%d - SOCKS v5 server response \"%s\"\n",host,port,S5error[S5r.rep]);
}
else // dead code???
printf("%s:%d - SOCKS v5 server requires authentication\"%s\"\n",host,port);
close(sockfd2);
return 1;
}
else
printf("%s:%d - Unknown SOCKS version or CRAP (0x%0.2X,0x%0.2X,0x%0.2X) or ERROR 0x%0.2X (%s).\n",host,port,(unsigned char)tmpstr2[0],(unsigned char)tmpstr2[1],(unsigned char)tmpstr2[2], errno, strerror(errno));
close(sockfd2);
return 1;
}
}
// fall through
printf("%s:%d - Bizarre outcome with errno = 0x%0.2X (%s).\n",host,port,errno,strerror(errno));
close(sockfd2);
return 0;
}