/* RIP-related user commands
 *   Al Broscious, N3FCT
 *   Phil Karn, KA9Q
 *
 *  Changes Copyright (c) 1993 Jeff White - N0POY, All Rights Reserved.
 *  Permission granted for non-commercial copying and use, provided
 *  this notice is retained.
 *
 * Rehack for RIP-2 (RFC1388) by N0POY 4/1993
 *
 * Beta release 11/10/93 V0.91
 *
 * 2/19/94 release V1.0
 *
 * rip98 support added, 29/3/97
 */

#include "global.h"
#ifdef RIP
#include "commands.h"
#include "mbuf.h"
#include "netuser.h"
#include "internet.h"
#include "iface.h"
#include "udp.h"
#include "rip.h"

#if !defined(_lint)
static char rcsid[] OPTIONAL = "$Id: ripcmd.c,v 1.18 2001/05/06 16:32:58 brian Exp $";
#endif

static int doripproxy (int argc, char *argv[], void *p);
static int doripauthadd (int argc, char *argv[], void *p);
static int doripauthdrop (int argc, char *argv[], void *p);
static int doripreject (int argc, char *argv[], void *p);
static int doripfilter (int argc, char *argv[], void *p);
static int doaddrefuse (int argc,char *argv[],void *p);
static int doripmerge (int argc,char *argv[],void *p);
static int dodroprefuse (int argc,char *argv[],void *p);
static int doripadd (int argc,char *argv[],void *p);
static int doripdrop (int argc,char *argv[],void *p);
static int doripkick (int argc,char *argv[],void *p);
static int doripreq (int argc,char *argv[],void *p);
static int doriptrace (int argc,char *argv[],void *p);
static int doripttl (int argc,char *argv[],void *p);
static int dorip98rx (int argc,char *argv[],void *p);

static struct cmds Ripcmds[] =
{
	{ "accept",	dodroprefuse,	0, 2, "rip accept <gateway> " },
	{ "add",	doripadd,	0, 3, "rip add <dest> <interval> [<flags>] [<ripver>] [AUTH <password>] [RD <routing domain>]" },
	{ "proxy",	doripproxy,	0, 4, "rip proxy <src> <dest> <interval> [<flags>] [AUTH <password>] [RD <routing domain>]" },
	{ "drop",	doripdrop,	0, 2, "rip drop <dest> [<domain>]" },
	{ "authadd",	doripauthadd,	0, 3, "rip authadd <interface> <routing domain> [<password>]" },
	{ "authdrop",	doripauthdrop,	0, 3, "rip authdrop <interface> <routing domain>" },
	{ "reject",	doripreject,	0, 2, "rip reject <version>" },
	{ "filter",	doripfilter,	0, 0, NULLCHAR },
	{ "kick",	doripkick,	0, 0, NULLCHAR },
	{ "merge",	doripmerge,	0, 0, NULLCHAR },
	{ "refuse",	doaddrefuse, 	0, 2, "rip refuse <gateway>" },
	{ "request",	doripreq,	0, 2, NULLCHAR },
	{ "rip98rx",	dorip98rx,	0, 0, NULLCHAR },
	{ "status",	doripstat,	0, 0, NULLCHAR },
	{ "trace",	doriptrace,	0, 0, NULLCHAR },
	{ "ttl",	doripttl,	0, 0, NULLCHAR },
	{ NULLCHAR,	NULL,		0, 0, NULLCHAR }
};



/* rip add 192.133.30.15 360 SUBPA 2 AUTH password RD 2 RT 0
 * rip add <dest> <interval> <ripver> [<flags>] [AUTH <password>]
 *    [RD <routing domain>]
 * rip proxy <src> <dest> <interval> [<flags>] [AUTH <password>]
 *    [RD <routing domain>]
 * rip authadd <ifc> <rd> [<password>]
 * rip authdrop <ifc> <rd>
 * rip reject <ifc> <version>
 * rip filter <on|off>
 * rip drop <dest> <domain>
 */

int
dorip (int argc, char *argv[], void *p)
{
	return subcmd (Ripcmds, argc, argv, p);
}



/* Facility to chuck away RIP98 frames when rip server is active */
static int
dorip98rx (int argc, char *argv[], void *p OPTIONAL)
{
	return setbool (&rip98allow, "Rip 98 reception", argc, argv);
}



