about summary refs log tree commit diff
path: root/Src/Modules
diff options
context:
space:
mode:
Diffstat (limited to 'Src/Modules')
-rw-r--r--Src/Modules/tcp.c159
-rw-r--r--Src/Modules/tcp.h1
2 files changed, 120 insertions, 40 deletions
diff --git a/Src/Modules/tcp.c b/Src/Modules/tcp.c
index ab87a98c0..8ff481b09 100644
--- a/Src/Modules/tcp.c
+++ b/Src/Modules/tcp.c
@@ -89,11 +89,11 @@ int h_errno;
 mod_export char const *
 zsh_inet_ntop(int af, void const *cp, char *buf, size_t len)
 {       
-    if(af != AF_INET) {
+    if (af != AF_INET) {
 	errno = EAFNOSUPPORT;
 	return NULL;
     } 
-    if(len < INET_ADDRSTRLEN) {
+    if (len < INET_ADDRSTRLEN) {
 	errno = ENOSPC;
 	return NULL;
     }
@@ -111,14 +111,11 @@ zsh_inet_ntop(int af, void const *cp, char *buf, size_t len)
 #endif /* !HAVE_INET_NTOP */
 
 /**/
-#ifndef HAVE_INET_PTON
-
-/**/
-# ifndef HAVE_INET_ATON
+#ifndef HAVE_INET_ATON
 
-#  ifndef INADDR_NONE
-#   define INADDR_NONE 0xffffffffUL
-#  endif
+# ifndef INADDR_NONE
+#  define INADDR_NONE 0xffffffffUL
+# endif
 
 /**/
 mod_export int zsh_inet_aton(char const *src, struct in_addr *dst)
@@ -133,13 +130,16 @@ mod_export int zsh_inet_aton(char const *src, struct in_addr *dst)
 # define zsh_inet_aton inet_aton
 
 /**/
-# endif /* !HAVE_INET_ATON */
+#endif /* !HAVE_INET_ATON */
+
+/**/
+#ifndef HAVE_INET_PTON
 
 /**/
 mod_export int
 zsh_inet_pton(int af, char const *src, void *dst)
 {
-    if(af != AF_INET) {
+    if (af != AF_INET) {
 	errno = EAFNOSUPPORT;
 	return -1;
     }
@@ -163,7 +163,7 @@ zsh_inet_pton(int af, char const *src, void *dst)
 mod_export struct hostent *
 zsh_gethostbyname2(char const *name, int af)
 {
-    if(af != AF_INET) {
+    if (af != AF_INET) {
 	h_errno = NO_RECOVERY;
 	return NULL;
     }
@@ -196,7 +196,7 @@ zsh_getipnodebyname(char const *name, int af, int flags, int *errorp)
     static char pbuf[INET_ADDRSTRLEN];
 # endif
     struct hostent *he;
-    if(zsh_inet_pton(af, name, nbuf) == 1) {
+    if (zsh_inet_pton(af, name, nbuf) == 1) {
 	zsh_inet_ntop(af, nbuf, pbuf, sizeof(pbuf));
 	ahe.h_name = pbuf;
 	ahe.h_aliases = addrlist+1;
@@ -206,7 +206,7 @@ zsh_getipnodebyname(char const *name, int af, int flags, int *errorp)
 	return &ahe;
     }
     he = zsh_gethostbyname2(name, af);
-    if(!he)
+    if (!he)
 	*errorp = h_errno;
     return he;
 }
@@ -247,12 +247,12 @@ zts_alloc(int ztflags)
     Tcp_session sess;
 
     sess = (Tcp_session)zcalloc(sizeof(struct tcp_session));
-    if(!sess) return NULL;
+    if (!sess) return NULL;
     sess->fd=-1;
     sess->next=NULL;
     sess->flags=ztflags;
 
-    if(!zts_head()) {
+    if (!zts_head()) {
 	ztcp_head = ztcp_tail = sess;
     }
     else {
@@ -268,7 +268,7 @@ tcp_socket(int domain, int type, int protocol, int ztflags)
     Tcp_session sess;
 
     sess = zts_alloc(ztflags);
-    if(!sess) return NULL;
+    if (!sess) return NULL;
 
     sess->fd = socket(domain, type, protocol);
     return sess;
@@ -281,7 +281,7 @@ zts_delete(Tcp_session sess)
 
     tsess = zts_head();
 
-    if(tsess == sess)
+    if (tsess == sess)
     {
 	ztcp_head = sess->next;
 	free(sess);
@@ -293,7 +293,7 @@ zts_delete(Tcp_session sess)
 	tsess = zts_next(tsess);
     }
 
-    if(!tsess->next) return 1;
+    if (!tsess->next) return 1;
 
     tsess->next = tsess->next->next;
     free(tsess->next);
@@ -309,7 +309,7 @@ zts_byfd(int fd)
     tsess = zts_head();
 
     do {
-	if(tsess->fd == fd)
+	if (tsess->fd == fd)
 	    return tsess;
 
 	tsess = zts_next(tsess);
@@ -338,10 +338,10 @@ tcp_close(Tcp_session sess)
 {
     int err;
     
-    if(sess->fd != -1)
+    if (sess->fd != -1)
     {  
 	err = close(sess->fd);
-	if(err)
+	if (err)
 	{
 	    zwarn("connection close failed: %e", NULL, errno);
 	    return -1;
@@ -358,7 +358,7 @@ tcp_connect(Tcp_session sess, char *addrp, struct hostent *zhost, int d_port)
 {
     int salen;
 #ifdef SUPPORT_IPV6
-    if(zhost->h_addrtype==AF_INET6) {
+    if (zhost->h_addrtype==AF_INET6) {
 	memcpy(&(sess->peer.in6.sin6_addr), addrp, zhost->h_length);
 	sess->peer.in6.sin6_port = d_port;
 	sess->peer.in6.sin6_flowinfo = 0;
@@ -381,9 +381,9 @@ tcp_connect(Tcp_session sess, char *addrp, struct hostent *zhost, int d_port)
 static int
 bin_ztcp(char *nam, char **args, char *ops, int func)
 {
-    int herrno, err=1, destport, force=0, verbose=0, len;
-    char **addrp, *desthost;
-    struct hostent *zthost = NULL;
+    int herrno, err=1, destport, force=0, verbose=0, len, rfd;
+    char **addrp, *desthost, *localname, *remotename;
+    struct hostent *zthost = NULL, *ztpeer = NULL;
     Tcp_session sess;
 
     if (ops['f'])
@@ -400,9 +400,9 @@ bin_ztcp(char *nam, char **args, char *ops, int func)
 	    int targetfd = atoi(args[0]);
 	    sess = zts_byfd(targetfd);
 
-	    if(sess)
+	    if (sess)
 	    {
-		if((sess->flags & ZTCP_ZFTP) && !force)
+		if ((sess->flags & ZTCP_ZFTP) && !force)
 		{
 		    zwarnnam(nam, "use -f to force closure of a zftp control connection", NULL, 0);
 		    return 1;
@@ -418,16 +418,93 @@ bin_ztcp(char *nam, char **args, char *ops, int func)
 	    }
 	}
     }
+    else if (ops['l']) {
+	int lport;
+
+	if (!args[0]) {
+	    zwarnnam(nam, "-l requires an argument", NULL, 0);
+	    return 1;
+	}
+	lport = atoi(args[0]);
+	if (!lport) {
+	    zwarnnam(nam, "bad port number", NULL, 0);
+	    return 1;
+	}
+	sess = tcp_socket(PF_INET, SOCK_STREAM, 0, 0);
+
+	if (!sess) {
+	    zwarnnam(nam, "unable to allocate a TCP session slot", NULL, 0);
+	    return 1;
+	}
+#ifdef SO_OOBINLINE
+	len = 1;
+	setsockopt(sess->fd, SOL_SOCKET, SO_OOBINLINE, (char *)&len, sizeof(len));
+#endif
+	if (!zsh_inet_aton("0.0.0.0", &(sess->sock.in.sin_addr)))
+	{
+	    zwarnnam(nam, "bad address: %s", "0.0.0.0", 0);
+	    return 1;
+	}
+
+	sess->sock.in.sin_family = AF_INET;
+	sess->sock.in.sin_port = htons(lport);
+
+
+	if (bind(sess->fd, (struct sockaddr *)&sess->sock.in, sizeof(struct sockaddr_in)))
+	{
+	    zwarnnam(nam, "could not bind to %s: %e", "0.0.0.0", errno);
+	    tcp_close(sess);
+	    return 1;
+	}
+
+	if (listen(sess->fd, 1))
+	{
+	    zwarnnam(nam, "could not listen on socket: %e", NULL, errno);
+	    tcp_close(sess);
+	    return 1;
+	}
+
+	if ((rfd = accept(sess->fd, (struct sockaddr *)&sess->peer.in, &len)) == -1)
+	{
+	    zwarnnam(nam, "could not accept connection: %e", NULL, errno);
+	    tcp_close(sess);
+	    return 1;
+	}
+
+	/* move the fd since it doesn't seem to be closing well */
+	sess->fd = movefd(sess->fd);
+
+	err = close(sess->fd);
+	if (err)
+	{
+	    zwarn("listener close failed: %e", NULL, errno);
+	    return -1;
+	}
+	sess->fd = rfd;
+
+	fprintf(shout, "%d is on fd %d\n", ntohs(sess->peer.in.sin_port), sess->fd);
+
+	return 0;
+
+    }
     else {
 	
 	if (!args[0]) {
 	    for(sess = zts_head(); sess != NULL; sess = zts_next(sess))
 	    {
-		if(sess->fd != -1)
+		if (sess->fd != -1)
 		{
-		    zthost = gethostbyaddr(&(sess->peer.in.sin_addr), sizeof(struct sockaddr_in), AF_INET);
-		    if(zthost) fprintf(shout, "%s:%d is on fd %d%s\n", zthost->h_name, ntohs(sess->peer.in.sin_port), sess->fd, (sess->flags & ZTCP_ZFTP) ? " ZFTP" : "");
-		    else fprintf(shout, "%s:%d is on fd %d%s\n", "UNKNOWN", sess->peer.in.sin_port, sess->fd, (sess->flags & ZTCP_ZFTP) ? " ZFTP" : "");
+		    zthost = gethostbyaddr(&(sess->sock.in.sin_addr), sizeof(struct sockaddr_in), AF_INET);
+		    if (zthost)
+			localname = zthost->h_name;
+		    else
+			localname = ztrdup(inet_ntoa(sess->sock.in.sin_addr));
+		    ztpeer = gethostbyaddr(&(sess->peer.in.sin_addr), sizeof(struct sockaddr_in), AF_INET);
+		    if (ztpeer)
+			remotename = ztpeer->h_name;
+		    else
+			remotename = ztrdup(inet_ntoa(sess->sock.in.sin_addr));
+		    fprintf(shout, "%s:%d -> %s:%d is on fd %d%s%s\n", localname, ntohs(sess->sock.in.sin_port), remotename, ntohs(sess->peer.in.sin_port), sess->fd, (sess->flags & ZTCP_ZFTP) ? " ZFTP" : "", (sess->flags & ZTCP_INBOUND) ? "INBOUND" : "");
 		}
 	    }
 	    return 0;
@@ -448,15 +525,17 @@ bin_ztcp(char *nam, char **args, char *ops, int func)
 	}
 	
 	sess = tcp_socket(PF_INET, SOCK_STREAM, 0, 0);
+
+	if (!sess) {
+	    zwarnnam(nam, "unable to allocate a TCP session slot", NULL, 0);
+	    return 1;
+	}
+
 #ifdef SO_OOBINLINE
 	len = 1;
 	setsockopt(sess->fd, SOL_SOCKET, SO_OOBINLINE, (char *)&len, sizeof(len));
 #endif
 
-	if(!sess) {
-	    zwarnnam(nam, "unable to allocate a TCP session slot", NULL, 0);
-	    return 1;
-	}
 	if (sess->fd < 0) {
 	    zwarnnam(nam, "socket creation failed: %e", NULL, errno);
 	    zsfree(desthost);
@@ -465,18 +544,18 @@ bin_ztcp(char *nam, char **args, char *ops, int func)
 	}
 	
 	for (addrp = zthost->h_addr_list; err && *addrp; addrp++) {
-	    if(zthost->h_length != 4)
+	    if (zthost->h_length != 4)
 		zwarnnam(nam, "address length mismatch", NULL, 0);
 	    do {
 		err = tcp_connect(sess, *addrp, zthost, htons(destport));
 	    } while (err && errno == EINTR && !errflag);
 	}
 	
-	if(err)
+	if (err)
 	    zwarnnam(nam, "connection failed: %e", NULL, errno);
 	else
 	{
-	    if(verbose)
+	    if (verbose)
 		fprintf(shout, "%s:%d is now on fd %d\n", desthost, destport, sess->fd);
 	    else
 		fprintf(shout, "%d\n", sess->fd);
@@ -490,7 +569,7 @@ bin_ztcp(char *nam, char **args, char *ops, int func)
 }
 
 static struct builtin bintab[] = {
-    BUILTIN("ztcp", 0, bin_ztcp, 0, 2, 0, "c", NULL),
+    BUILTIN("ztcp", 0, bin_ztcp, 0, 2, 0, "cflv", NULL),
 };
 
 /* The load/unload routines required by the zsh library interface */
diff --git a/Src/Modules/tcp.h b/Src/Modules/tcp.h
index 94efb255a..9b674dd76 100644
--- a/Src/Modules/tcp.h
+++ b/Src/Modules/tcp.h
@@ -72,6 +72,7 @@ union tcp_sockaddr {
 
 typedef struct tcp_session *Tcp_session;
 
+#define ZTCP_INBOUND 1
 #define ZTCP_ZFTP 16
 
 struct tcp_session {