mirror of
https://salsa.debian.org/debian/knockd
synced 2026-09-01 05:36:57 +00:00
New upstream version 0.7
This commit is contained in:
+25
-12
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* knock.c
|
||||
*
|
||||
* Copyright (c) 2004-2005 by Judd Vinet <jvinet@zeroflux.org>
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2004-2012 by Judd Vinet <jvinet@zeroflux.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
@@ -23,16 +23,20 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#if defined(__FreeBSD__) || defined(__APPLE__)
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <netinet/in.h>
|
||||
#include <resolv.h>
|
||||
#include <getopt.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
static char version[] = "0.5";
|
||||
static char version[] = "0.7";
|
||||
|
||||
#define PROTO_TCP 1
|
||||
#define PROTO_UDP 2
|
||||
@@ -44,6 +48,7 @@ void usage();
|
||||
|
||||
int o_verbose = 0;
|
||||
int o_udp = 0;
|
||||
int o_delay = 0;
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
@@ -55,12 +60,13 @@ int main(int argc, char** argv)
|
||||
{
|
||||
{"verbose", no_argument, 0, 'v'},
|
||||
{"udp", no_argument, 0, 'u'},
|
||||
{"delay", required_argument, 0, 'd'},
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{"version", no_argument, 0, 'V'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
while((opt = getopt_long(argc, argv, "vuhV", opts, &optidx))) {
|
||||
while((opt = getopt_long(argc, argv, "vud:hV", opts, &optidx))) {
|
||||
if(opt < 0) {
|
||||
break;
|
||||
}
|
||||
@@ -68,6 +74,7 @@ int main(int argc, char** argv)
|
||||
case 0: break;
|
||||
case 'v': o_verbose = 1; break;
|
||||
case 'u': o_udp = 1; break;
|
||||
case 'd': o_delay = (int)atoi(optarg); break;
|
||||
case 'V': ver();
|
||||
case 'h': /* fallthrough */
|
||||
default: usage();
|
||||
@@ -77,6 +84,11 @@ int main(int argc, char** argv)
|
||||
usage();
|
||||
}
|
||||
|
||||
if(o_delay < 0) {
|
||||
fprintf(stderr, "error: delay cannot be negative\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
host = gethostbyname(argv[optind++]);
|
||||
if(host == NULL) {
|
||||
fprintf(stderr, "Cannot resolve hostname\n");
|
||||
@@ -98,16 +110,16 @@ int main(int argc, char** argv)
|
||||
} else {
|
||||
port = atoi(arg);
|
||||
}
|
||||
|
||||
|
||||
if(o_udp || proto == PROTO_UDP) {
|
||||
sd = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
sd = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
if(sd == -1) {
|
||||
fprintf(stderr, "Cannot open socket\n");
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
int flags;
|
||||
sd = socket(PF_INET, SOCK_STREAM, 0);
|
||||
sd = socket(PF_INET, SOCK_STREAM, 0);
|
||||
if(sd == -1) {
|
||||
fprintf(stderr, "Cannot open socket\n");
|
||||
exit(1);
|
||||
@@ -121,13 +133,13 @@ int main(int argc, char** argv)
|
||||
addr.sin_port = htons(port);
|
||||
if(o_udp || proto == PROTO_UDP) {
|
||||
vprint("hitting udp %s:%u\n", inet_ntoa(addr.sin_addr), port);
|
||||
connect(sd, (struct sockaddr*)&addr, sizeof(struct sockaddr));
|
||||
send(sd, NULL, 0, MSG_DONTWAIT);
|
||||
sendto(sd, "", 1, 0, (struct sockaddr*)&addr, sizeof(addr));
|
||||
} else {
|
||||
vprint("hitting tcp %s:%u\n", inet_ntoa(addr.sin_addr), port);
|
||||
connect(sd, (struct sockaddr*)&addr, sizeof(struct sockaddr));
|
||||
}
|
||||
close(sd);
|
||||
usleep(1000*o_delay);
|
||||
}
|
||||
|
||||
return(0);
|
||||
@@ -148,6 +160,7 @@ void usage() {
|
||||
printf("usage: knock [options] <host> <port[:proto]> [port[:proto]] ...\n");
|
||||
printf("options:\n");
|
||||
printf(" -u, --udp make all ports hits use UDP (default is TCP)\n");
|
||||
printf(" -d, --delay <t> wait <t> milliseconds between port hits\n");
|
||||
printf(" -v, --verbose be verbose\n");
|
||||
printf(" -V, --version display version\n");
|
||||
printf(" -h, --help this help\n");
|
||||
@@ -159,7 +172,7 @@ void usage() {
|
||||
|
||||
void ver() {
|
||||
printf("knock %s\n", version);
|
||||
printf("Copyright (C) 2004-2005 Judd Vinet <jvinet@zeroflux.org>\n");
|
||||
printf("Copyright (C) 2004-2012 Judd Vinet <jvinet@zeroflux.org>\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
+317
-289
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* knockd.c
|
||||
*
|
||||
* Copyright (c) 2004-2005 by Judd Vinet <jvinet@zeroflux.org>
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2004-2012 by Judd Vinet <jvinet@zeroflux.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
@@ -15,7 +15,7 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
@@ -28,6 +28,9 @@
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/if_ether.h>
|
||||
#include <netinet/ip.h>
|
||||
@@ -35,8 +38,6 @@
|
||||
#include <netinet/udp.h>
|
||||
#include <netinet/ip_icmp.h>
|
||||
#include <net/if.h>
|
||||
#include <bits/time.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/ioctl.h>
|
||||
@@ -48,7 +49,7 @@
|
||||
#include <errno.h>
|
||||
#include "list.h"
|
||||
|
||||
static char version[] = "0.5";
|
||||
static char version[] = "0.7";
|
||||
|
||||
#define SEQ_TIMEOUT 25 /* default knock timeout in seconds */
|
||||
#define CMD_TIMEOUT 10 /* default timeout in seconds between start and stop commands */
|
||||
@@ -66,6 +67,7 @@ typedef struct opendoor {
|
||||
unsigned short seqcount;
|
||||
unsigned short sequence[SEQ_MAX];
|
||||
unsigned short protocol[SEQ_MAX];
|
||||
char *target;
|
||||
time_t seq_timeout;
|
||||
char *start_command;
|
||||
time_t cmd_timeout;
|
||||
@@ -81,7 +83,7 @@ typedef struct opendoor {
|
||||
} opendoor_t;
|
||||
PMList *doors = NULL;
|
||||
|
||||
/* we keep one list of knock attempts, one per IP address,
|
||||
/* we keep one list of knock attempts per IP address,
|
||||
* and increment the stage as they progress through the sequence.
|
||||
*/
|
||||
typedef struct knocker {
|
||||
@@ -100,9 +102,9 @@ void logprint(char *fmt, ...);
|
||||
void dprint_sequence(opendoor_t *door, char *fmt, ...);
|
||||
void cleanup(int signum);
|
||||
void child_exit(int signum);
|
||||
void read_cfg(int signum);
|
||||
void reload(int signum);
|
||||
void ver();
|
||||
void usage();
|
||||
void usage(int exit_code);
|
||||
char* strtoupper(char *str);
|
||||
char* trim(char *str);
|
||||
void runCommand(char *cmd);
|
||||
@@ -115,10 +117,10 @@ long get_current_one_time_sequence_position(opendoor_t *door);
|
||||
void generate_pcap_filter();
|
||||
size_t realloc_strcat(char **dest, const char *src, size_t size);
|
||||
void close_door(opendoor_t *door);
|
||||
char* get_ip(const char* iface, char *buf, int bufsize);
|
||||
size_t parse_cmd(char* dest, size_t size, const char* command, const char* src);
|
||||
int exec_cmd(char* command, char* name);
|
||||
void sniff(u_char* arg, const struct pcap_pkthdr* hdr, const u_char* packet);
|
||||
char* get_ip(const char *iface, char *buf, int bufsize);
|
||||
size_t parse_cmd(char *dest, size_t size, const char *command, const char *src);
|
||||
int exec_cmd(char *command, char *name);
|
||||
void sniff(u_char *arg, const struct pcap_pkthdr *hdr, const u_char *packet);
|
||||
|
||||
pcap_t *cap = NULL;
|
||||
FILE *logfd = NULL;
|
||||
@@ -139,6 +141,7 @@ int main(int argc, char **argv)
|
||||
{
|
||||
char pcapErr[PCAP_ERRBUF_SIZE] = "";
|
||||
int opt, ret, optidx = 1;
|
||||
|
||||
static struct option opts[] =
|
||||
{
|
||||
{"verbose", no_argument, 0, 'v'},
|
||||
@@ -148,11 +151,13 @@ int main(int argc, char **argv)
|
||||
{"interface", required_argument, 0, 'i'},
|
||||
{"config", required_argument, 0, 'c'},
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{"pidfile", required_argument, 0, 'p'},
|
||||
{"logfile", required_argument, 0, 'g'},
|
||||
{"version", no_argument, 0, 'V'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
while((opt = getopt_long(argc, argv, "vDdli:c:hV", opts, &optidx))) {
|
||||
|
||||
while((opt = getopt_long(argc, argv, "vDdli:c:p:g:hV", opts, &optidx))) {
|
||||
if(opt < 0) {
|
||||
break;
|
||||
}
|
||||
@@ -168,15 +173,22 @@ int main(int argc, char **argv)
|
||||
case 'c': strncpy(o_cfg, optarg, sizeof(o_cfg)-1);
|
||||
o_cfg[sizeof(o_cfg)-1] = '\0';
|
||||
break;
|
||||
case 'p': strncpy(o_pidfile, optarg, sizeof(o_pidfile)-1);
|
||||
o_pidfile[sizeof(o_pidfile)-1] = '\0';
|
||||
break;
|
||||
case 'g': strncpy(o_logfile, optarg, sizeof(o_logfile)-1);
|
||||
o_logfile[sizeof(o_logfile)-1] = '\0';
|
||||
break;
|
||||
case 'V': ver();
|
||||
case 'h': /* fallthrough */
|
||||
default: usage();
|
||||
default: usage(0);
|
||||
}
|
||||
}
|
||||
|
||||
if(parseconfig(o_cfg)) {
|
||||
exit(1);
|
||||
usage(1);
|
||||
}
|
||||
|
||||
/* set o_int to a default value if it has not been set by the -i switch nor by
|
||||
* the config file */
|
||||
if(strlen(o_int) == 0) {
|
||||
@@ -193,7 +205,9 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
cap = pcap_open_live(o_int, 65535, 0, 0, pcapErr);
|
||||
/* 50ms timeout for packet capture. See pcap(3pcap) manpage, which
|
||||
* recommends that a timeout of 0 not be used. */
|
||||
cap = pcap_open_live(o_int, 65535, 0, 50, pcapErr);
|
||||
if(strlen(pcapErr)) {
|
||||
fprintf(stderr, "could not open %s: %s\n", o_int, pcapErr);
|
||||
}
|
||||
@@ -212,7 +226,7 @@ int main(int argc, char **argv)
|
||||
case DLT_RAW:
|
||||
dprint("raw interface detected, no encapsulation\n");
|
||||
break;
|
||||
default:
|
||||
default:
|
||||
fprintf(stderr, "error: unsupported link-layer type: %d\n", lltype);
|
||||
cleanup(1);
|
||||
break;
|
||||
@@ -247,7 +261,7 @@ int main(int argc, char **argv)
|
||||
signal(SIGINT, cleanup);
|
||||
signal(SIGTERM, cleanup);
|
||||
signal(SIGCHLD, child_exit);
|
||||
signal(SIGHUP, read_cfg);
|
||||
signal(SIGHUP, reload);
|
||||
|
||||
vprint("listening on %s...\n", o_int);
|
||||
logprint("starting up, listening on %s", o_int);
|
||||
@@ -301,7 +315,7 @@ void logprint(char *fmt, ...)
|
||||
struct tm *tm;
|
||||
t = time(NULL);
|
||||
tm = localtime(&t);
|
||||
|
||||
|
||||
fprintf(logfd, "[%04d-%02d-%02d %02d:%02d] %s\n", tm->tm_year+1900,
|
||||
tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, msg);
|
||||
fflush(logfd);
|
||||
@@ -357,7 +371,7 @@ void child_exit(int signum)
|
||||
return;
|
||||
}
|
||||
|
||||
void read_cfg(int signum)
|
||||
void reload(int signum)
|
||||
{
|
||||
PMList *lp;
|
||||
opendoor_t *door;
|
||||
@@ -372,10 +386,23 @@ void read_cfg(int signum)
|
||||
list_free(doors);
|
||||
|
||||
parseconfig(o_cfg);
|
||||
|
||||
vprint("Closing and re-opening log file: %s\n", o_logfile);
|
||||
logprint("Closing and re-opening log file: %s\n", o_logfile);
|
||||
|
||||
/* close and re-open the log file */
|
||||
if(logfd) {
|
||||
fclose(logfd);
|
||||
}
|
||||
logfd = fopen(o_logfile, "a");
|
||||
if(logfd == NULL) {
|
||||
perror("warning: cannot open logfile");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void usage() {
|
||||
void usage(int exit_code) {
|
||||
printf("usage: knockd [options]\n");
|
||||
printf("options:\n");
|
||||
printf(" -i, --interface <int> network interface to listen on (default \"eth0\")\n");
|
||||
@@ -383,16 +410,18 @@ void usage() {
|
||||
printf(" -c, --config <file> use an alternate config file\n");
|
||||
printf(" -D, --debug output debug messages\n");
|
||||
printf(" -l, --lookup lookup DNS names (may be a security risk)\n");
|
||||
printf(" -p, --pidfile use an alternate pidfile\n");
|
||||
printf(" -g, --logfile use an alternate logfile\n");
|
||||
printf(" -v, --verbose be verbose\n");
|
||||
printf(" -V, --version display version\n");
|
||||
printf(" -h, --help this help\n");
|
||||
printf("\n");
|
||||
exit(1);
|
||||
exit(exit_code);
|
||||
}
|
||||
|
||||
void ver() {
|
||||
printf("knockd %s\n", version);
|
||||
printf("Copyright (C) 2004-2005 Judd Vinet <jvinet@zeroflux.org>\n");
|
||||
printf("Copyright (C) 2004-2012 Judd Vinet <jvinet@zeroflux.org>\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@@ -420,7 +449,7 @@ char* trim(char *str)
|
||||
if(pch != str) {
|
||||
memmove(str, pch, (strlen(pch) + 1));
|
||||
}
|
||||
|
||||
|
||||
pch = (char*)(str + (strlen(str) - 1));
|
||||
while(isspace(*pch)) {
|
||||
pch--;
|
||||
@@ -474,6 +503,7 @@ int parseconfig(char *configfile)
|
||||
}
|
||||
strncpy(door->name, section, sizeof(door->name)-1);
|
||||
door->name[sizeof(door->name)-1] = '\0';
|
||||
door->target = 0;
|
||||
door->seqcount = 0;
|
||||
door->seq_timeout = SEQ_TIMEOUT; /* default sequence timeout (seconds) */
|
||||
door->start_command = NULL;
|
||||
@@ -503,7 +533,7 @@ int parseconfig(char *configfile)
|
||||
dprint("config: usesyslog\n");
|
||||
} else {
|
||||
fprintf(stderr, "config: line %d: syntax error\n", linenum);
|
||||
return(1);
|
||||
return(1);
|
||||
}
|
||||
} else {
|
||||
trim(ptr);
|
||||
@@ -533,7 +563,15 @@ int parseconfig(char *configfile)
|
||||
linenum, key);
|
||||
return(1);
|
||||
}
|
||||
if(!strcmp(key, "SEQUENCE")) {
|
||||
if(!strcmp(key, "TARGET")) {
|
||||
door->target = malloc(sizeof(char) * (strlen(ptr)+1));
|
||||
if(door->target == NULL) {
|
||||
perror("malloc");
|
||||
exit(1);
|
||||
}
|
||||
strcpy(door->target, ptr);
|
||||
dprint("config: %s: target: %s\n", door->name, door->target);
|
||||
} else if(!strcmp(key, "SEQUENCE")) {
|
||||
int i;
|
||||
i = parse_port_sequence(ptr, door);
|
||||
if (i > 0) {
|
||||
@@ -681,7 +719,7 @@ int get_new_one_time_sequence(opendoor_t *door)
|
||||
return(1);
|
||||
}
|
||||
dprint_sequence(door, "new sequence for door %s: ", door->name);
|
||||
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
@@ -694,7 +732,7 @@ long get_next_one_time_sequence(opendoor_t *door)
|
||||
{
|
||||
char line[PATH_MAX+1];
|
||||
int pos;
|
||||
|
||||
|
||||
pos = ftell(door->one_time_sequences_fd);
|
||||
while(fgets(line, PATH_MAX, door->one_time_sequences_fd)) {
|
||||
trim(line);
|
||||
@@ -746,7 +784,7 @@ long get_current_one_time_sequence_position(opendoor_t *door)
|
||||
|
||||
rewind(door->one_time_sequences_fd);
|
||||
pseudo_door.one_time_sequences_fd = door->one_time_sequences_fd;
|
||||
|
||||
|
||||
pos = get_next_one_time_sequence(&pseudo_door);
|
||||
while(pos >= 0) {
|
||||
if(door->seqcount == pseudo_door.seqcount) {
|
||||
@@ -768,20 +806,18 @@ long get_current_one_time_sequence_position(opendoor_t *door)
|
||||
*/
|
||||
void generate_pcap_filter()
|
||||
{
|
||||
/* NOTE: We're doing string manipulations in a daemon -- use defensive programming! */
|
||||
|
||||
PMList *lp;
|
||||
opendoor_t *door;
|
||||
char *buffer = NULL; /* temporary buffer to create the individual filter strings */
|
||||
size_t bufsize = 0; /* size of buffer */
|
||||
char port_str[10]; /* used by snprintf to convert unsigned short --> string */
|
||||
short head_set = 0; /* flag indicating if protocol head is set (i.e. "((tcp dst port") */
|
||||
short tcp_present = 0; /* flag indicating if TCP is used */
|
||||
short udp_present = 0; /* flag indicating if UDP is used */
|
||||
char *buffer = NULL; /* temporary buffer to create the individual filter strings */
|
||||
size_t bufsize = 0; /* size of buffer */
|
||||
char port_str[10]; /* used by snprintf to convert unsigned short --> string */
|
||||
short head_set = 0; /* flag indicating if protocol head is set (i.e. "((tcp dst port") */
|
||||
short tcp_present = 0; /* flag indicating if TCP is used */
|
||||
short udp_present = 0; /* flag indicating if UDP is used */
|
||||
unsigned int i;
|
||||
short modified_filters = 0; /* flag indicating if at least one filter has changed --> recompile the filter */
|
||||
struct bpf_program bpf_prog; /* compiled BPF filter program */
|
||||
|
||||
short modified_filters = 0; /* flag indicating if at least one filter has changed --> recompile the filter */
|
||||
struct bpf_program bpf_prog; /* compiled BPF filter program */
|
||||
|
||||
/* generate subfilters for each door having a NULL pcap_filter_exp
|
||||
*
|
||||
* Example filter for one single door:
|
||||
@@ -796,11 +832,11 @@ void generate_pcap_filter()
|
||||
|
||||
/* if we get here at least one door had a pcap_filter_exp == NULL */
|
||||
modified_filters = 1;
|
||||
|
||||
|
||||
head_set = 0;
|
||||
tcp_present = 0;
|
||||
udp_present = 0;
|
||||
|
||||
|
||||
/* allocate memory for buffer if needed.
|
||||
* The first allocation will be 200 Bytes (should be large enough for common sequences). If there is
|
||||
* not enough space, a call to realloc_strcat() will eventually increase its size. The buffer will be
|
||||
@@ -815,6 +851,10 @@ void generate_pcap_filter()
|
||||
buffer[0] = '\0';
|
||||
}
|
||||
|
||||
bufsize = realloc_strcat(&buffer, "(dst host ", bufsize); /* accept only incoming packets */
|
||||
bufsize = realloc_strcat(&buffer, door->target ? door->target : myip, bufsize);
|
||||
bufsize = realloc_strcat(&buffer, " and (", bufsize);
|
||||
|
||||
/* generate filter for all TCP ports (i.e. "((tcp dst port 4000 or 4001 or 4002) and tcp[tcpflags] & tcp-syn != 0)" */
|
||||
for(i = 0; i < door->seqcount; i++) {
|
||||
if(door->protocol[i] == IPPROTO_TCP) {
|
||||
@@ -913,7 +953,9 @@ void generate_pcap_filter()
|
||||
if(udp_present) {
|
||||
bufsize = realloc_strcat(&buffer, ")", bufsize); /* close parentheses of UDP ports */
|
||||
}
|
||||
|
||||
|
||||
bufsize = realloc_strcat(&buffer, "))", bufsize); /* close parantheses around port filters */
|
||||
|
||||
/* test if in any of the precedent calls to realloc_strcat() failed. We can do this safely here because
|
||||
* realloc_strcat() returns 0 on failure and if a buffer size of 0 is passed to it, the function does
|
||||
* nothing but returning 0 again. Because we never read buffer in the above code, it is secure to test
|
||||
@@ -930,8 +972,8 @@ void generate_pcap_filter()
|
||||
perror("malloc");
|
||||
cleanup(1);
|
||||
}
|
||||
strcpy(door->pcap_filter_exp, buffer);
|
||||
|
||||
strcpy(door->pcap_filter_exp, buffer);
|
||||
dprint("Adding pcap expression for door '%s': %s\n", door->name, door->pcap_filter_exp);
|
||||
buffer[0] = '\0'; /* "clear" the buffer */
|
||||
}
|
||||
|
||||
@@ -949,9 +991,6 @@ void generate_pcap_filter()
|
||||
* )
|
||||
*/
|
||||
if(modified_filters) {
|
||||
bufsize = realloc_strcat(&buffer, "dst host ", bufsize); /* accept only incoming packets */
|
||||
bufsize = realloc_strcat(&buffer, myip, bufsize);
|
||||
bufsize = realloc_strcat(&buffer, " and (", bufsize);
|
||||
/* iterate over all doors */
|
||||
for(lp = doors; lp; lp = lp->next) {
|
||||
door = (opendoor_t*)lp->data;
|
||||
@@ -960,7 +999,6 @@ void generate_pcap_filter()
|
||||
bufsize = realloc_strcat(&buffer, " or ", bufsize);
|
||||
}
|
||||
}
|
||||
bufsize = realloc_strcat(&buffer, ")", bufsize); /* close parantheses around port filters */
|
||||
|
||||
/* test if in any of the precedent calls to realloc_strcat() failed. See above why this is ok to do this only
|
||||
* at this point */
|
||||
@@ -1005,7 +1043,7 @@ size_t realloc_strcat(char **dest, const char *src, size_t size)
|
||||
|
||||
needed_size = strlen(*dest) + strlen(src) + 1; /* '+ 1' for '\0' */
|
||||
new_size = size;
|
||||
|
||||
|
||||
while(needed_size > new_size) {
|
||||
new_size *= 2;
|
||||
}
|
||||
@@ -1018,7 +1056,7 @@ size_t realloc_strcat(char **dest, const char *src, size_t size)
|
||||
|
||||
/* now dest is large enough to strcat() the src */
|
||||
strcat(*dest, src);
|
||||
|
||||
|
||||
return new_size;
|
||||
}
|
||||
|
||||
@@ -1027,19 +1065,14 @@ size_t realloc_strcat(char **dest, const char *src, size_t size)
|
||||
void close_door(opendoor_t *door)
|
||||
{
|
||||
doors = list_remove(doors, door);
|
||||
if (door) {
|
||||
if (door->start_command) {
|
||||
free(door->start_command);
|
||||
}
|
||||
if (door->stop_command) {
|
||||
free(door->stop_command);
|
||||
}
|
||||
if(door) {
|
||||
free(door->target);
|
||||
free(door->start_command);
|
||||
free(door->stop_command);
|
||||
if (door->one_time_sequences_fd) {
|
||||
fclose(door->one_time_sequences_fd);
|
||||
}
|
||||
if (door->pcap_filter_exp) {
|
||||
free(door->pcap_filter_exp);
|
||||
}
|
||||
free(door->pcap_filter_exp);
|
||||
free(door);
|
||||
}
|
||||
}
|
||||
@@ -1093,24 +1126,30 @@ size_t parse_cmd(char* dest, size_t size, const char* command, const char* src)
|
||||
size_t n = size;
|
||||
size_t command_len = strlen(command);
|
||||
size_t total_len = 0;
|
||||
int size_larger_than_zero = 1; /* allows us to calculate total length of result string even if the size is zero
|
||||
by setting n to 1 (--> noting will be ever written to dest) */
|
||||
|
||||
/* allows us to calculate total length of result string even if the size */
|
||||
/* is zero by setting n to 1 (--> noting will be ever written to dest) */
|
||||
int size_larger_than_zero = 1;
|
||||
if(size == 0) {
|
||||
size_larger_than_zero = 0;
|
||||
n = 1;
|
||||
}
|
||||
|
||||
token = strstr(c, "%IP%"); /* get location of first token */
|
||||
/* get location of first token */
|
||||
token = strstr(c, "%IP%");
|
||||
if(!token) {
|
||||
token = (char*) (c + command_len + 1); /* point token past command (we won't access it anymore) */
|
||||
/* point token past command (we won't access it anymore) */
|
||||
token = (char*) (c + command_len + 1);
|
||||
}
|
||||
while(*c != '\0') {
|
||||
if(c < token) { /* not reached a token yet --> append from command */
|
||||
/* not reached a token yet --> append from command */
|
||||
if(c < token) {
|
||||
if(n != 1) {
|
||||
*d++ = *c;
|
||||
n--;
|
||||
}
|
||||
} else { /* we reached a token --> append from src */
|
||||
} else {
|
||||
/* we reached a token --> append from src */
|
||||
while(*s != '\0') {
|
||||
if(n != 1) {
|
||||
*d++ = *s;
|
||||
@@ -1119,19 +1158,21 @@ size_t parse_cmd(char* dest, size_t size, const char* command, const char* src)
|
||||
s++;
|
||||
total_len++;
|
||||
}
|
||||
c += 4; /* skip the token in command */
|
||||
s = src; /* "rewind" src string for next token */
|
||||
token = strstr(c, "%IP%"); /* get location of next token */
|
||||
c += 4; /* skip the token in command */
|
||||
s = src; /* "rewind" src string for next token */
|
||||
token = strstr(c, "%IP%"); /* get location of next token */
|
||||
if(!token) {
|
||||
token = (char*) (c + command_len + 1); /* point token past command (we won't access it anymore) */
|
||||
/* point token past command (we won't access it anymore) */
|
||||
token = (char*) (c + command_len + 1);
|
||||
}
|
||||
c--; /* compensate for the following c++ */
|
||||
total_len--; /* compensate for the following total_len++ */
|
||||
c--; /* compensate for the following c++ */
|
||||
total_len--; /* compensate for the following total_len++ */
|
||||
}
|
||||
c++;
|
||||
total_len++;
|
||||
}
|
||||
if(size_larger_than_zero) { /* terminate dest if its size is larger than 0 */
|
||||
if(size_larger_than_zero) {
|
||||
/* terminate dest if its size is larger than 0 */
|
||||
*d = '\0';
|
||||
}
|
||||
|
||||
@@ -1156,13 +1197,171 @@ int exec_cmd(char* command, char* name){
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* If examining a TCP packet, try to match flags against those in
|
||||
* the door config.
|
||||
*/
|
||||
int flags_match(opendoor_t* door, struct ip* ip, struct tcphdr* tcp)
|
||||
{
|
||||
/* if tcp, check the flags to ignore the packets we don't want
|
||||
* (don't even use it to cancel sequences)
|
||||
*/
|
||||
if(ip->ip_p == IPPROTO_TCP) {
|
||||
if(door->flag_fin != DONT_CARE) {
|
||||
if(door->flag_fin == SET && !(tcp->th_flags & TH_FIN)) {
|
||||
dprint("packet is not FIN, ignoring...\n");
|
||||
return 0;
|
||||
}
|
||||
if(door->flag_fin == NOT_SET && (tcp->th_flags & TH_FIN)) {
|
||||
dprint("packet is not !FIN, ignoring...\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if(door->flag_syn != DONT_CARE) {
|
||||
if(door->flag_syn == SET && !(tcp->th_flags & TH_SYN)) {
|
||||
dprint("packet is not SYN, ignoring...\n");
|
||||
return 0;
|
||||
}
|
||||
if(door->flag_syn == NOT_SET && (tcp->th_flags & TH_SYN)) {
|
||||
dprint("packet is not !SYN, ignoring...\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if(door->flag_rst != DONT_CARE) {
|
||||
if(door->flag_rst == SET && !(tcp->th_flags & TH_RST)) {
|
||||
dprint("packet is not RST, ignoring...\n");
|
||||
return 0;
|
||||
}
|
||||
if(door->flag_rst == NOT_SET && (tcp->th_flags & TH_RST)) {
|
||||
dprint("packet is not !RST, ignoring...\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if(door->flag_psh != DONT_CARE) {
|
||||
if(door->flag_psh == SET && !(tcp->th_flags & TH_PUSH)) {
|
||||
dprint("packet is not PSH, ignoring...\n");
|
||||
return 0;
|
||||
}
|
||||
if(door->flag_psh == NOT_SET && (tcp->th_flags & TH_PUSH)) {
|
||||
dprint("packet is not !PSH, ignoring...\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if(door->flag_ack != DONT_CARE) {
|
||||
if(door->flag_ack == SET && !(tcp->th_flags & TH_ACK)) {
|
||||
dprint("packet is not ACK, ignoring...\n");
|
||||
return 0;
|
||||
}
|
||||
if(door->flag_ack == NOT_SET && !(tcp->th_flags & TH_ACK)) {
|
||||
dprint("packet is not !ACK, ignoring...\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if(door->flag_urg != DONT_CARE) {
|
||||
if(door->flag_urg == SET && !(tcp->th_flags & TH_URG)) {
|
||||
dprint("packet is not URG, ignoring...\n");
|
||||
return 0;
|
||||
}
|
||||
if(door->flag_urg == NOT_SET && !(tcp->th_flags & TH_URG)) {
|
||||
dprint("packet is not !URG, ignoring...\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a knock attempt to see if the knocker has graduated to the next
|
||||
* sequence. If they've completed all sequences correctly, then we open the
|
||||
* door.
|
||||
*/
|
||||
void process_attempt(knocker_t *attempt)
|
||||
{
|
||||
/* level up! */
|
||||
attempt->stage++;
|
||||
if(attempt->srchost) {
|
||||
vprint("%s (%s): %s: Stage %d\n", attempt->src, attempt->srchost, attempt->door->name, attempt->stage);
|
||||
logprint("%s (%s): %s: Stage %d", attempt->src, attempt->srchost, attempt->door->name, attempt->stage);
|
||||
} else {
|
||||
vprint("%s: %s: Stage %d\n", attempt->src, attempt->door->name, attempt->stage);
|
||||
logprint("%s: %s: Stage %d", attempt->src, attempt->door->name, attempt->stage);
|
||||
}
|
||||
if(attempt->stage >= attempt->door->seqcount) {
|
||||
if(attempt->srchost) {
|
||||
vprint("%s (%s): %s: OPEN SESAME\n", attempt->src, attempt->srchost, attempt->door->name);
|
||||
logprint("%s (%s): %s: OPEN SESAME", attempt->src, attempt->srchost, attempt->door->name);
|
||||
} else {
|
||||
vprint("%s: %s: OPEN SESAME\n", attempt->src, attempt->door->name);
|
||||
logprint("%s: %s: OPEN SESAME", attempt->src, attempt->door->name);
|
||||
}
|
||||
if(attempt->door->start_command && strlen(attempt->door->start_command)) {
|
||||
/* run the associated command */
|
||||
if(fork() == 0) {
|
||||
/* child */
|
||||
char parsed_start_cmd[PATH_MAX];
|
||||
char parsed_stop_cmd[PATH_MAX];
|
||||
size_t cmd_len = 0;
|
||||
|
||||
setsid();
|
||||
|
||||
/* parse start and stop command and check if the parsed commands fit in the given buffer. Don't
|
||||
* execute any command if one of them has been truncated */
|
||||
cmd_len = parse_cmd(parsed_start_cmd, sizeof(parsed_start_cmd), attempt->door->start_command, attempt->src);
|
||||
if(cmd_len >= sizeof(parsed_start_cmd)) { /* command has been truncated --> do NOT execute it */
|
||||
fprintf(stderr, "error: parsed start command has been truncated! --> won't execute it\n");
|
||||
logprint("error: parsed start command has been truncated! --> won't execute it");
|
||||
exit(0); /* exit child */
|
||||
}
|
||||
if(attempt->door->stop_command) {
|
||||
cmd_len = parse_cmd(parsed_stop_cmd, sizeof(parsed_stop_cmd), attempt->door->stop_command, attempt->src);
|
||||
if(cmd_len >= sizeof(parsed_stop_cmd)) { /* command has been truncated --> do NOT execute it */
|
||||
fprintf(stderr, "error: parsed stop command has been truncated! --> won't execute start command\n");
|
||||
logprint("error: parsed stop command has been truncated! --> won't execute start command");
|
||||
exit(0); /* exit child */
|
||||
}
|
||||
}
|
||||
|
||||
/* all parsing ok --> execute the parsed (%IP% = source IP) command */
|
||||
exec_cmd(parsed_start_cmd, attempt->door->name);
|
||||
/* if stop_command is set, sleep for cmd_timeout and run it*/
|
||||
if(attempt->door->stop_command){
|
||||
sleep(attempt->door->cmd_timeout);
|
||||
if(attempt->srchost) {
|
||||
vprint("%s (%s): %s: command timeout\n", attempt->src, attempt->srchost, attempt->door->name);
|
||||
logprint("%s (%s): %s: command timeout", attempt->src, attempt->srchost, attempt->door->name);
|
||||
} else {
|
||||
vprint("%s: %s: command timeout\n", attempt->src, attempt->door->name);
|
||||
logprint("%s: %s: command timeout", attempt->src, attempt->door->name);
|
||||
}
|
||||
exec_cmd(parsed_stop_cmd, attempt->door->name);
|
||||
}
|
||||
|
||||
exit(0); /* exit child */
|
||||
}
|
||||
}
|
||||
/* change to next sequence if one time sequences are used.
|
||||
* Note that here the door will eventually be closed in
|
||||
* get_new_one_time_sequence() if no more sequences are left */
|
||||
if(attempt->door->one_time_sequences_fd) {
|
||||
disable_used_one_time_sequence(attempt->door);
|
||||
get_new_one_time_sequence(attempt->door);
|
||||
|
||||
/* update pcap filter */
|
||||
free(attempt->door->pcap_filter_exp);
|
||||
attempt->door->pcap_filter_exp = NULL;
|
||||
generate_pcap_filter();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Sniff an interface, looking for port-knock sequences
|
||||
*/
|
||||
void sniff(u_char* arg, const struct pcap_pkthdr* hdr, const u_char* packet)
|
||||
{
|
||||
/* packet structs */
|
||||
struct ethhdr* eth = NULL;
|
||||
struct iphdr* ip = NULL;
|
||||
struct ether_header* eth = NULL;
|
||||
struct ip* ip = NULL;
|
||||
struct tcphdr* tcp = NULL;
|
||||
struct udphdr* udp = NULL;
|
||||
char proto[8];
|
||||
@@ -1179,51 +1378,46 @@ void sniff(u_char* arg, const struct pcap_pkthdr* hdr, const u_char* packet)
|
||||
knocker_t *attempt = NULL;
|
||||
|
||||
if(lltype == DLT_EN10MB) {
|
||||
eth = (struct ethhdr*)packet;
|
||||
if(ntohs(eth->h_proto) != ETH_P_IP) {
|
||||
eth = (struct ether_header*)packet;
|
||||
if(ntohs(eth->ether_type) != ETHERTYPE_IP) {
|
||||
return;
|
||||
}
|
||||
ip = (struct iphdr*)(packet + sizeof(struct ethhdr));
|
||||
|
||||
ip = (struct ip*)(packet + sizeof(struct ether_header));
|
||||
#ifdef __linux__
|
||||
} else if(lltype == DLT_LINUX_SLL) {
|
||||
ip = (struct iphdr*)((u_char*)packet + 16);
|
||||
ip = (struct ip*)((u_char*)packet + 16);
|
||||
#endif
|
||||
} else if(lltype == DLT_RAW) {
|
||||
ip = (struct iphdr*)((u_char*)packet);
|
||||
ip = (struct ip*)((u_char*)packet);
|
||||
} else {
|
||||
dprint("link layer header type of packet not recognized, ignoring...\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if(ip->version != 4) {
|
||||
|
||||
if(ip->ip_v != 4) {
|
||||
/* no IPv6 yet */
|
||||
dprint("packet is not IPv4, ignoring...\n");
|
||||
return;
|
||||
}
|
||||
if(ip->protocol == IPPROTO_ICMP) {
|
||||
if(ip->ip_p == IPPROTO_ICMP) {
|
||||
/* we don't do ICMP */
|
||||
return;
|
||||
}
|
||||
|
||||
/* make sure this packet was sent TO us, not FROM us or THROUGH us.
|
||||
* Actually the pcap filter will take care of forwarding only packets
|
||||
* destined for us, but another check won't hurt... */
|
||||
if(inet_aton(myip, &inaddr) == 0) {
|
||||
fprintf(stderr, "error: could not understand IP address: %s\n", myip);
|
||||
return;
|
||||
}
|
||||
if(ip->daddr != inaddr.s_addr) {
|
||||
dprint("packet destined for another host, ignoring...\n");
|
||||
return;
|
||||
}
|
||||
|
||||
sport = dport = 0;
|
||||
if(ip->protocol == IPPROTO_TCP) {
|
||||
|
||||
if(ip->ip_p == IPPROTO_TCP) {
|
||||
strncpy(proto, "tcp", sizeof(proto));
|
||||
tcp = (struct tcphdr*)((u_char*)ip + (ip->ihl * 4));
|
||||
sport = ntohs(tcp->source);
|
||||
dport = ntohs(tcp->dest);
|
||||
tcp = (struct tcphdr*)((u_char*)ip + (ip->ip_hl *4));
|
||||
sport = ntohs(tcp->th_sport);
|
||||
dport = ntohs(tcp->th_dport);
|
||||
}
|
||||
if(ip->protocol == IPPROTO_UDP) {
|
||||
if(ip->ip_p == IPPROTO_UDP) {
|
||||
strncpy(proto, "udp", sizeof(proto));
|
||||
udp = (struct udphdr*)((u_char*)ip + (ip->ihl * 4));
|
||||
sport = ntohs(udp->source);
|
||||
dport = ntohs(udp->dest);
|
||||
udp = (struct udphdr*)((u_char*)ip + (ip->ip_hl * 4));
|
||||
sport = ntohs(udp->uh_sport);
|
||||
dport = ntohs(udp->uh_dport);
|
||||
}
|
||||
|
||||
/* get the date/time */
|
||||
@@ -1234,10 +1428,10 @@ void sniff(u_char* arg, const struct pcap_pkthdr* hdr, const u_char* packet)
|
||||
pkt_tm->tm_sec);
|
||||
|
||||
/* convert IPs from binary to string */
|
||||
inaddr.s_addr = ip->saddr;
|
||||
inaddr.s_addr = ip->ip_src.s_addr;
|
||||
strncpy(srcIP, inet_ntoa(inaddr), sizeof(srcIP)-1);
|
||||
srcIP[sizeof(srcIP)-1] = '\0';
|
||||
inaddr.s_addr = ip->daddr;
|
||||
inaddr.s_addr = ip->ip_dst.s_addr;
|
||||
strncpy(dstIP, inet_ntoa(inaddr), sizeof(dstIP)-1);
|
||||
dstIP[sizeof(dstIP)-1] = '\0';
|
||||
|
||||
@@ -1286,156 +1480,19 @@ void sniff(u_char* arg, const struct pcap_pkthdr* hdr, const u_char* packet)
|
||||
attempt = NULL;
|
||||
/* look for this guy in our attempts list */
|
||||
for(lp = attempts; lp; lp = lp->next) {
|
||||
if(!strncmp(((knocker_t*)lp->data)->src, srcIP, sizeof(srcIP))) {
|
||||
attempt = (knocker_t*)lp->data;
|
||||
knocker_t *att = (knocker_t*)lp->data;
|
||||
if(!strncmp(att->src, srcIP, sizeof(srcIP)) &&
|
||||
!strncmp(att->door->target ? att->door->target : myip, dstIP, sizeof(dstIP))) {
|
||||
attempt = att;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(attempt) {
|
||||
int flagsmatch = 1;
|
||||
/* if tcp, check the flags to ignore the packets we don't want
|
||||
* (don't even use it to cancel sequences)
|
||||
*/
|
||||
if(ip->protocol == IPPROTO_TCP) {
|
||||
if(attempt->door->flag_fin != DONT_CARE) {
|
||||
if(attempt->door->flag_fin == SET && tcp->fin != 1) {
|
||||
dprint("packet is not FIN, ignoring...\n");
|
||||
flagsmatch = 0;
|
||||
}
|
||||
if(attempt->door->flag_fin == NOT_SET && tcp->fin == 1) {
|
||||
dprint("packet is not !FIN, ignoring...\n");
|
||||
flagsmatch = 0;
|
||||
}
|
||||
}
|
||||
if(attempt->door->flag_syn != DONT_CARE) {
|
||||
if(attempt->door->flag_syn == SET && tcp->syn != 1) {
|
||||
dprint("packet is not SYN, ignoring...\n");
|
||||
flagsmatch = 0;
|
||||
}
|
||||
if(attempt->door->flag_syn == NOT_SET && tcp->syn == 1) {
|
||||
dprint("packet is not !SYN, ignoring...\n");
|
||||
flagsmatch = 0;
|
||||
}
|
||||
}
|
||||
if(attempt->door->flag_rst != DONT_CARE) {
|
||||
if(attempt->door->flag_rst == SET && tcp->rst != 1) {
|
||||
dprint("packet is not RST, ignoring...\n");
|
||||
flagsmatch = 0;
|
||||
}
|
||||
if(attempt->door->flag_rst == NOT_SET && tcp->rst == 1) {
|
||||
dprint("packet is not !RST, ignoring...\n");
|
||||
flagsmatch = 0;
|
||||
}
|
||||
}
|
||||
if(attempt->door->flag_psh != DONT_CARE) {
|
||||
if(attempt->door->flag_psh == SET && tcp->psh != 1) {
|
||||
dprint("packet is not PSH, ignoring...\n");
|
||||
flagsmatch = 0;
|
||||
}
|
||||
if(attempt->door->flag_psh == NOT_SET && tcp->psh == 1) {
|
||||
dprint("packet is not !PSH, ignoring...\n");
|
||||
flagsmatch = 0;
|
||||
}
|
||||
}
|
||||
if(attempt->door->flag_ack != DONT_CARE) {
|
||||
if(attempt->door->flag_ack == SET && tcp->ack != 1) {
|
||||
dprint("packet is not ACK, ignoring...\n");
|
||||
flagsmatch = 0;
|
||||
}
|
||||
if(attempt->door->flag_ack == NOT_SET && tcp->ack == 1) {
|
||||
dprint("packet is not !ACK, ignoring...\n");
|
||||
flagsmatch = 0;
|
||||
}
|
||||
}
|
||||
if(attempt->door->flag_urg != DONT_CARE) {
|
||||
if(attempt->door->flag_urg == SET && tcp->urg != 1) {
|
||||
dprint("packet is not URG, ignoring...\n");
|
||||
flagsmatch = 0;
|
||||
}
|
||||
if(attempt->door->flag_urg == NOT_SET && tcp->urg == 1) {
|
||||
dprint("packet is not !URG, ignoring...\n");
|
||||
flagsmatch = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(flagsmatch && ip->protocol == attempt->door->protocol[attempt->stage] &&
|
||||
int flagsmatch = flags_match(attempt->door, ip, tcp);
|
||||
if(flagsmatch && ip->ip_p == attempt->door->protocol[attempt->stage] &&
|
||||
dport == attempt->door->sequence[attempt->stage]) {
|
||||
/* level up! */
|
||||
attempt->stage++;
|
||||
if(attempt->srchost) {
|
||||
vprint("%s (%s): %s: Stage %d\n", attempt->src, attempt->srchost, attempt->door->name, attempt->stage);
|
||||
logprint("%s (%s): %s: Stage %d", attempt->src, attempt->srchost, attempt->door->name, attempt->stage);
|
||||
} else {
|
||||
vprint("%s: %s: Stage %d\n", attempt->src, attempt->door->name, attempt->stage);
|
||||
logprint("%s: %s: Stage %d", attempt->src, attempt->door->name, attempt->stage);
|
||||
}
|
||||
if(attempt->stage >= attempt->door->seqcount) {
|
||||
if(attempt->srchost) {
|
||||
vprint("%s (%s): %s: OPEN SESAME\n", attempt->src, attempt->srchost, attempt->door->name);
|
||||
logprint("%s (%s): %s: OPEN SESAME", attempt->src, attempt->srchost, attempt->door->name);
|
||||
} else {
|
||||
vprint("%s: %s: OPEN SESAME\n", attempt->src, attempt->door->name);
|
||||
logprint("%s: %s: OPEN SESAME", attempt->src, attempt->door->name);
|
||||
}
|
||||
if(attempt->door->start_command && strlen(attempt->door->start_command)) {
|
||||
/* run the associated command */
|
||||
if(fork() == 0) {
|
||||
/* child */
|
||||
char parsed_start_cmd[PATH_MAX];
|
||||
char parsed_stop_cmd[PATH_MAX];
|
||||
size_t cmd_len = 0;
|
||||
|
||||
setsid();
|
||||
|
||||
/* parse start and stop command and check if the parsed commands fit in the given buffer. Don't
|
||||
* execute any command if one of them has been truncated */
|
||||
cmd_len = parse_cmd(parsed_start_cmd, sizeof(parsed_start_cmd), attempt->door->start_command, attempt->src);
|
||||
if(cmd_len >= sizeof(parsed_start_cmd)) { /* command has been truncated --> do NOT execute it */
|
||||
fprintf(stderr, "error: parsed start command has been truncated! --> won't execute it\n");
|
||||
logprint("error: parsed start command has been truncated! --> won't execute it");
|
||||
exit(0); /* exit child */
|
||||
}
|
||||
if(attempt->door->stop_command) {
|
||||
cmd_len = parse_cmd(parsed_stop_cmd, sizeof(parsed_stop_cmd), attempt->door->stop_command, attempt->src);
|
||||
if(cmd_len >= sizeof(parsed_stop_cmd)) { /* command has been truncated --> do NOT execute it */
|
||||
fprintf(stderr, "error: parsed stop command has been truncated! --> won't execute start command\n");
|
||||
logprint("error: parsed stop command has been truncated! --> won't execute start command");
|
||||
exit(0); /* exit child */
|
||||
}
|
||||
}
|
||||
|
||||
/* all parsing ok --> execute the parsed (%IP% = source IP) command */
|
||||
exec_cmd(parsed_start_cmd, attempt->door->name);
|
||||
/* if stop_command is set, sleep for cmd_timeout and run it*/
|
||||
if(attempt->door->stop_command){
|
||||
sleep(attempt->door->cmd_timeout);
|
||||
if(attempt->srchost) {
|
||||
vprint("%s (%s): %s: command timeout\n", attempt->src, attempt->srchost, attempt->door->name);
|
||||
logprint("%s (%s): %s: command timeout", attempt->src, attempt->srchost, attempt->door->name);
|
||||
} else {
|
||||
vprint("%s: %s: command timeout\n", attempt->src, attempt->door->name);
|
||||
logprint("%s: %s: command timeout", attempt->src, attempt->door->name);
|
||||
}
|
||||
exec_cmd(parsed_stop_cmd, attempt->door->name);
|
||||
}
|
||||
|
||||
exit(0); /* exit child */
|
||||
}
|
||||
}
|
||||
/* change to next sequence if one time sequences are used.
|
||||
* Note that here the door will eventually be closed in
|
||||
* get_new_one_time_sequence() if no more sequences are left */
|
||||
if(attempt->door->one_time_sequences_fd) {
|
||||
disable_used_one_time_sequence(attempt->door);
|
||||
get_new_one_time_sequence(attempt->door);
|
||||
|
||||
/* update pcap filter */
|
||||
free(attempt->door->pcap_filter_exp);
|
||||
attempt->door->pcap_filter_exp = NULL;
|
||||
generate_pcap_filter();
|
||||
}
|
||||
}
|
||||
process_attempt(attempt);
|
||||
} else if(flagsmatch == 0) {
|
||||
/* TCP flags didn't match -- just ignore this packet, don't
|
||||
* invalidate the knock.
|
||||
@@ -1451,34 +1508,11 @@ void sniff(u_char* arg, const struct pcap_pkthdr* hdr, const u_char* packet)
|
||||
for(lp = doors; lp; lp = lp->next) {
|
||||
opendoor_t *door = (opendoor_t*)lp->data;
|
||||
/* if we're working with TCP, try to match the flags */
|
||||
if(ip->protocol == IPPROTO_TCP){
|
||||
if(door->flag_fin != DONT_CARE) {
|
||||
if(door->flag_fin == SET && tcp->fin != 1) {dprint("packet is not FIN, ignoring...\n");continue;}
|
||||
if(door->flag_fin == NOT_SET && tcp->fin == 1) {dprint("packet is not !FIN, ignoring...\n");continue;}
|
||||
}
|
||||
if(door->flag_syn != DONT_CARE) {
|
||||
if(door->flag_syn == SET && tcp->syn != 1) {dprint("packet is not SYN, ignoring...\n");continue;}
|
||||
if(door->flag_syn == NOT_SET && tcp->syn == 1) {dprint("packet is not !SYN, ignoring...\n");continue;}
|
||||
}
|
||||
if(door->flag_rst != DONT_CARE) {
|
||||
if(door->flag_rst == SET && tcp->rst != 1) {dprint("packet is not RST, ignoring...\n");continue;}
|
||||
if(door->flag_rst == NOT_SET && tcp->rst == 1) {dprint("packet is not !RST, ignoring...\n");continue;}
|
||||
}
|
||||
if(door->flag_psh != DONT_CARE) {
|
||||
if(door->flag_psh == SET && tcp->psh != 1) {dprint("packet is not PSH, ignoring...\n");continue;}
|
||||
if(door->flag_psh == NOT_SET && tcp->psh == 1) {dprint("packet is not !PSH, ignoring...\n");continue;}
|
||||
}
|
||||
if(door->flag_ack != DONT_CARE) {
|
||||
if(door->flag_ack == SET && tcp->ack != 1) {dprint("packet is not ACK, ignoring...\n");continue;}
|
||||
if(door->flag_ack == NOT_SET && tcp->ack == 1) {dprint("packet is not !ACK, ignoring...\n");continue;}
|
||||
}
|
||||
if(door->flag_urg != DONT_CARE) {
|
||||
if(door->flag_urg == SET && tcp->urg != 1) {dprint("packet is not URG, ignoring...\n");continue;}
|
||||
if(door->flag_urg == NOT_SET && tcp->urg == 1) {dprint("packet is not !URG, ignoring...\n");continue;}
|
||||
}
|
||||
if(!flags_match(door, ip, tcp)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(ip->protocol == door->protocol[0] && dport == door->sequence[0]) {
|
||||
if(ip->ip_p == door->protocol[0] && dport == door->sequence[0] &&
|
||||
!strcmp(dstIP, door->target ? door->target : myip)) {
|
||||
struct hostent *he;
|
||||
/* create a new entry */
|
||||
attempt = (knocker_t*)malloc(sizeof(knocker_t));
|
||||
@@ -1490,24 +1524,18 @@ void sniff(u_char* arg, const struct pcap_pkthdr* hdr, const u_char* packet)
|
||||
strcpy(attempt->src, srcIP);
|
||||
/* try a reverse lookup if enabled */
|
||||
if (o_lookup) {
|
||||
inaddr.s_addr = ip->saddr;
|
||||
inaddr.s_addr = ip->ip_src.s_addr;
|
||||
he = gethostbyaddr((void *)&inaddr, sizeof(inaddr), AF_INET);
|
||||
if(he) {
|
||||
attempt->srchost = strdup(he->h_name);
|
||||
}
|
||||
}
|
||||
|
||||
attempt->stage = 1;
|
||||
attempt->stage = 0;
|
||||
attempt->seq_start = pkt_secs;
|
||||
attempt->door = door;
|
||||
if(attempt->srchost) {
|
||||
vprint("%s (%s): %s: Stage 1\n", attempt->src, attempt->srchost, door->name);
|
||||
logprint("%s (%s): %s: Stage 1", attempt->src, attempt->srchost, door->name);
|
||||
} else {
|
||||
vprint("%s: %s: Stage 1\n", attempt->src, door->name);
|
||||
logprint("%s: %s: Stage 1", attempt->src, door->name);
|
||||
}
|
||||
attempts = list_add(attempts, attempt);
|
||||
process_attempt(attempt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user