*BSD News Article 96068


Return to BSD News archive

Newsgroups: comp.unix.bsd.freebsd.misc
Path: euryale.cc.adfa.oz.au!newshost.carno.net.au!harbinger.cc.monash.edu.au!news.rmit.EDU.AU!news.unimelb.edu.au!munnari.OZ.AU!news.ecn.uoknor.edu!feed1.news.erols.com!disgorge.news.demon.net!demon!dispatch.news.demon.net!demon!rill.news.pipex.net!pipex!oleane!in2p3.fr!univ-lyon1.fr!fdn.fr!r2d2.fdn.org!sphynx.fdn.fr!causse
From: causse@sphynx.fdn.fr (Philippe Causse)
Subject: Re: Accept()-ing a connection from a specific IP address...
X-Newsreader: TIN [version 1.2 PL2]
Organization: individual - paris - france
Message-ID: <EAnnEo.12E@sphynx.fdn.fr>
References: <864144757.18711@dejanews.com> <EAHuuM.129@sphynx.fdn.fr> <5lvqjg$7rq$1@goof.Germany.EU.net>
Date: Fri, 23 May 1997 22:20:47 GMT
Lines: 162
Xref: euryale.cc.adfa.oz.au comp.unix.bsd.freebsd.misc:41533

Bernard Steiner (knob@wizards.staff.Germany.EU.net) wrote:
: In article <EAHuuM.129@sphynx.fdn.fr>,
: 	causse@sphynx.fdn.fr (Philippe Causse) writes:
: > moballa@WESTECHMobile.com wrote:
: >: Is there any way to use the Accept() routine to only accept a connection
: >: from a specific IP address?  Currently my program accepts a connection
: >: from anyone issuing a connect() call to it.  I would like to specify that
: >: it should only accept a connection from a particular IP address.

: > Afetr you created your `listening' socket:
: > 	1) bind it to the interface you whish to accept calls from
: > 	(getnetent could help)

: That helps in cases where you wish to service requests only on a particular
: interface (or similar).
That's exactly what I meant...

: > 	2) When accept() returns, check the peer address and if
: > 	the address is not an "allowed one", you should immediately
: > 	close the returned socket.

: That does not help really, since AFAIK accept() does a three-way handshake and
: closing the connection immediately is quite different from not accepting it.

It may be more polite to accept, then write a short message like
500 - Service not available
and close nicely. Yes,it'll require a few more packets, but saying "goodbye"
never hurted anyone...

: What I would like to know is whether or not it is now possible to
: (a) use the rcvmsg() (or was that recvfrom() ?) calls for bound TCP sockets
: *and
According to the man page, it says recvfrom can be used on a socket, whether
it is connection-oriented or not. Although does not state that recvfrom
can be used on a passive socket!  The demo program attached illustrates
that you cannot guess the peer's address before accept() has been done
(for TCP stuff, of course).

: (b) somehow discard TCP SYNs from illegitimate addresses and optionally tell
: the other side we are refusing connections ?

Then you should probably setup a firwall ! AFAIK this is the only way to
reject connection attemps. (kinda fascit stuff IMHO).

: > Other option (simpler, faster): use the tcp_wrappers library !

: You mean reverse-engineer the thing ;-)
Not at all. Just making use of the tcpwrappers API in your program like
a few others did (ypserv for example). And if your server is started from
inetd, it's trivial to start put it under tcpwrapper's control... RTFM!

: Bernard

----[cut here]---

#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/time.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define SERVER_PORT 4321

/*
 * Method 1 : does not work.
 * Peek some data in the TCP queue to look for IP address...
 */
void filter_connect_1(int so)
{
  struct sockaddr_in peer_addr;
  int peer_addr_len = sizeof(peer_addr);
  int sts;
  char buf[1];

  bzero(&peer_addr, peer_addr_len);
  sts = recvfrom(so, buf, sizeof(buf), MSG_PEEK,
		 (struct sockaddr *)&peer_addr, &peer_addr_len);
  if(sts < 0) perror("recvfrom");
  printf("Rejecting incoming connect() from %s\n",
	 inet_ntoa(peer_addr.sin_addr));
  close( accept(so, NULL, 0));
}

/*
 * Method 2 : does work :-)
 * Check the result of accept.
 */
void filter_connect_2(int so)
{
  FILE * cli;
  int cli_sock;
  struct sockaddr_in peer_addr;
  int peer_addr_len = sizeof(peer_addr);

  bzero(&peer_addr, peer_addr_len);
  cli_sock = accept(so, (struct sockaddr *)&peer_addr, &peer_addr_len);
  if( cli_sock < 0) perror("accept");

  printf("Incoming connect() from %s\n", inet_ntoa(peer_addr.sin_addr));

  cli = fdopen(cli_sock, "w");
  fprintf(cli, "500 - Not authorized to connect\r\n");
  fflush(cli);
  fclose(cli);
  close(cli_sock);
}


int main()
{
  int sts;
  int so;			/*  server socket */
  struct sockaddr_in serv_addr;
  int serv_addr_len;
  fd_set readfds;
  int nfds;

  serv_addr.sin_port = htons(SERVER_PORT);
  serv_addr.sin_family = AF_INET;
  serv_addr.sin_addr.s_addr = INADDR_ANY;
  serv_addr.sin_len = sizeof(serv_addr); /* total length */
  bzero(&serv_addr.sin_zero, sizeof(serv_addr.sin_zero));
  serv_addr_len = sizeof(serv_addr);

  so = socket(AF_INET, SOCK_STREAM, PF_UNSPEC);
  assert(so >= 0);

  sts = bind(so, (struct sockaddr *)&serv_addr, serv_addr_len);
  assert( sts == 0);
  
  sts = listen(so, 5);
  assert(sts == 0);

  while(1)
    {
      puts("--> select()");
      nfds = so + 1;
      FD_ZERO(&readfds);
      FD_SET(so, &readfds);
      sts = select(nfds, &readfds, 0, 0, NULL);
      puts("<-- select()");

      /* filter_connect_1(so); */ /* doesn't work */
      filter_connect_2(so);	/* works */
    }

  close(so);
  return EXIT_FAILURE;
}
------[cut here, compile and telnet to port 4321]-----

-- 
-------------------------------------------------------------------
P. Causse			http://www.fdn.fr/~pcausse
4.4BSD/X11R6/Motif-2.0/C++	mailto:causse@sphynx.fdn.fr (UUCP)