/force_bind.c (a5207a60db67a4c778de9ee0e238069c6c978978) (3807 bytes) (mode 100644) (type blob)

/*
 * Description: Force bind on a specified address
 * Author: Catalin(ux) M. BOIE
 * E-mail: catab at embedromix dot ro
 * Web: http://kernel.embedromix.ro/us/
 */

#define __USE_GNU
#define	_GNU_SOURCE
#define __USE_XOPEN2K
#define __USE_LARGEFILE64
#define __USE_FILE_OFFSET64

#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <syslog.h>
#include <dlfcn.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <dirent.h>
#include <asm/unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <arpa/inet.h>


static int		(*old_bind)(int sockfd, const struct sockaddr *addr, socklen_t addrlen) = NULL;
static int		(*old_setsockopt)(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
static int		(*old_socket)(int domain, int type, int protocol);
static char		*force_address = NULL;
static int		force_port = -1;
static char		set_tos = 0;
static unsigned char	tos;

/* Functions */

void init(void)
{
	static unsigned char inited = 0;
	char *x;

	if (inited == 1)
		return;

	inited = 1;

	x = getenv("FORCE_BIND_ADDRESS");
	if (x != NULL) {
		force_address = x;
		syslog(LOG_INFO, "force_bind: Force bind to address %s.\n",
			force_address);
	}

	x = getenv("FORCE_BIND_PORT");
	if (x != NULL) {
		force_port = strtol(x, NULL, 10);
		syslog(LOG_INFO, "force_bind: Force bind to port %d.\n",
			force_port);
	}

	/* tos */
	x = getenv("FORCE_NET_TOS");
	if (x != NULL) {
		set_tos = 1;
		tos = strtoul(x, NULL, 0);
		syslog(LOG_INFO, "force_bind: Force TOS to %hhu.\n",
			tos);
	}

	old_bind = dlsym(RTLD_NEXT, "bind");
	if (old_bind == NULL) {
		syslog(LOG_ERR, "force_bind: Cannot resolve 'bind'!\n");
		exit(1);
	}

	old_setsockopt = dlsym(RTLD_NEXT, "setsockopt");
	if (old_setsockopt == NULL) {
		syslog(LOG_ERR, "force_bind: Cannot resolve 'setsockopt'!\n");
		exit(1);
	}

	old_socket = dlsym(RTLD_NEXT, "socket");
	if (old_socket == NULL) {
		syslog(LOG_ERR, "force_bind: Cannot resolve 'socket'!\n");
		exit(1);
	}
}

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
{
	int err;
	struct sockaddr new;
	struct sockaddr_in *sa4;
	struct sockaddr_in6 *sa6;
	void *p = NULL;
	unsigned short *pport = NULL;

	init();

	if ((addr->sa_family != AF_INET) && (addr->sa_family != AF_INET6)) {
		syslog(LOG_INFO, "force_bind: unsupported family=%u!\n",
			addr->sa_family);
		return old_bind(sockfd, addr, addrlen);
	}

	memcpy(&new, addr, sizeof(struct sockaddr));

	switch (new.sa_family) {
		case AF_INET:
			sa4 = (struct sockaddr_in *) &new;
			p = &sa4->sin_addr;
			pport = &sa4->sin_port;
			break;

		case AF_INET6:
			sa6 = (struct sockaddr_in6 *) &new;
			p = &sa6->sin6_addr.s6_addr;
			pport = &sa6->sin6_port;
			break;
	}

	if (force_address != NULL) {
		err = inet_pton(new.sa_family, force_address, p);
		if (err != 1) {
			syslog(LOG_INFO, "force_bind: cannot convert [%s] (%d)!\n",
				force_address, err);
			return old_bind(sockfd, addr, addrlen);
		}
	}

	if (force_port != -1)
		*pport = htons(force_port);

	return old_bind(sockfd, &new, addrlen);
}

int setsockopt(int sockfd, int level, int optname, const void *optval,
	socklen_t optlen)
{
	init();

	switch (optname) {
		case IP_TOS:
			if (set_tos == 1) {
				syslog(LOG_INFO, "force_bind: changing TOS from %hhu to %hhu.\n",
					*(char *)optval, tos);
				optval = &tos;
			}
		break;
	}


	return old_setsockopt(sockfd, level, optname, optval, optlen);
}

/*
 * 'socket' is hijacked to be able to call setsockopt on it.
 */
int socket(int domain, int type, int protocol)
{
	int sock;

	init();

	sock = old_socket(domain, type, protocol);
	if (sock == -1)
		return -1;

	if (set_tos == 1)
		setsockopt(sock, IPPROTO_IP, IP_TOS, &tos, 1);

	return sock;
}



Mode Type Size Ref File
100644 blob 43 9108d94cb8e6f127c99b7099975be00532899907 .gitignore
100644 blob 30 d987fa5df957830331139935d517009e2911b0cf INSTALL
100644 blob 35147 94a9ed024d3859793618152ea559a168bbcbb5e2 LICENSE
100644 blob 541 b035b10712cea5a98c1d9e50887c363226307608 Makefile.in
100644 blob 855 70d1482667fbea25d33d3bbed803bb508cf0dd53 README
100644 blob 174 a0af61e812bd62970aa1e3dc33c883c756520f42 TODO
100755 blob 23 d33bb6c4ecdce1390ce1db3c79ea3b93e22ea755 configure
100755 blob 12723 62411b6de6bc9d88b550b7c96e140e8ce9015086 duilder
100644 blob 261 11bcae688fe61c68a0e1ac8e6694459208cbc2e3 duilder.conf
100644 blob 3807 a5207a60db67a4c778de9ee0e238069c6c978978 force_bind.c
100644 blob 804 b7ef7798c25d781fc2c7790aa80f8f431703e781 force_bind.spec.in
100755 blob 165 83d21d25e27dc624569788a2467ff66002d3b4a3 test1.sh
100644 blob 1135 ef564034e516db96e7e9346000e4a7917da3b82d test_bind.c
Hints:
Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://rocketgit.com/user/catalinux/force_bind

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@ssh.rocketgit.com/user/catalinux/force_bind

Clone this repository using git:
git clone git://git.rocketgit.com/user/catalinux/force_bind

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a merge request:
... clone the repository ...
... make some changes and some commits ...
git push origin main