--- a/docs/nc6.1.in +++ b/docs/nc6.1.in @@ -160,6 +160,10 @@ With this option set, netcat6 will use UDP as the transport protocol (TCP is the default). .TP 13 +.I \-U, --unix +With this option set, netcat6 will connect to a unix domain socket. +The listen mode has not been implemented yet. +.TP 13 .I \-v Enable verbose mode. This gives some basic information about what netcat6 is doing. Use it twice for extra verbosity. --- a/src/Makefile.am +++ b/src/Makefile.am @@ -6,6 +6,7 @@ network.h \ afindep.h \ bluez.h \ + unixsocket.h \ netsupport.h \ parser.h \ readwrite.h \ @@ -20,6 +21,7 @@ afindep.c \ netsupport.c \ parser.c \ + unixsocket.c \ readwrite.c \ io_stream.c \ connection.c --- a/src/connection.c +++ b/src/connection.c @@ -109,6 +109,9 @@ fatal_internal("unavailable bluez support required"); #endif break; + case PROTO_UNIX: + ainfo->ai_family = PF_UNIX; + break; default: fatal_internal("unknown socket domain"); } @@ -144,6 +147,10 @@ fatal_internal("unavailable bluez support required"); #endif break; + case UNIX_PROTOCOL: + ainfo->ai_protocol = 0; + ainfo->ai_socktype = SOCK_STREAM; + break; default: fatal_internal("unknown socket type"); } --- a/src/connection.h +++ b/src/connection.h 2008-10-25 14:17:09 +0000 @@ -31,12 +31,14 @@ PROTO_UNSPECIFIED, PROTO_IPv6, PROTO_IPv4, + PROTO_UNIX, PROTO_BLUEZ } sock_family_t; typedef enum sock_protocol { TCP_PROTOCOL, UDP_PROTOCOL, + UNIX_PROTOCOL, SCO_PROTOCOL, L2CAP_PROTOCOL } sock_protocol_t; --- a/src/network.c +++ b/src/network.c @@ -23,6 +23,7 @@ #include "network.h" #include "connection.h" #include "afindep.h" +#include "unixsocket.h" #ifdef ENABLE_BLUEZ #include "bluez.h" #endif/*ENABLE_BLUEZ*/ @@ -113,6 +114,11 @@ /* invoke the appropriate connector for the protocol family */ switch (ca_family(attrs)) { + case PROTO_UNIX: + fd = unixsocket_connect(&hints, + remote->address, + timeout, &socktype); + break; #ifdef ENABLE_BLUEZ case PROTO_BLUEZ: fd = bluez_connect(&hints, --- a/src/parser.c +++ b/src/parser.c @@ -109,7 +109,9 @@ {"bluetooth", no_argument, NULL, 'b'}, #define OPT_SCO 24 {"sco", no_argument, NULL, 0 }, -#define OPT_MAX 25 +#define OPT_UNIX_SOCKET 25 + {"unix", no_argument, NULL, 'U'}, +#define OPT_MAX 26 {0, 0, 0, 0} }; @@ -160,7 +162,7 @@ _verbosity_level = 0; /* option recognition loop */ - while ((c = getopt_long(argc, argv, "46be:hlnp:q:s:uvw:xX", + while ((c = getopt_long(argc, argv, "46be:hlnp:q:s:uUvw:xX", long_options, &option_index)) >= 0) { switch (c) { @@ -231,6 +233,9 @@ family = PROTO_IPv6; ca_set_flag(attrs, CA_STRICT_IPV6); break; + case 'U': + family = PROTO_UNIX; + break; case 'b': family = PROTO_BLUEZ; break; @@ -330,6 +335,9 @@ /* set default protocols */ if (protocol == PROTO_UNSPECIFIED) { switch (family) { + case PROTO_UNIX: + protocol = UNIX_PROTOCOL; + break; case PROTO_BLUEZ: protocol = L2CAP_PROTOCOL; break; @@ -344,6 +352,11 @@ fatal(_("cannot specify UDP protocol and bluetooth")); if (protocol == SCO_PROTOCOL && family != PROTO_BLUEZ) fatal(_("--sco requires --bluetooth (-b)")); + if (protocol == UNIX_PROTOCOL && family != PROTO_UNIX) + fatal(_("--unix does not need protocol specifications")); + + if (family == PROTO_UNIX && listen_mode) + fatal(_("--unix cannot --listen yet")); /* check compiled options */ #ifndef ENABLE_BLUEZ @@ -380,6 +393,10 @@ fatal_internal("unknown/unsupported bluetooth " "protocol %d", protocol); break; + case PROTO_UNIX: + if (protocol != UNIX_PROTOCOL) + fatal_internal("unknown/unsupported UNIX protocol %d", protocol); + break; default: fatal_internal("invalid protocol family %d", family); } @@ -425,18 +442,18 @@ fatal(_("cannot set both --recv-only and --send-only")); } - /* check ports have not been specified with --sco */ - if (protocol == SCO_PROTOCOL) { + /* check ports have not been specified with --sco and --unix */ + if (protocol == SCO_PROTOCOL || protocol == UNIX_PROTOCOL) { if (remote_address.service != NULL) - fatal(_("--sco does not support remote port")); + fatal(_("--sco and --unix do not support remote port")); if (local_address.service != NULL) - fatal(_("--sco does not support local port (-p)")); + fatal(_("--sco and --unix do not support local port (-p)")); } /* check mode specific option availability and interactions */ if (listen_mode == true) { /* check port has been specified (except with sco) */ - if (local_address.service == NULL && protocol != SCO_PROTOCOL) { + if (local_address.service == NULL && protocol != SCO_PROTOCOL && protocol != UNIX_PROTOCOL) { fatal(_("in listen mode you must specify a port " "with the -p switch")); } @@ -450,6 +467,7 @@ /* check port has been specified (except with sco) */ if (remote_address.address == NULL || (remote_address.service == NULL && + protocol != UNIX_PROTOCOL && protocol != SCO_PROTOCOL)) { fatal(_("you must specify the address/port couple " @@ -553,6 +571,8 @@ fprintf(fp, " -6 %s\n", _("Use only IPv6")); fprintf(fp, " -b, --bluetooth %s\n", _("Use Bluetooth (defaults to L2CAP protocol)")); + fprintf(fp, " -U, --unix %s\n", + _("Connect to unix domain sockets")); fprintf(fp, " --buffer-size=BYTES %s\n", _("Set buffer size")); fprintf(fp, " --continuous %s\n", _("Continuously accept connections\n" --- a/src/unixsocket.c +++ b/src/unixsocket.c @@ -0,0 +1,78 @@ +/* + * unixsocket.c - address family independant networking functions + */ +#include "system.h" +#include "unixsocket.h" +#include "misc.h" +#include "netsupport.h" +#include "parser.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +RCSID("@(#) $Id$"); + + +int unixsocket_connect(const struct addrinfo *hints, + const char *remote_address, + time_t timeout, int *rt_socktype) +{ + int err, fd = -1; + struct sockaddr_un sa; + const struct addrinfo *ptr = hints; + + /* make sure arguments are valid and preconditions are respected */ + assert(hints != NULL); + assert(remote_address != NULL && strlen(remote_address) > 0); + assert(sizeof(sa.sun_path) >= strlen(remote_address)); + + sa.sun_family = ptr->ai_family; + strncpy(sa.sun_path, remote_address, sizeof(sa.sun_path)); + + + /* create the socket */ + fd = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol); + if (fd < 0) { + warning("cannot create the socket: %s", strerror(errno)); + return -1; + } + + /* attempt the connection */ + err = connect_with_timeout(fd, (struct sockaddr *)&sa, sizeof(sa), timeout); + + if (err != 0) + { + /* check error code */ + if (verbose_mode()) { + /* use different error message for timeout */ + if (errno == ETIMEDOUT) { + /* connection timed out */ + warning(_("timeout while connecting to %s"), remote_address); + } + else { + /* connection failed */ + warning(_("cannot connect to %s: %s"), remote_address, strerror(errno)); + } + } + close(fd); + return -1; + } + + assert(ptr == NULL || fd >= 0); + + /* let the user know the connection has been established */ + if (verbose_mode()) warning(_("%s open"), remote_address); + + /* return the socktype */ + if (rt_socktype != NULL) *rt_socktype = ptr->ai_socktype; + + return fd; +} + --- a/src/unixsocket.h +++ b/src/unixsocket.h @@ -0,0 +1,12 @@ +#ifndef UNIXSOCKET_H +#define UNIXSOCKET_H + +#include +#include + +/* establish a connection and return a new fd and socktype */ +int unixsocket_connect(const struct addrinfo *hints, + const char *remote_address, + time_t timeout, int *socktype); + +#endif