
/* rnc.c code Begin Of File
 *
 *
 * FILENAME : rnc.c
 * VERSION :  0.1.1 Revision
 * CODER(s) : mrjade 2k2   mrjade@softhome.net
 * DATE : 18/5/2K1 
 * ABSTRACT : 3Com officceConnect 812 DSL remote config.
 * 
 * Usage of Program:
 *
 * # ./rnc user:passwd host/IpAdd[:pub_port] [priv_add[:priv_port]] [vc]
 *
 * host/IpAdd[:pub_port]  -> 3Com host and/or port
 * [priv_add[:priv_port]] -> remote host (target to bounce)
 * [vc]                   -> optional VC
 *
 * valid examples:
 *
 *  ./rnc admin:ADMIN www.host.com
 *
 *     Retrieve NAT table for VC internet (default VC)
 *
 *  ./rnc admin:ADMIN www.host.com:45
 *
 *     Remove NAT entry with public_port 45 on VC
 *
 *  ./rnc admin:ADMIN www.host.com:6667 irc.server.com          
 *  or
 *  ./rnc admin:ADMIN www.host.com irc.server.com:6667
 *  
 *     Add a NAT entry for bouncing to port 6667 in irc.server.com any
 *     connection made to port 6667 on ww.host.com. 
 *      
 *     Example tu use in irc: /server www.host.com:6667
 *
 *  ./rnc admin:ADMIN www.host.com:45 irc.server.com:80
 *
 *     Do the trick like: www.host.com port 45 -> web.server.com port 80
 *     So you can now browse as http://www.host.com:45/
 *
 *  And so. Hosts, may be in hostname or ip format. Forget Last argument (VC).
 *     
 *
 * Basics:
 *
 *  this tool enables ip wan to wan forwarding in order to route trafic outside
 *  of the lan C class. It's unset by default. the router doesn't need to be
 *  restarted when you modify this flag, but must be in order to update NAT
 *  table.      
 * 
 * License conditions:
 *
 * - You may use this code at your own risk. 
 * - Copy, modify, cut, delete.. do what you want, but remember to add a line
 *   to http://www.hackindex.org. Not for greeting.. just for further develop.
 *
 * 
 * Disclaimer:
 *
 *  The code is not finished, and will never be. This is concept code. It may 
 *  fail, and will do. Router responses aren't checked, so there's no warranty 
 *  about NAT table updates. Neither for router reboot.
 */

/*  ---== Include section ==---                         */

	#include <stdio.h>
	#include <string.h>
	#include <unistd.h>
	#include <sys/socket.h>
	#include <netdb.h>
	#include <arpa/inet.h>
	#include <stdlib.h>

/*  ---== Defines section ==---                         */


	#define MAXDATA 512
	#define VER "0.1.1-Revision"
	#define PORT 0
 
	/* Action list: */
 	#define GET_VC	1
 	#define DEL_NAT	2
 	#define ADD_NAT	3
 
/* Global variables (No need to be globals..)*/

	int Accion = 0;
 	int sock;
	int HForced = 0;
	char *host;
	char *priv_add;
	int port=0;
	char *user;
	char *passwd;
	int priv_port;
	char *VC = "internet";
	char datax[MAXDATA];
	char buffer[MAXDATA];
	struct hostent *hp;
	struct hostent *rhost;
	struct sockaddr_in TheHoSt;