/* Add an entry to the RIP output list */
static int
doripadd (int argc, char *argv[], void *p OPTIONAL)
{
int x;
char flags = RIP_SPLIT | RIP_BROADCAST | RIP_POISON;
char ripver = 1;
char rip_auth[RIP_AUTH_SIZE + 1];
int16 domain = 0;
int16 route_tag = 0;
uint32 dest;

	for (x = 0; x < RIP_AUTH_SIZE + 1; x++)	/* Null out the string */
		rip_auth[x] = '\0';

	strcpy (rip_auth, RIP_NO_AUTH);

	if (argc > 3)
		flags = (char) htoi (argv[3]);
	if (argc > 4)
		ripver = (char) atoi (argv[4]);
	if (argc > 5) {
		for (x = 5; x < argc; x++) {
			if (!strcmp (argv[x], "AUTH")) {
				x++;
				strncpy (rip_auth, argv[x], RIP_AUTH_SIZE);
			} else if (!strcmp (argv[x], "RD")) {
				x++;
				domain = (int16) atoi (argv[x]);
			}
		}
	}
	dest = resolve (argv[1]);
	if (rip_add (dest, atol (argv[2]), flags, ripver, rip_auth, domain, route_tag, 0))
		return 0;
	else
		return 1;
}



/* Add a proxy entry to the RIP output list */
static int
doripproxy (int argc, char *argv[] OPTIONAL, void *p OPTIONAL)
{
int x;
char flags = RIP_SPLIT | RIP_BROADCAST | RIP_POISON;
char ripver = RIP_VERSION_2;
char rip_auth[RIP_AUTH_SIZE + 1];
int16 domain = 0;
int16 route_tag = 0;
uint32 dest;
uint32 proxy;

	for (x = 0; x < RIP_AUTH_SIZE+ 1; x++)	/* Null out the string */
		rip_auth[x] = '\0';

	strcpy (rip_auth, RIP_NO_AUTH);

	if (argc > 4)
		flags = (char) htoi (argv[4]);
	if (argc > 5) {
		for (x = 5; x < argc; x++) {
			if (!strcmp (argv[x], "AUTH")) {
				x++;
				strncpy (rip_auth, argv[x], RIP_AUTH_SIZE);
			} else if (!strcmp (argv[x], "RD")) {
				x++;
				domain = (int16) atoi (argv[x]);
			}
		}
	}
	dest = resolve (argv[2]);
	proxy = resolve (argv[1]);
	(void) rip_add (dest, atol (argv[3]), flags, ripver, rip_auth, domain, route_tag, proxy);
	return 1;
}



/* Add an entry to the RIP refuse list */
static int
doaddrefuse (int argc OPTIONAL, char *argv[], void *p OPTIONAL)
{
	return riprefadd (resolve (argv[1]));
}



/* Drop an entry from the RIP output list */
static int
doripdrop (int argc, char *argv[], void *p OPTIONAL)
{
int16 domain = 0;

	if (argc > 2)
		domain = (int16) atoi (argv[2]);

	return rip_drop (resolve (argv[1]), domain);
}



/* Add an entry to the RIP authentication list */
static int
doripauthadd (int argc, char *argv[], void *p OPTIONAL)
{
	return ripauthadd (argv[1], (int16) atoi (argv[2]), (argc > 3) ? argv[3] : RIP_NO_AUTH);
}



/* Drop an entry from the RIP authentication list */
static int
doripauthdrop (int argc OPTIONAL, char *argv[], void *p OPTIONAL)
{
	return ripauthdrop (argv[1], (int16) atoi (argv[2]));
}



static int
doripkick (int argc OPTIONAL, char *argv[] OPTIONAL, void *p OPTIONAL)
{
register struct rip_list *rl;

	rl = (struct rip_list *) Rip_list;
	if (Rip_list != NULLRL)
		for (rl = Rip_list; rl != NULLRL; rl = rl->next)
			rip_shout (rl);
	return 0;
}



/* Drop an entry from the RIP refuse list */
static int
dodroprefuse (int argc OPTIONAL, char *argv[], void *p OPTIONAL)
{
	return riprefdrop (resolve (argv[1]));
}



/* Initialize the RIP listener */
int
doripinit (int argc OPTIONAL, char *argv[] OPTIONAL, void *p OPTIONAL)
{
	return rip_init ();
}



int
doripstop (int argc OPTIONAL, char *argv[] OPTIONAL, void *p OPTIONAL)
{
	(void) del_udp (Rip_cb);
	Rip_cb = NULLUDP;
	return 0;
}



static int
doripreq (int argc, char *argv[], void *p OPTIONAL)
{
int16 replyport;
int16 version;

	if (argc > 2)
		version = (int16) atoi (argv[2]);
	else
		version = 2;

	if (argc > 3)
		replyport = (int16) atoi (argv[3]);
	else
		replyport = RIP_PORT;
	return ripreq (resolve (argv[1]), replyport, version);
}



