Wietse Venema via Postfix-users wrote in
 <4svjy117ywzj...@spike.porcupine.org>:
 ...
 |I expect that a SOCKS5 client would not use much code, compared to
 |the code that was needed with HaProxy.

Gaetan Bisson (former ArchLinux, a very smart math professor
Tahiti) has written a small LD_PRELOAD SOCKS5 wrapper.  It does
not proxy DNS queries due to its simplicistic design, however.
I used it in the past, before i implemented SOCKS5 for the MUA
i maintain, and before Thomas Dickey accepted a SOCKS5 patch for
the lynx browser.  (These can and do also proxy DNS.)

--steffen
|
|Der Kragenbaer,                The moon bear,
|der holt sich munter           he cheerfully and one by one
|einen nach dem anderen runter  wa.ks himself off
|(By Robert Gernhardt)
|
| Only in December: lightful Dubai COP28 Narendra Modi quote:
|  A small part of humanity has ruthlessly exploited nature.
|  But the entire humanity is bearing the cost of it,
|  especially the inhabitants of the Global South.
|  The selfishness of a few will lead the world into darkness,
|  not just for themselves but for the entire world.
|  [Christians might think of Revelation 11:18
|    The nations were angry, and your wrath has come[.]
|    [.]for destroying those who destroy the earth.
|   But i find the above more kind, and much friendlier]
/* This is https://fenua.org/gaetan/src/usocks-0.7.c */
/*
 * Copyright (C) 2013-2018, Gaetan Bisson <bis...@archlinux.org>.
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/*
 * USocks. Minimalistic SOCKS5 proxying library.
 *
 * USocks implements a connect() function over the system one in order to
 * forward connections through a prescribed SOCKS5 proxy; its design focuses
 * are code clarity and conciseness.
 *
 * Compile with:
 *
 *   cc -O2 -fPIC -ldl -shared -o usocks.so usocks.c
 *
 * Use by exporting:
 *
 *   USOCKS_PORT=7772
 *   USOCKS_ADDR=127.0.0.1
 *   LD_PRELOAD=`pwd`/usocks.so
 */


/* ****************************************************************************
 *
 * HEADERS
 *
 */


#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <dlfcn.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>


/* ****************************************************************************
 *
 * INITIALIZE PROXY DATA AND LOCATE SYSTEM FUNCTIONS
 *
 */


struct sockaddr_in us_proxy;

typedef int (*connect_t)(int, const struct sockaddr *, socklen_t);
connect_t sys_connect;

int us_init (void) {
	char *port = getenv("USOCKS_PORT");
	char *addr = getenv("USOCKS_ADDR");
	if (!port) return -1;
	if (!addr) return -1;

	memset(&us_proxy, 0, sizeof(us_proxy));
	us_proxy.sin_family = AF_INET;
	us_proxy.sin_port = htons(atoi(port));
	us_proxy.sin_addr.s_addr = inet_addr(addr);

	sys_connect = (connect_t)(intptr_t)dlsym(RTLD_NEXT, "connect");
	return 0;
}


/* ****************************************************************************
 *
 * LEAVE NO BYTES BEHIND
 *
 */


int us_sendall (int socket, const char *buffer, size_t length, int flags) {
	int r, off=0;
	while(off<length) {
		r = send(socket, buffer+off, length-off, flags);
		if (r<0) return -1;
		off += r;
	}
	return off;
}

int us_recvall (int socket, char *buffer, size_t length, int flags) {
	int r, off=0;
	while (off<length) {
		r = recv(socket, buffer+off, length-off, flags);
		if (r<0) return -1;
		off += r;
	}
	return off;
}


/* ****************************************************************************
 *
 * REDEFINE CONNECT()
 *
 */


const unsigned char l4[] = { 0x7f };                                            /* matches loopback IPv4 addresses    */
const unsigned char l6[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };  /* matches loopback IPv6 address      */
const unsigned char l64[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0x7f }; /* matches loopback IPv6to4 addresses */

