/*
 * Simple & dirty telnetd encryption scanner by Kingcope
 * Year 2011
 *
 * Compile : gcc telnetscan.c -o telnetscan -lpthread
*/

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/time.h>
#include <fcntl.h>
#include <errno.h>

#define MAX_THREADS 50
#define CONNECT_TIMEOUT 3 // in seconds
#define MAX_BUF 100

void *telnet(void *arg)
{
  int sockd;
  int count;
  struct sockaddr_in serv_name;
  unsigned char buf[MAX_BUF];
  char ip[256];
  char saveip[256];
  char request[1024];
  char req_enc[6] = "\xff\xfd\x26\xff\xfb\x26";
  int status;
  FILE *f;

  strcpy(ip, (char*)arg);

  sockd = socket(AF_INET, SOCK_STREAM, 0);
  if (sockd == -1)
  {
    perror("Socket creation");
    return NULL;
  }

  serv_name.sin_family = AF_INET;
  inet_aton(ip, &serv_name.sin_addr);

  serv_name.sin_port = htons(23);
  unsigned long iMode = 1;
  
  status = connect(sockd, (struct sockaddr*)&serv_name, sizeof(serv_name));
  if (status == -1)
  {
	close(sockd);
	return NULL;
  }

  count = read(sockd, buf, MAX_BUF);
    
  memcpy(request, req_enc, 6);
  write(sockd, request, 6);
  
  count = read(sockd, buf, MAX_BUF);

  if (buf[0]==0xff&&buf[1]==0xfb&&buf[2]==0x26&&buf[3]==0xff&&buf[4]==0xfd&&buf[5]==0x26) {
	printf("\n%s supports encryption\n", ip);
        snprintf(saveip, sizeof(saveip), "%s\n", ip);
	f = fopen("scan.log", "a");
	fputs(saveip, f);
	fclose(f);
	
	close(sockd);
	return NULL;
  }

  close(sockd);
  return NULL;
}

void usage(char *argv[]) {
	printf("%s <startip> <endip>\n", argv[0]);
	exit(0);
}

void parseip(char *ip, int *a1, int *a2, int *a3, int *a4)
{
	char *pos,*pos2,*pos3;

	pos = strchr(ip, '.');
	if ((!pos) || (pos-ip > 3)) {
		printf("Invalid ip.\n");
		exit(0);
	}

	*pos=0;
	*a1 = atoi(ip);

	pos2 = strchr(pos+1, '.');
	if ((!pos2) || (pos2-(pos+1) > 3)) {
		printf("Invalid ip.\n");
		exit(0);
	}
	*pos2=0;
	*a2 = atoi(pos+1);

	pos3 = strchr(pos2+1, '.');
	if ((!pos3) || (pos3-(pos2+1) > 3)) {
		printf("Invalid ip.\n");
		exit(0);
	}
	*pos3=0;
	*a3 = atoi(pos2+1);

	if (strlen(pos3+1) > 3) {
		printf("Invalid ip\n");
		exit(0);
	}
	*a4 = atoi(pos3+1);
}

int main(int argc, char *argv[]) {
	char *startip;
	char *endip;
	int a1,a2,a3,a4;
	int b1,b2,b3,b4;
	pthread_t threads[512];
        int threads_running[512];
	char scanip[256];
	int k,k1,k2,k3,k4;

	printf("telnetd encryption scanner by Kingcope\n");
	if (argc != 3) usage(argv);

	startip = (char*)malloc(strlen(argv[1])+1);
	if (startip == NULL) {
		printf("error: malloc()\n");
		exit(0);
	}
	strcpy(startip, argv[1]);

	endip = (char*)malloc(strlen(argv[2])+1);
	if (endip == NULL) {
		printf("error: malloc()\n");
		exit(0);
	}
	strcpy(endip, argv[2]);

	parseip(startip, &a1, &a2, &a3, &a4);
	parseip(endip, &b1, &b2, &b3, &b4);

	printf("Starting scan from %d.%d.%d.%d to %d.%d.%d.%d\nSaving hits to scan.log\n", a1, a2, a3, a4, b1, b2, b3, b4);
	k1=a1;
	k2=a2;
	k3=a3;
	k4=a4;	

	k=0;
	printf("CURRENT IP: %d.%d.%d.%d\n", k1, k2, k3, k4);
	fflush(stdout);

	for(;;) {
		snprintf(scanip, sizeof(scanip), "%d.%d.%d.%d", k1, k2, k3, k4);
                threads_running[k] = time(NULL);
		if (pthread_create( &threads[k], NULL, telnet, (void*) scanip) != 0) {
			printf("Error: Could not create thread. Done.\n");
			exit(0);
		}
		usleep(1000);
		
		k++;

		if (k==MAX_THREADS) {
			int kk;
			for (kk=0;kk<MAX_THREADS;kk++) {
				while (threads_running[kk] + CONNECT_TIMEOUT > time(NULL)) {
					__asm("nop");
				}
				pthread_cancel(threads[kk]);
				pthread_join(threads[kk], NULL);
			}
			for (kk=0;kk<1024;kk++) {
				close(kk+4);
			}
			k=0;

			printf("CURRENT IP: %d.%d.%d.%d\n", k1, k2, k3, k4);
			fflush(stdout);
		}

		if (k4==b4 && k3==b3 && k2==b2 && k1==b1) {
			printf("\nscan finished\ndone.\n");
			exit(0);
		}

		k4++;

		if (k4 == 256) {
			k3++;
			k4=0;
		}

		if (k3 == 256) {
			k2++;
			k3=0;
		}

		if (k2 == 256) {
			k1++;
			k2=0;
		}
		
		if (k1 == 256) {
			printf("\nscan finished\ndone.\n");
                        exit(0);
		}
	}

	return 0;
}
