Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,26 @@ sbin_PROGRAMS = knockd
dist_sbin_SCRIPTS = src/knock_helper_ipt.sh
man_MANS += doc/knockd.1
sysconf_DATA = knockd.conf
unit_file = knockd.service
unit_dir = /etc/systemd/system

install-data-hook: $(unit_files)
mkdir -p $(unit_dir)
cp $(unit_file) $(unit_dir)
endif

dist_doc_DATA = README.md TODO ChangeLog COPYING

knock_SOURCES = src/knock.c
knock_SOURCES = src/knock.c src/interface.h
if USE_GETIFADDRS
knock_SOURCES += src/interface_getifaddrs.c
else
knock_SOURCES += src/interface_ioctl.c
endif
knockd_SOURCES = src/knockd.c src/list.c src/list.h src/knock_helper_ipt.sh

%.1: %.1.in
sed -e "s/#VERSION#/$(VERSION)/" $< > $@

EXTRA_DIST = doc/knock.1 doc/knock.1.in doc/knockd.1 doc/knockd.1.in knockd.conf
EXTRA_DIST = doc/knock.1 doc/knock.1.in doc/knockd.1 doc/knockd.1.in knockd.conf knockd.service
CLEANFILES = $(man_MANS)
12 changes: 11 additions & 1 deletion configure.ac
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
AC_PREREQ(2.60)
AC_INIT([knock], [0.7.8], [https://github.com/jvinet/knock/issues])
AC_INIT([knock], [0.7.9], [https://github.com/jvinet/knock/issues])
AM_INIT_AUTOMAKE([dist-xz no-dist-gzip foreign subdir-objects])

AC_CONFIG_HEADER([config.h])
Expand All @@ -10,12 +10,22 @@ AC_USE_SYSTEM_EXTENSIONS
AC_ARG_ENABLE([knockd],
[AS_HELP_STRING([--disable-knockd], [Disable building knockd (requires libpcap) @<:@default=enabled@:>@])])

AC_ARG_ENABLE([getifaddrs],
[AS_HELP_STRING([--disable-getifaddrs], [Disable using getifaddrs from glib @<:@default=enabled@:>@])])

AS_IF([test "x$enable_knockd" != "xno"], [
AC_CHECK_LIB([pcap], [pcap_dispatch], ,
[AC_MSG_ERROR([you need the libpcap library to build knockd])])
])

AS_IF([test "x$enable_getifaddrs" != "xno"], [
AC_CHECK_FUNC([getifaddrs],
[AC_DEFINE([HAVE_GETIFADDRS],[],[Use getifaddrs function])],
[AC_MSG_ERROR([can not find getifaddrs function.])])
])

AM_CONDITIONAL([BUILD_KNOCKD], [test "x$enable_knockd" != "xno"])
AM_CONDITIONAL([USE_GETIFADDRS], [test "x$enable_getifaddrs" != "xno"])

AC_CONFIG_FILES([Makefile])

Expand Down
5 changes: 5 additions & 0 deletions doc/knock.1.in
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ where a router mistakes your stream of SYN packets as a port scan and blocks
them. If the packet rate is slowed with \-\-delay, then the router should let
the packets through.
.TP
.B "\-i <n>, \-\-interface <n>"
Use network interface <n> for knocks, like eth0. This option can be useful
when a system has more than one network interface with different gateways
(multihomed).
.TP
.B "\-v, \-\-verbose"
Output verbose status messages.
.TP
Expand Down
9 changes: 9 additions & 0 deletions knockd.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[Unit]
Description=Port-Knocking Daemon
After=network.target

[Service]
ExecStart=/usr/bin/knockd

[Install]
WantedBy=multi-user.target
7 changes: 7 additions & 0 deletions src/interface.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#include <netinet/in.h>
#include <stdbool.h>

#ifndef MY_INTERFACE
#define MY_INTERFACE
bool get_interface_addr4(const char *if_name,struct in_addr *if_addr);
#endif // MY_INTERFACE
34 changes: 34 additions & 0 deletions src/interface_getifaddrs.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#include <sys/types.h>
#include <ifaddrs.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdbool.h>
#include "interface.h"

bool get_interface_addr4(const char *if_name,struct in_addr *if_addr) {
struct ifaddrs *addrs=NULL,*tmp=NULL;
bool found=false;
getifaddrs(&addrs);
tmp=addrs;
while(tmp) {
if (tmp->ifa_addr && tmp->ifa_addr->sa_family == AF_INET) {
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wcast-align"
#endif
struct sockaddr_in *addr_in = (struct sockaddr_in *)tmp->ifa_addr;
#ifdef __clang__
#pragma clang diagnostic pop
#endif
if (strcmp(if_name,tmp->ifa_name) == 0 ) {
if_addr->s_addr = addr_in->sin_addr.s_addr;
found=true;
break;
}
}
tmp = tmp->ifa_next;
}
freeifaddrs(addrs);
return found;
}
41 changes: 41 additions & 0 deletions src/interface_ioctl.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#include "interface.h"
#include <errno.h>

bool get_interface_addr4(const char *if_name,struct in_addr *if_addr) {
struct ifreq ifr;
int s;

s = socket(AF_INET, SOCK_DGRAM, 0);
if(s < 0) {
printf("%s is %d\n",strerror(errno),s);
return(false);
}

memset(ifr.ifr_name, 0, sizeof(ifr.ifr_name));
strncpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name)-1);
printf("%s\n",ifr.ifr_name);
ifr.ifr_name[sizeof(ifr.ifr_name)-1] = '\0';
if(ioctl(s, SIOCGIFADDR, &ifr)==-1) {
close(s);
return(false);
}
close(s);
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wcast-align"
#endif
struct sockaddr_in *addr_in = (struct sockaddr_in *)&ifr.ifr_addr;
#ifdef __clang__
#pragma clang diagnostic pop
#endif
if_addr->s_addr = addr_in->sin_addr.s_addr;
return(true);
}
27 changes: 26 additions & 1 deletion src/knock.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include <resolv.h>
#include <getopt.h>
#include <fcntl.h>
#include "interface.h"

static char version[] = "0.7";

Expand All @@ -54,6 +55,8 @@ int main(int argc, char** argv)
int sd;
struct hostent* host;
struct sockaddr_in addr;
struct sockaddr_in bind_addr;
bool do_bind=false;
int opt, optidx = 1;
static struct option opts[] =
{
Expand All @@ -62,10 +65,11 @@ int main(int argc, char** argv)
{"delay", required_argument, 0, 'd'},
{"help", no_argument, 0, 'h'},
{"version", no_argument, 0, 'V'},
{"interface", required_argument, 0, 'i'},
{0, 0, 0, 0}
};

while((opt = getopt_long(argc, argv, "vud:hV", opts, &optidx))) {
while((opt = getopt_long(argc, argv, "vud:hVi:", opts, &optidx))) {
if(opt < 0) {
break;
}
Expand All @@ -74,6 +78,17 @@ int main(int argc, char** argv)
case 'v': o_verbose = 1; break;
case 'u': o_udp = 1; break;
case 'd': o_delay = (int)atoi(optarg); break;
case 'i':
memset(&bind_addr,0,sizeof(struct sockaddr_in));
if ( get_interface_addr4(optarg,&bind_addr.sin_addr) ) {
do_bind=true;
bind_addr.sin_family=AF_INET;
bind_addr.sin_port=0;
} else {
fprintf(stderr,"error: interface %s not found.\n",optarg);
exit(1);
}
break;
case 'V': ver();
case 'h': /* fallthrough */
default: usage();
Expand Down Expand Up @@ -126,10 +141,19 @@ int main(int argc, char** argv)
flags = fcntl(sd, F_GETFL, 0);
fcntl(sd, F_SETFL, flags | O_NONBLOCK);
}
if (do_bind) {
int tmp = bind(sd,(struct sockaddr *)&bind_addr,sizeof(bind_addr));
if (tmp !=0 ) {
fprintf(stderr,"error can not bind to specified interface.\n");
exit(1);
}
}
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = *((long*)host->h_addr_list[0]);
addr.sin_port = htons(port);
if (do_bind)
vprint("using %s:%u addr: ",inet_ntoa(bind_addr.sin_addr),bind_addr.sin_port);
if(o_udp || proto == PROTO_UDP) {
vprint("hitting udp %s:%u\n", inet_ntoa(addr.sin_addr), port);
sendto(sd, "", 1, 0, (struct sockaddr*)&addr, sizeof(addr));
Expand Down Expand Up @@ -160,6 +184,7 @@ void usage() {
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(" -i, --interface <n> use interface <name> for port hits\n");
printf(" -v, --verbose be verbose\n");
printf(" -V, --version display version\n");
printf(" -h, --help this help\n");
Expand Down