int connect (int sock, const struct sockaddr *addr, socklen_t len) {
	int p, t, v, f=sizeof(t);
	char b[256];

	if (!sys_connect) if (us_init()) return -1;

	/* let unix domain sockets and loopback traffic through */
	switch (addr->sa_family) {
		case AF_UNIX:
			return sys_connect(sock,addr,len);
		case AF_INET6:
#if 0
			if (!memcmp(&(((struct sockaddr_in6 *)addr)->sin6_addr.s6_addr), l64, 13) ||
			    !memcmp(&(((struct sockaddr_in6 *)addr)->sin6_addr.s6_addr), l6, 16))
				return sys_connect(sock,addr,len);
#endif
			v=16;
			break;
		case AF_INET:
#if 0
			/*if (!memcmp(&(((struct sockaddr_in *)addr)->sin_addr.s_addr), l4, 1))
				return sys_connect(sock,addr,len);*/
#endif
			v=4;
			break;
		default:
			return -1;
	}

	/* let non-TCP through */
	getsockopt(sock, SOL_SOCKET, SO_TYPE, &t, (socklen_t *)&f);
	if (t!=SOCK_STREAM) return sys_connect(sock,addr,len);

	/* open blocking connection to proxy */
	f = fcntl(sock, F_GETFL);
	p = socket(AF_INET, SOCK_STREAM, 0);
	fcntl(p, F_SETFL, f & ~O_NONBLOCK);
	if (sys_connect(p,(struct sockaddr*)&us_proxy,sizeof(us_proxy))) return -1;

	/* protocol version and authentication method */
	memcpy(b, "\x05\x01\x00", 3);
	if (us_sendall(p,b,3,0)!=3) goto err;
	if (us_recvall(p,b,2,0)!=2) goto err;
	if (memcmp(b,"\x05\x00",2)) goto err;

	/* connection request */
	memcpy(b, "\x05\x01\x00", 3);
	if (v==4) {
		b[3] = '\x01';
		memcpy(b+4, &(((struct sockaddr_in *)addr)->sin_addr.s_addr), 4);
		memcpy(b+8, &(((struct sockaddr_in *)addr)->sin_port), 2);
	} else {
		b[3] = '\x04';
		memcpy(b+4, &(((struct sockaddr_in6 *)addr)->sin6_addr.s6_addr), 16);
		memcpy(b+20, &(((struct sockaddr_in6 *)addr)->sin6_port), 2);
	}
	if (us_sendall(p,b,v+6,0)!=v+6) goto err;
	if (us_recvall(p,b,4,0)!=4) goto err;
	if (memcmp(b,"\x05\x00\x00",3)) goto err;
	if (us_recvall(p,b,v+2,0)!=v+2) goto err;

	/* return proxy socket */
	close(sock);
	fcntl(p, F_SETFL, f);
	fcntl(p, F_DUPFD, sock);

	return 0;

err:
	close(p);
	return -1;
}
#!/bin/sh -
#@ usocks - detour network traffic through SOCKS5 proxy.
#@
#@ Synopsis: usocks PROXY-ADDRESS PROXY-PORT COMMAND [:ARGS:]
#
# Public Domain

ld_preload=/usr/lib/preloadable-usocks.so

if [ ${#} -lt 3 ]; then
        echo >&2 'Synopsis: usocks PROXY-ADDRESS PROXY-PORT COMMAND [:ARGS:]'
        exit 64 # EX_USAGE
fi

USOCKS_ADDR=${1} USOCKS_PORT=${2} cmd=${3}
shift 3

LD_PRELOAD="${ld_preload} ${LD_PRELOAD}"

export USOCKS_ADDR USOCKS_PORT LD_PRELOAD
exec "${cmd}" "${@}"
.\"@ usocks - detour network traffic through SOCKS5 proxy.
.\"
.\" Public Domain
.
.Dd September 17, 2020
.Dt USOCKS 1
.Os
.
.
.Sh NAME
.Nm usocks
.Nd detour network traffic through SOCKS5 proxy
.
.
.Sh SYNOPSIS
.Nm
.Ar proxy-address
.Ar proxy-port
.Ar command
.Op Pf : Ar argument Ns \&:
.
.
.Sh DESCRIPTION
.
.Nm
can be used to detour stream-based network traffic of
.Ar command
through the specified SOCKS5 proxy.
This is realized by preloading a shared library which overwrites the
.Xr connect 2
system call.
Because of this simple approach the SOCKS5 provided DNS (name) lookup
mechanism is not used.
.Ar proxy-address
must be an IPv4 internet address (like
.Ql 127.0.0.1 ) .
For example
.
.Bd -literal -offset indent
# Login as USER on HOST, create a local SOCKS proxy on port 10000
$ ssh -D 10000 USER@HOST

# Thereafter use usocks(1) to proxy any command over it
$ usocks 127.0.0.1 10000 irssi
.Ed
.
.\" s-ts-mode
_______________________________________________
Postfix-users mailing list -- postfix-users@postfix.org
To unsubscribe send an email to postfix-users-le...@postfix.org

Reply via email to