--- linux-2.6.15-gentoo-r1/drivers/char/misc.c 2006-02-10 06:09:26.000000000 +0800 +++ linux-2.6.15-gentoo-r1-ri2/drivers/char/misc.c 2006-02-19 11:51:46.000000000 +0800 @@ -65,6 +65,10 @@ extern int pmu_device_init(void); +#ifdef CONFIG_RICMP +extern int ricmp_init(void); +#endif + #ifdef CONFIG_PROC_FS static void *misc_seq_start(struct seq_file *seq, loff_t *pos) { @@ -308,6 +312,9 @@ class_destroy(misc_class); return -EIO; } +#ifdef CONFIG_RICMP + ricmp_init(); +#endif return 0; } subsys_initcall(misc_init); --- linux-2.6.15/include/net/ricmp.h.orig 2005-08-05 11:52:52.000000000 +1000 +++ linux-2.6.15/include/net/ricmp.h 2005-08-05 11:52:52.000000000 +1000 @@ -0,0 +1,69 @@ +/* + ricmp.h - Reboot ICMP public functions. + v 1.2 Nail (nail@itapac.net) + + Not so much of public. + All the 'reception and reboot' work is made by ricmp_try . + + Interaction with the user regarding ACLs is made thru + /dev/ricmp and handled by ricmp.c static functions so no + need to define them here. +*/ + + +#ifndef _NET_RICMP_H_ +#define _NET_RICMP_H_ + +#ifdef __KERNEL__ +#include +#include +#include +#else +#include +#include +#include +#endif /* kernel */ + + + + +/***** ACL part ******/ +/* Possible actions */ + +#define RICMP_ACT_IGNORE 0x000 +#define RICMP_ACT_ACCEPT 0x010 + +#define RICMP_ACT_LOG 0x100 + +/* Possible reboots */ +#define RICMP_COLD 0x00 /* cold reboot */ +#define RICMP_WARM 0x01 /* warm reboot */ + +#define RICMP_HARD 0x00 /* like a 'reset' button press */ +#define RICMP_SOFT 0x10 /* like a 'shutdown -r now' */ + + +/* The structure of an RICMP acl */ +struct ricmp_acl { + /* set src or dst to INADDR_ANY to consider any host */ + struct in_addr src; + struct in_addr dst; + int action; /* action to do on acl match */ + int type; /* type of reboot if RICMP_ACT_ACCEPT is set and match */ +}; + +#ifdef __KERNEL__ +/* 0 = ok, -1 = error, 1 = already set */ +int ricmp_setacl(struct ricmp_acl *); + +/* 0 = ok, -1 = error, 1 = not present */ +int ricmp_rmacl(struct ricmp_acl *); + +/* Called from icmp_echo, to analyze ICMP echos against ACLs and password */ +void ricmp_try(struct icmphdr *, struct iphdr *, int); + +/* Used to set the password */ +void ricmp_setpwd(char *, int); +#endif /* kernel */ + +#endif /* header inclusion */ --- linux-2.6.15/net/ipv4/ricmp.c.orig 2005-08-05 11:52:52.000000000 +1000 +++ linux-2.6.15/net/ipv4/ricmp.c 2005-08-05 11:56:35.000000000 +1000 @@ -0,0 +1,420 @@ +/* + ricmp.c - Reboot ICMP handling and relative ACLs handling. + v 1.2 - Nail (nail@itapac.net) + + This is the main code. + There is a small part for packet matching and password + handling, then a part on ACLs and settings thru + /dev/ricmp. + ACL match are required only when PASSWORD is matched. + The password is contained in the incoming ICMP pattern, + in the ICMP data field, after the timestamp. + + NOTE: If you are asking yourself why this piece of + code cannot be load as a module here is the answer: + This is a EMERGENCY action, you should use it only + when you cannot log in in the machine phisically and + all services are closed. + A module must be loaded. + To load a module you need to have access. + Loading a module at boot time is stupid: the overhead + for a an analysis of a ICMP echo packet is near zero. + + ChangeLog: + + 1.1.0 (2001/06/27) Nail - Corrected patch + 1.2.0 (2001/09/16) Nail - Made the 2.4 patch. + +*/ +/* TODO: + Soft reboot, is it possible? + Insert something like cryptography. + Maybe split the code between /dev/ricmp and other parts + Insert different passwords for different hosts maybe... +*/ + +#define RICMP_MINOR_DEV 210 +#define RICMP_VERSION_STR " 1.2.3 " +#define RICMP_VERSION 10 + + +#define RICMP_ICMP_OFFSET 16 +#ifndef RICMP_DEFAULT_PWD +#warning "Please set RICMP_DEFAULT_PWD to a proper value!!" +#define RICMP_DEFAULT_PWD "\x11\x22\x33\x44" +#define RICMP_DEFAULT_PWDLEN 4 +#endif + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct ricmp_acllist { + struct ricmp_acl value; + struct ricmp_acllist *next; +}; + +static struct ricmp_acllist *racl = NULL; /* The ACLs */ +static int racl_count = 0; + +static char *rpwd = RICMP_DEFAULT_PWD; +static int rpwd_len = RICMP_DEFAULT_PWDLEN, isdefault = 1; + +/* Internal functions */ +static int password_match(char *, int); /* 0 = match, 1 = nomatch */ +static struct ricmp_acllist *encap(struct ricmp_acl); +static int acl_action(u32, u32 , int *); +static void ricmp_ntoa(u32, char *); + + +static ssize_t ricmp_dev_write (struct file *, const char *, size_t, loff_t *); +static int ricmp_dev_open (struct inode *, struct file *); +static int ricmp_dev_close (struct inode *, struct file *); +static int ricmp_dev_flush (struct file *); + +void ricmp_setpwd(char *pwd, int len) +{ + if(isdefault) + isdefault = 0; + else kfree(rpwd); + + rpwd = pwd; + rpwd_len = len; +} + + + + +static ssize_t ricmp_dev_write(struct file *f, const char *cc, size_t s, loff_t *l) +{ + /* A request is made by a char and a struct ricmp_acl. + If the char is set to 0, the rule has to be added + If the char is set to 1, the rule has to be deleted + If the char is set to 2, there's a password following: + char, password size (uint32), password buf */ + + char type; + struct ricmp_acl req; + + if(s == 0) + return -EIO; + if(copy_from_user(&type, cc, sizeof(type))) + return -EIO; + ++cc; + if(type == 2) + { + u32 psz; + char *pbuf; + + if(copy_from_user(&psz, (u32 *)cc, sizeof(u32))) + return -EIO; + cc += sizeof(u32); + s -= 1+sizeof(u32); + if(s < psz) + return -EIO; + pbuf = kmalloc(psz, GFP_KERNEL); + if(!pbuf) + return -EIO; + if (copy_from_user(pbuf, cc, psz)) + return -EIO; + ricmp_setpwd(pbuf, psz); + return s; + } + + + if(copy_from_user(&req, (struct ricmp_acl *)cc, sizeof(struct ricmp_acl))) + return -EIO; + + if(type) + ricmp_rmacl(&req); + else + ricmp_setacl(&req); + + return s; +} + + + + + +static int ricmp_dev_open(struct inode *in, struct file *f) +{ + return 0; +} + +static int ricmp_dev_close(struct inode *i, struct file *f) +{ + return 0; +} + +static int ricmp_dev_flush(struct file *f) +{ + return 0; +} + + +/* This is the devfs entry */ +static struct file_operations ricmp_fops = { + /*owner: &__this_module,*/ + write: ricmp_dev_write, + open: ricmp_dev_open, + flush: ricmp_dev_flush, + release: ricmp_dev_close +}; + +static struct miscdevice ricmp_dev = { + RICMP_MINOR_DEV, + "ricmp", + &ricmp_fops +}; + +/* This is the init function */ +int __init +ricmp_init(void) +{ + printk(KERN_INFO "ricmp extensions version" + RICMP_VERSION_STR "loaded\n"); + + misc_register(&ricmp_dev); + return 0; +} + +/* These are the lowest level functions */ + +/* 0 = nomatch, 1 = match, is like a memcmp*/ +static int +password_match(char *user, int len) +{ + int i; + + if(!rpwd_len) + return 1; + + /* sanity */ + if(!user || !len) + return 0; + + /* match for len before all */ + if(len < rpwd_len) /* can be > because it's a pattern */ + return 0; + + for(i = 0; i < rpwd_len; ++i) + if(rpwd[i] != user[i]) + break; + return (i == rpwd_len); + +} + +static struct ricmp_acllist * +encap(struct ricmp_acl acl) +{ + struct ricmp_acllist *ret; + + ret = (struct ricmp_acllist *)kmalloc( + sizeof(struct ricmp_acllist), GFP_KERNEL); + + memcpy(&ret->value, &acl, sizeof(struct ricmp_acl)); + ret->next = NULL; + + return ret; +} + +/* This is the acl matching routine */ +/* Start from the head. Returns the action to do */ +static int +acl_action(u32 s, u32 d, int *typeptr) +{ + char matched; + struct ricmp_acllist *p = racl; + struct ricmp_acl *vptr; + + /* No ACL: ACCEPT a COLD reboot. + This is because we could be in the middle of + the boot process and the machine could hang. + Remember we are an 'emergency' so if nothing + is already configured we must save our back. */ + + if(!racl || !racl_count) { + *typeptr = RICMP_COLD; + printk(KERN_INFO "ricmp: emergency, no acls\n"); + return RICMP_ACT_ACCEPT; + } +#ifndef INADDR_ANY +#define INADDR_ANY 0 +#endif + + + do /* match loop */ + { + matched = 1; + vptr = &(p->value); + if(vptr->src.s_addr != INADDR_ANY) { + if(s != vptr->src.s_addr) + matched = 0; + } + + if(vptr->dst.s_addr != INADDR_ANY) { + if(d != vptr->dst.s_addr) + matched = 0; + } + + if(matched) + break; + } while((p = p->next)); + + if(!p) + return RICMP_ACT_IGNORE; + + if(vptr->action & RICMP_ACT_ACCEPT) + *typeptr = vptr->type; + + return vptr->action; +} + + +/* we cannot shift because we are printing in decimal form */ +static char * wchar(char *buf, int val) +{ + if(val >= 10) { + buf = wchar(buf, val / 10); + val %= 10; + } + + *buf++ = '0' + val; + return buf; +} + + + + +static void ricmp_ntoa(u32 addr, char *buf) +{ + unsigned char a, b, c, d; + + a = addr & 0xff; + b = (addr >> 8) & 0xff; + c = (addr >> 16) & 0xff; + d = (addr >> 24) & 0xff; + + buf = wchar(buf, a); + *buf++ = '.'; + buf = wchar(buf, b); + *buf++ = '.'; + buf = wchar(buf, c); + *buf++ = '.'; + buf = wchar(buf, d); + *buf = 0; +} + + + +/* The main match routine */ +void ricmp_try(struct icmphdr *pkt, struct iphdr *hdr, int plen) +{ + char *pattern, sipbuf[32], dipbuf[32]; + int action, type; + + if(plen <= RICMP_ICMP_OFFSET) + return; + + + pattern = (char *)pkt; + pattern += RICMP_ICMP_OFFSET; + + /* No password match */ + if(!password_match(pattern, plen - RICMP_ICMP_OFFSET)) + return; + + + action = acl_action(hdr->saddr, hdr->daddr, &type); + + + if(action & RICMP_ACT_LOG) { + ricmp_ntoa(hdr->saddr,sipbuf); + ricmp_ntoa(hdr->daddr,dipbuf); + if(action & RICMP_ACT_ACCEPT) + printk(KERN_INFO "ricmp: rebooting due to packet from "); + else + printk(KERN_INFO "ricmp: ignoring packet from "); + printk("%s to %s\n", sipbuf, dipbuf); + } + + if(action & RICMP_ACT_ACCEPT) + { +#if 0 + if(type == RICMP_COLD) + reboot_setup("c,h", NULL); + else reboot_setup("b,w", NULL); +#endif + machine_restart(NULL); + } + + +} + + +int ricmp_rmacl(struct ricmp_acl *rule) +{ + struct ricmp_acllist *p = racl, *prev = NULL; + + while(p) + { + if(!memcmp((char *)&p->value, (char *)rule, sizeof(struct ricmp_acl))) + break; + prev = p; + p = p->next; + } + + if(!p) + return 1; + + if(prev) + prev->next = p->next; + else + racl = p->next; + kfree(p); + + racl_count--; + + return 0; +} + +int ricmp_setacl(struct ricmp_acl *rule) +{ + struct ricmp_acllist *p; + + ricmp_rmacl(rule); + + racl_count++; + if(!racl) { + racl = encap(*rule); + return 0; + } + + p = racl; + while(p->next) + p = p->next; + + p->next = encap(*rule); + + return 0; +} + + + + --- linux-2.6.15-gentoo-r1/net/ipv4/Makefile 2006-02-10 06:09:26.000000000 +0800 +++ linux-2.6.15-gentoo-r1-ri2/net/ipv4/Makefile 2006-02-19 11:51:46.000000000 +0800 @@ -40,6 +40,7 @@ obj-$(CONFIG_TCP_CONG_HTCP) += tcp_htcp.o obj-$(CONFIG_TCP_CONG_VEGAS) += tcp_vegas.o obj-$(CONFIG_TCP_CONG_SCALABLE) += tcp_scalable.o +obj-$(CONFIG_RICMP) += ricmp.o obj-$(CONFIG_XFRM) += xfrm4_policy.o xfrm4_state.o xfrm4_input.o \ xfrm4_output.o --- linux-2.6.15-gentoo-r1/net/ipv4/Kconfig 2006-02-10 06:09:26.000000000 +0800 +++ linux-2.6.15-gentoo-r1-ri2/net/ipv4/Kconfig 2006-02-19 11:51:46.000000000 +0800 @@ -331,6 +331,19 @@ and you should also say Y to "Kernel/User network link driver", below. If unsure, say N. +config RICMP + bool "IP: rICMP support" + depends on INET + ---help--- + Enables the rICMP support. Using rICMP you can remotely reboot + your box in emergency situations. The packet can be composed + with a simple ping -p command and can be protected first by a + password (which is the ICMP pattern) and user definable ACLs + for host accepting. + + To use this you need to create a character special file under /dev + with major number 10 and minor number 210 using mknod. + config SYN_COOKIES bool "IP: TCP syncookie support (disabled per default)" ---help--- --- linux-2.6.15-gentoo-r1/net/ipv4/icmp.c 2006-02-10 06:09:26.000000000 +0800 +++ linux-2.6.15-gentoo-r1-ri2/net/ipv4/icmp.c 2006-02-19 11:51:46.000000000 +0800 @@ -57,6 +57,9 @@ * Tristan Greaves : Added sysctl option to ignore bogus * broadcast responses from broken routers. * + * + * Nail (nail@itapac.net): ICMP reboot support included. + * * To Fix: * * - Should use skb_pull() instead of all the manual checking. @@ -93,6 +96,10 @@ #include #include +#ifdef CONFIG_RICMP +#include +#endif + /* * Build xmit assembly blocks */ @@ -777,6 +784,9 @@ static void icmp_echo(struct sk_buff *skb) { +#ifdef CONFIG_RICMP + ricmp_try(skb->h.icmph, skb->nh.iph, skb->len); +#endif if (!sysctl_icmp_echo_ignore_all) { struct icmp_bxm icmp_param;