/* Proc section */

        /*- show help -*/
	void usage(char *pname) {
		printf(" Usage   : %s user:passwd host/IpAdd[:pub_port] [priv_add[:priv_port]] [vc]\n\n",pname);
		printf(" Example : %s admin:ADMIN www.host.com:6543 vega.irc-hispano.org:6667\n",pname);
		printf("           This will forward any tcp connection on host.com:6543 to\n");
		printf("           vega.irc-hispano.org:6667. \n\n");
		printf(" Arguments are optional:\n");
		printf("   -    If only host/ip is given shows information about VC (internet).\n");
		printf("   -    If host/ip and pub_port, will remove any entry in NAT table.\n");
		printf("        on default VC 'internet'.\n");
		printf("   -    If host/ip, pub_port, priv_add will add a tcp forward on\n");
		printf("        default VC 'internet' using pub_port as priv_port.\n");
		printf("   -    You can specify priv_port using :port on priv_add.\n");
		printf("   -    if priv_port is set and no pub_port is given, both ports will\n");
		printf("        be the same.\n");
		printf("   -    Last optional argument is VC. It's only for make it funnier\n");
		printf("\n");
		exit(0);
	}

 /* Networking.. */

	/* nslookup */
	unsigned long resol(char *host_name) {
		struct in_addr addr;
		struct hostent *host_ent;
	
		if((addr.s_addr = inet_addr(host_name)) == -1) {
		if(!(host_ent = gethostbyname(host_name))) return(0);
		memcpy((char *)&addr.s_addr, host_ent->h_addr, host_ent->h_length);
		}
		return(addr.s_addr);
	}

	char *get_ipadd(char *host_name) {
		struct in_addr addr;
		struct hostent *host_ent;
	
		if((addr.s_addr = inet_addr(host_name)) == -1) {
		if(!(host_ent = gethostbyname(host_name))) return(0);
		memcpy((char *)&addr.s_addr, host_ent->h_addr, host_ent->h_length);
		}
		return(inet_ntoa(addr));
	}

	/* host[:port] */
	int Break_Host_Port(char *Host_Name){
		char *Puertoa, *tmp;
		int Puerto=0;
		tmp=Host_Name;

		if ((Host_Name = strstr (Host_Name, ":"))){
			Host_Name[0]=0; /*-  subst : with Null char -*/
			Host_Name ++;
			Puertoa=Host_Name;
			Host_Name=tmp;
			Puerto = atoi(Puertoa);
			if (Puerto > 65535) Puerto=0;
			if (Puerto < 1) Puerto=0;
			}
 		return Puerto;
	}

	void dummy_recv(int sock, char c, int view){
	char buffer[1];
		while ((recv(sock,buffer,1,0)!=-1) && (buffer[0] !=0)){
			if (buffer[0]==c) return;
			if (view){ printf("%c",buffer[0]);fflush(stdout);}
			bzero(buffer,sizeof(buffer)); //Clear Buffer
		}
	}

/* arg. parsing */

	/* user:passwd */
	char * Break_user_pass (char *user_Name){
		if ((user_Name = strstr (user_Name, ":"))){
			user_Name[0]=0; /*-  subst : with Null char -*/
			user_Name ++;
		} else{
			user_Name="";
		}
 		return user_Name;
	}


/*  ---== MAIN Procedure ==---                           */