/* Dump RIP statistics */
int
doripstat (int argc OPTIONAL, char *argv[] OPTIONAL, void *p OPTIONAL)
{
struct rip_list *rl;
struct rip_refuse *rfl;
struct rip_auth *ra;
int cnt;

	for (cnt = 1; cnt < RIP_VERSIONS; cnt++) {
		if (cnt != RIP_VERSION_X)
			tprintf ("RIP V%d:  sent %lu rcvd %lu reqst %lu resp %lu unk %lu\n",
				cnt, Rip_stat.vdata[cnt].output, Rip_stat.vdata[cnt].rcvd,
				Rip_stat.vdata[cnt].request, Rip_stat.vdata[cnt].response,
				Rip_stat.vdata[cnt].unknown);
		else
			tprintf ("RIP V98: sent %lu rcvd %lu reqst %lu resp %lu unk %lu\n",
				Rip_stat.vdata[cnt].output, Rip_stat.vdata[cnt].rcvd,
				Rip_stat.vdata[cnt].request, Rip_stat.vdata[cnt].response,
				Rip_stat.vdata[cnt].unknown);
	}

	tprintf ("Version Errors:            %lu   ", Rip_stat.version);
	tprintf ("Address Family Errors:     %lu\n", Rip_stat.addr_family);
	tprintf ("Rip refusals:              %lu   ", Rip_stat.refusals);
	tprintf ("Wrong Domain on Interface: %lu\n", Rip_stat.wrong_domain);
	tprintf ("Authentication failures:   %lu   ", Rip_stat.auth_fail);
	tprintf ("Unknown Authentication:    %lu\n", Rip_stat.unknown_auth);

	if (Rip_list != NULLRL) {
		tprintf ("Active RIP output interfaces:\n");
		tprintf ("Ver Dest Addr       Int  Flags Domain Proxy           Authentication\n");
		for (rl = Rip_list; rl != NULLRL; rl = rl->next) {
			tprintf ("%-4d%-16s%-5lu0x%-4X%-7u", rl->rip_version,
				 inet_ntoa (rl->dest), rl->interval, rl->flags, rl->domain);
			tprintf ("%-16s%-16s\n", inet_ntoa (rl->proxy_route), rl->rip_auth_code);
		}
	}
	if (Rip_refuse != NULLREF) {
		tprintf ("Refusing announcements from gateways:\n");
		for (rfl = Rip_refuse; rfl != NULLREF; rfl = rfl->next) {
			if (tprintf ("%s\n", inet_ntoa (rfl->target)) == EOF)
				break;
		}
	}
	if (Rip_auth != NULLAUTH) {
		tprintf ("\nAuthentications accepted:\n");
		tprintf ("Interface           Domain   Password\n");
		for (ra = Rip_auth; ra != NULLAUTH; ra = ra->next) {
			tprintf ("%-20s%-9u%-16s\n", ra->ifc_name, ra->domain, ra->rip_auth_code);
		}
	}
	tprintf ("Refusing versions less than or equal to V%d\n", Rip_ver_refuse);

	return 0;
}



static int
doriptrace (int argc, char *argv[], void *p OPTIONAL)
{
	if (argc > 1) {
		Rip_trace = (int16) atoi (argv[1]);
		if ((Rip_trace == 0) && (Rip_trace_file != NULLFILE)) {	/* Turn off tracing */
			(void) fclose (Rip_trace_file);
			Rip_trace_file = NULLFILE;
			if (Rip_trace_fname != NULLCHAR) {
				free (Rip_trace_fname);
				Rip_trace_fname = NULLCHAR;
			}
		}
		if (argc > 2) {
			if ((Rip_trace_file = fopen (argv[2], APPEND_TEXT)) == NULLFILE)
				tprintf ("Cannot write to %s\n", argv[2]);
			else
				Rip_trace_fname = strdup (argv[2]);

			(void) fclose (Rip_trace_file);
		}
	} else {
		if (Rip_trace_file != NULLFILE)
			tprintf ("Tracing RIP status level %d to file %s\n", Rip_trace,	Rip_trace_fname);
		else
			tprintf ("Tracing RIP status level %d\n", Rip_trace);
	}
	return 0;
}



static int
doripttl (int argc, char *argv[], void *p OPTIONAL)
{
	return setlong (&Rip_ttl, "RIP route ttl", argc, argv);
}



static int
doripreject (int argc, char *argv[], void *p OPTIONAL)
{
	return setshort (&Rip_ver_refuse, "RIP version refusal level", argc, argv);
}



static int
doripmerge (int argc, char *argv[], void *p OPTIONAL)
{
	return setbool ((int *) &Rip_merge, "RIP merging", argc, argv);
}



static int
doripfilter (int argc, char *argv[], void *p OPTIONAL)
{
	return setbool ((int *) &Rip_default_refuse, "RIP default refusal", argc, argv);
}

#endif
