Hi
I wrote a small patch to netcat to work with unix domain sockets to
enable me to communicate with an asterisk daemon through the
unix-domain socket /var/run/asterisk/asterisk.ctl .
Only then I noticed that reading the code is done very differently than
a typical network protocol: it expects every command in a separate read.
Basically I used the following filter to pipe commands from the standard
input to netcat:
while read line
do
echo -n "$line"
sleep 0.001
done
This reads one text line and prints it to the output after stripping the
linefeed in the end. Then it waits a bit (IIRC sleep is not an internal
bash command, and thus it actually takes some time to exec the process,
so the sleep is closer to 0.007 sec. on my system). This hints netcat to
send two lines in two seperate writes.
I am still left with one problem: there is no way for me to order the
termination of a connection. 'exit/quit' are implemented locally.
So basically I have to change the filter there to detect an exit:
while read line
do
case "$line" in exit*)break;; esac
echo -n "$line"
sleep 0.001
done
I wonder, though haven't really checked, what happens if I send some
randome data into this socket (specifically: some data that may have
some '\0' inside it).
I attach my patch to netcat, if anybody is interested. It applies to an
already patched Debian source. Alternatively, you can try the small
programs I posted here a while ago that just write to the socket.
--
Tzafrir Cohen | tzafrir@jbr.cohens.org.il | VIM is
http://tzafrir.org.il | | a Mutt's
tzafrir@cohens.org.il | | best
ICQ# 16849755 | | friend
-------------- next part --------------
#! /bin/sh /usr/share/dpatch/dpatch-run
## unix.dpatch by <tzafrir@>
##
## All lines beginning with `## DP:' are a description of the patch.
## DP: unix-domain sockets support for netcat. Try:
## DP:
## DP: nc -U /path/to/socket localhost 0
## DP:
## DP: listen mode (-l) should theoretically work, but is untested.
@DPATCH@
diff -urNad netcat-1.10/netcat.c /tmp/dpep.QmuQvQ/netcat-1.10/netcat.c
--- netcat-1.10/netcat.c 2006-01-04 22:11:40.000000000 +0200
+++ /tmp/dpep.QmuQvQ/netcat-1.10/netcat.c 2006-01-04 22:17:16.000000000 +0200
@@ -71,6 +71,7 @@
#include <sys/time.h> /* timeval, time_t */
#include <setjmp.h> /* jmp_buf et al */
#include <sys/socket.h> /* basics, SO_ and AF_ defs, sockaddr, ... */
+#include <sys/un.h> /* UNIX-domain sockets */
#include <netinet/in.h> /* sockaddr_in, htons, in_addr */
#include <netinet/in_systm.h> /* misc crud that netinet/ip.h references
*/
#include <netinet/ip.h> /* IPOPT_LSRR, header stuff */
@@ -87,6 +88,7 @@
/* handy stuff: */
#define SA struct sockaddr /* socket overgeneralization braindeath */
+#define SAU struct sockaddr_un /* */
#define SAI struct sockaddr_in /* ... whoever came up with this model */
#define IA struct in_addr /* ... should be taken out and shot, */
/* ... not that TLI is any better. sigh.. */
@@ -149,12 +151,16 @@
unsigned int wrote_net = 0; /* total net bytes */
static char wrote_txt[] = " sent %d, rcvd %d";
static char hexnibs[20] = "0123456789abcdef ";
+char * unixsock_name = NULL; /* the filename for the unix domain socket to
+ connect to or listen on, and also a flag
+ to tell when in unixsock mode */
/* will malloc up the following globals: */
struct timeval * timer1 = NULL;
struct timeval * timer2 = NULL;
SAI * lclend = NULL; /* sockaddr_in structs */
SAI * remend = NULL;
+SAU * unixsock = NULL;
HINF ** gates = NULL; /* LSRR hop hostpoop */
char * optbuf = NULL; /* LSRR or sockopts */
char * bigbuf_in; /* data buffers */
@@ -660,10 +666,17 @@
/* grab a socket; set opts */
newskt:
- if (o_udpmode)
- nnetfd = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
- else
- nnetfd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (unixsock_name) {
+ if (o_udpmode)
+ nnetfd = socket (AF_LOCAL, SOCK_DGRAM, 0);
+ else
+ nnetfd = socket (AF_LOCAL, SOCK_STREAM, 0);
+ } else {
+ if (o_udpmode)
+ nnetfd = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ else
+ nnetfd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ }
if (nnetfd < 0)
bail ("Can't get socket");
if (nnetfd == 0) /* if stdin was closed this might *be* 0, */
@@ -692,14 +705,20 @@
rr = setsockopt(nnetfd, SOL_SOCKET, SO_RCVBUF, &o_rcvbuf, sizeof
o_rcvbuf);
rr = setsockopt(nnetfd, SOL_SOCKET, SO_SNDBUF, &o_sndbuf, sizeof
o_sndbuf);
#endif
-
- /* fill in all the right sockaddr crud */
+
+ if (unixsock_name) {
+ unixsock->sun_family = AF_LOCAL;
+ strncpy(unixsock->sun_path, unixsock_name,
sizeof(unixsock->sun_path)-1);
+ //strncpy(unixsock->sun_path, unixsock_name, 108-1);
+ //unixsock->sun_path[sizeof(unixsock->sun_path)-1] = '\0';
+ } else {
+ /* fill in all the right sockaddr crud */
lclend->sin_family = AF_INET;
-/* fill in all the right sockaddr crud */
- lclend->sin_family = AF_INET;
- remend->sin_family = AF_INET;
-
+ /* fill in all the right sockaddr crud */
+ lclend->sin_family = AF_INET;
+ remend->sin_family = AF_INET;
+ }
/* if lad/lp, do appropriate binding */
if (lad)
memcpy (&lclend->sin_addr.s_addr, lad, sizeof (IA));
@@ -710,13 +729,21 @@
x = (int) lp;
/* try a few times for the local bind, a la ftp-data-port... */
for (y = 4; y > 0; y--) {
- rr = bind (nnetfd, (SA *)lclend, sizeof (SA));
+ if (unixsock_name) {
+ rr = bind (nnetfd, (SA *)unixsock, sizeof (SA));
+ } else {
+ rr = bind (nnetfd, (SA *)lclend, sizeof (SA));
+ }
if (rr == 0)
break;
if (errno != EADDRINUSE)
break;
else {
- holler ("retrying local %s:%d", inet_ntoa (lclend->sin_addr),
lp);
+ if (unixsock_name) {
+ holler ("retrying local socket %s", unixsock_name);
+ } else {
+ holler ("retrying local %s:%d", inet_ntoa (lclend->sin_addr),
lp);
+ }
sleep (2);
errno = 0; /* clear from sleep */
} /* if EADDRINUSE */
@@ -729,9 +756,10 @@
if (o_listen)
return (nnetfd); /* thanks, that's all for today */
- memcpy (&remend->sin_addr.s_addr, rad, sizeof (IA));
- remend->sin_port = htons (rp);
-
+ if (! unixsock_name) {
+ memcpy (&remend->sin_addr.s_addr, rad, sizeof (IA));
+ remend->sin_port = htons (rp);
+ }
/* rough format of LSRR option and explanation of weirdness.
Option comes after IP-hdr dest addr in packet, padded to *4, and ihl > 5.
IHL is multiples of 4, i.e. real len = ip_hl << 2.
@@ -805,14 +833,22 @@
arm_timer (1, o_wait);
#ifdef POSIX_SETJMP
if (sigsetjmp (jbuf,1) == 0) {
- rr = connect (nnetfd, (SA *)remend, sizeof (SA));
+ if (unixsock_name) {
+ rr = connect (nnetfd, (SA *)unixsock, sizeof (SAU));
+ } else {
+ rr = connect (nnetfd, (SA *)remend, sizeof (SA));
+ }
} else { /* setjmp: connect failed... */
rr = -1;
errno = ETIMEDOUT; /* fake it */
}
#else
if (setjmp (jbuf) == 0) {
- rr = connect (nnetfd, (SA *)remend, sizeof (SA));
+ if (unixsock_name) {
+ rr = connect (nnetfd, (SA *)unixsock, sizeof (SAU));
+ } else {
+ rr = connect (nnetfd, (SA *)remend, sizeof (SA));
+ }
} else { /* setjmp: connect failed... */
rr = -1;
errno = ETIMEDOUT; /* fake it */
@@ -1435,6 +1471,7 @@
/* round up the usual suspects, i.e. malloc up all the stuff we need */
lclend = (SAI *) Hmalloc (sizeof (SA));
remend = (SAI *) Hmalloc (sizeof (SA));
+ unixsock=(SAU *) Hmalloc (sizeof (SA));
bigbuf_in = Hmalloc (BIGSIZ);
bigbuf_net = Hmalloc (BIGSIZ);
ding1 = (fd_set *) Hmalloc (sizeof (fd_set));
@@ -1503,7 +1540,7 @@
/* If your shitbox doesn't have getopt, step into the nineties already. */
/* optarg, optind = next-argv-component [i.e. flag arg]; optopt = last-char */
- while ((x = getopt (argc, argv, "abc:e:g:G:hi:lno:p:q:rs:tuvw:z"))
!= EOF) {
+ while ((x = getopt (argc, argv,
"abc:e:g:G:hi:lno:p:q:rs:tuU:vw:z")) != EOF) {
/* Debug (("in go: x now %c, optarg %x optind %d", x, optarg,
optind)) */
switch (x) {
case 'a':
@@ -1579,6 +1616,8 @@
#endif /* TELNET */
case 'u': /* use UDP */
o_udpmode++; break;
+ case 'U': /* UNIX-domain socket */
+ unixsock_name = optarg;
case 'v': /* verbose */
o_verbose++; break;
case 'w': /* wait time */
@@ -1642,7 +1681,7 @@
curport = 0; /* rem port *can* be zero here... */
if (argv[optind]) { /* any rem-port-arg? */
curport = getportpoop (argv[optind], 0);
- if (curport == 0) /* if given, demand correctness */
+ if ((curport == 0) && (unixsock_name==NULL) )/* if given, demand
correctness */
bail ("invalid port %s", argv[optind]);
} /* if port-arg */
netfd = dolisten (themaddr, curport, ouraddr, o_lport);
@@ -1689,13 +1728,13 @@
*cp = '\0';
unescape(++cp); /* turn \-'s into -'s */
hiport = getportpoop (cp, 0);
- if (hiport == 0)
+ if ((hiport == 0) && (unixsock_name==NULL) )
bail ("invalid port %s", cp);
}
unescape(argv[optind]); /* turn \-'s into -'s */
} /* if found a dash */
loport = getportpoop (argv[optind], 0);
- if (loport == 0)
+ if ((loport == 0) && (unixsock_name==NULL) )
bail ("invalid port %s", argv[optind]);
if (hiport > loport) { /* was it genuinely a range? */
Single = 0; /* multi-mode, case B */