Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 29 Aug 2000 10:48:00 -0600 (MDT)
From:      "Aaron Gifford" <agifford@infowest.com>
To:        <questions@freebsd.org>, <freebsd-net@freebsd.org>
Subject:   Bug in jail with UDP???
Message-ID:  <20000829164800.D4D4A20F08@ns1.infowest.com>

next in thread | raw e-mail | index | archive | help
/*

(The body of this email message is a C program that demonstrates
the bug in the FreeBSD jail system when using UDP.  Please save
the body of this message with a file name like udpjailtest.c or
some other appropriate name if you wish to test this demo.)


Hello,

While setting up a FreeBSD 4.1-STABLE (as of 15 Aug 2000) jail
for running the Jabber instant messaging system inside, including
an ICQ transport/gateway, I discovered the following unusual
or at least unexpected (by me) behavior of FreeBSD's jail:

A UDP datagram socket that uses connect() without first using
bind() will end up using the primary interface IP address
for the connection instead of the expected jail IP address
(which in this case was an alias IP address on that same
interface).  I wrote this little C program (this message IS
the C test program) to demonstrate this.

Compile this program, then create an alias IP address, then
run this program within a jail using that alias IP address;

  Assuming a jail environment in /path/to/jail/env and
  assuming an etheret interface of fxp0 and a primary IP
  address on that interface of 10.50.23.200/255.255.255.0:

  cc -o /path/to/jail/env/udpjailtest udpjailtest.c
  ifconfig fxp0 inet 10.50.23.233 netmask 255.255.255.255 alias
  jail /path/to/jail/env jail.host.name 10.50.23.233 udpjailtest

Then you would see something like:

  The following socket (asock) has NOT been bound to a local address using
  bind() and so if in a jail this socket will probably show the host's main
  IP address instead of the jail IP address:
  Socket name is IP address 10.50.23.200 port 50189

  The following socket (bsock) HAS been bound to a local address (INADDR_ANY)
  using bind() and so inside of a jail, this should show the proper jail IP
  address as expected:
  Socket name is IP address 10.50.23.233 port 49933

Why is this so?  Of course I would expect any program worth its salt
to bind() the datagram socket before connect()ing to a remote address,
but there are cases where programs do not bother with that step.
The case in point being the icqtransport program for the Jabber IM
system.

Can anyone enlighten me as to whether this is a bug in the jail() system,
or a feature?

Thanks!

Aaron out.

*/

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>

/* I use a.root-servers.net, but any remote IP will do */
#define REMOTE_NAMESERVER_IP "198.41.0.4"

void showsockname(int sock) {
	socklen_t		len = sizeof(struct sockaddr_in);
	struct sockaddr_in	addr;

	if (getsockname(sock, (struct sockaddr *)&addr, &len) != 0) {
		printf("getsockname(): %d %s\n", errno, strerror(errno));
		return;
	}
	printf("Socket name is IP address %s port %d\n", inet_ntoa(addr.sin_addr), addr.sin_port);
}

main() {
	struct sockaddr_in	local;
	struct sockaddr_in	remote;
	int			asock, bsock;
	unsigned long		ip;


	if ((asock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
		printf("socket(): %d %s\n", errno, strerror(errno));
		return;
	}
	if ((bsock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
		printf("socket(): %d %s\n", errno, strerror(errno));
		return;
	}

	bzero(&local, sizeof(struct sockaddr_in));
	bzero(&remote, sizeof(struct sockaddr_in));
	local.sin_family = remote.sin_family = AF_INET;
	local.sin_addr.s_addr = INADDR_ANY;
	remote.sin_addr.s_addr = inet_addr(REMOTE_NAMESERVER_IP);
	local.sin_port = htons(0);
	remote.sin_port = htons(53);

	/* Only bsock gets boundto INADDR_ANY */
	if (bind(bsock,(struct sockaddr *)&local, sizeof(struct sockaddr_in)) != 0) {
		printf("bind(): %d %s\n", errno, strerror(errno));
		return;
	}

	if (connect(asock, (struct sockaddr *)(&remote), sizeof(struct sockaddr_in)) != 0) {
		printf("connect(): %d %s\n", errno, strerror(errno));
		return;
	}
	if (connect(bsock, (struct sockaddr *)(&remote), sizeof(struct sockaddr_in)) != 0) {
		printf("connect(): %d %s\n", errno, strerror(errno));
		return;
	}

	printf("The following socket (asock) has NOT been bound to a local address using\n");
	printf("bind() and so if in a jail this socket will probably show the host's main\n");
	printf("IP address instead of the jail IP address:\n");
	showsockname(asock);
	printf("\nThe following socket (bsock) HAS been bound to a local address (INADDR_ANY)\n");
	printf("using bind() and so inside of a jail, this should show the proper jail IP\n");
	printf("address as expected:\n");
	showsockname(bsock);
}


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-questions" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20000829164800.D4D4A20F08>