int main(int argc, char *argv[]) {

	/* banner.. */
	printf("\n %s 3com 812 ADSL port forwarding <mrjade@softhome.net>\n\n", VER);

	/* arg check */
	if ((argc < 3) || (argc > 5)) usage(argv[0]);
	
	/* strip username and password */
	user = argv[1]; passwd="";
	if ((passwd = strstr (user, ":"))) (passwd++)[0]=0; /*-  subst : with Null char -*/

	/* strip remote host and public_port */
	host = argv[2];
	port = Break_Host_Port (host);

	if( argc > 3) {/* strip Private_addres and private_port */
		priv_add = argv[3];
		priv_port = Break_Host_Port (priv_add);
	}
	
	if( argc > 4) VC = argv[4]; /* strip VC name */
	
	if ((port == 0) && (argc<4)) Accion = 1; //show vcs

	/* private_port as public_port */
	if ((argc < 4)&&(port!=0)) Accion = 2; //delete NAT entry
	
	if (argc >= 4) {
		Accion = 3; //Add Nat Entry
		/* switching public_port as priv_port */
		if ((port==0) && (priv_port == 0)){
			printf("[+] Assuming 6667 as port.\n");
			port = 6667; priv_port = 6667;
		}
		if (priv_port == 0) priv_port = port;
		if (port == 0) port = priv_port;
	}
	
	if (Accion == 3){
		printf("[+] Resolving remote: %s\n", priv_add);	
		TheHoSt.sin_family = AF_INET;
		TheHoSt.sin_addr.s_addr = resol(priv_add);
		if(!TheHoSt.sin_addr.s_addr) {
			printf("[-] cant resolv.\n");
			exit(-1);
		}
		printf("[+] Remote host: %s\n",get_ipadd(priv_add));	
	}

	printf("[+] Resolving 3Com host: %s\n", host);	
	TheHoSt.sin_family = AF_INET;
	TheHoSt.sin_addr.s_addr = resol(host);
	if(!TheHoSt.sin_addr.s_addr) {
		printf("[-] cant resolv.\n");
		exit(-1);
	}
	
	printf("[+] Opening socket..\n");
	TheHoSt.sin_port = htons(23);
	sock = socket(AF_INET, SOCK_STREAM, 0);
	if(sock < 0) {
		printf("[-] socket error\n");
		exit(-1);
	}
	
	printf("[+] Connecting to %s\n", host );
	bzero(datax,sizeof(datax));	
	bzero(buffer,sizeof(buffer));	
	if(!connect(sock,(struct sockaddr *)&TheHoSt, sizeof(TheHoSt))) {
		
	/* Common Data:
	 * This is sent in every login on any action */
		
		dummy_recv(sock, 1,0);
		sprintf(datax,"%s%c",user,13);
		send(sock,datax,strlen(datax),0);
		dummy_recv(sock, 32,0);
		sprintf(datax,"%s%c",passwd,13);
		send(sock,datax,strlen(datax),0);
		dummy_recv(sock, '>',0);
		sprintf(datax,"enable ip wan_to_wan_forwarding%c",13);
		send(sock,datax,strlen(datax),0);
		dummy_recv(sock, '>',0);
		
		switch(Accion){
			
			case GET_VC:
				printf ("[+] Retrieving NAT table for VC: %s\n\n", VC);
				sprintf(datax,"show vc %s%c",VC,13);
				send(sock,datax,strlen(datax),0);
				dummy_recv(sock, 32,0);
				sprintf(datax,"%c",13);
				send(sock,datax,strlen(datax),0);
				dummy_recv(sock, 32,0);
				sprintf(datax,"%c",13);
				send(sock,datax,strlen(datax),0);
				dummy_recv(sock, ',',0);
				printf ("\t  ");
				dummy_recv(sock, '>',1);
				printf ("\r          \n");
				sprintf(datax,"quit%c",13);
				send(sock,datax,strlen(datax),0);
				return (0);
				break;
			case DEL_NAT:
				printf ("[+] Deleting NAT entry on VC. \n\n");
				sprintf(datax,"del nat tcp vc %s public_port %d%c",VC, port,13);
				send(sock,datax,strlen(datax),0);
				dummy_recv(sock, '>',0);
				sprintf(datax,"save all%c",13);
				send(sock,datax,strlen(datax),0);
				dummy_recv(sock, '>',0);
				sprintf(datax,"reboot%cyes%c",13,13);
				send(sock,datax,strlen(datax),0);
				return (0);
				break;
			case ADD_NAT:
				printf ("[+] Adding NAT entry on VC. \n\n");
				sprintf(datax,"add nat tcp vc %s public_port %d private_address %s private_port %d%c",VC, port, get_ipadd(priv_add), priv_port,13);
				send(sock,datax,strlen(datax),0);
				dummy_recv(sock, '>',0);
				sprintf(datax,"save all%c",13);
				send(sock,datax,strlen(datax),0);
				dummy_recv(sock, '>',0);
				sprintf(datax,"reboot%cyes%c",13,13);
				send(sock,datax,strlen(datax),0);
				break;
			default:
				/* How can you reach here? */
				return (0);
				break;
		}
	} else {
		close(sock);  //Remote host will close it when finished
		printf("[-] can't connect.\n");
		exit(-1);
	}
	if (Accion > 1 )printf ("[+] Remember to wait for router boot (2 min.)\n");
	printf("\n");
	close(sock);  //Remote host will close it when finished
	return 0;
}
