The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

Net::Ident - lookup the username on the remote end of a TCP/IP connection

SYNOPSIS

use Net::Ident;

$username = SOCKET->ident_lookup($timeout);
($username, $opsys, $error) = SOCKET->ident_lookup($timeout);

$obj = Net::Ident->initconnect(SOCKET, $timeout);
$fh = $obj->getfh;
$obj->query;
$status = $obj->ready;
$username = $obj->username;
($username, $opsys, $error) = $obj->username;

use Net::Ident 'lookup';

$username = lookup(SOCKET, $timeout);
($username, $opsys, $error) = lookup(SOCKET, $timeout);

OVERVIEW

Net::Ident is a module that looks up the username on the remote side of a TCP/IP connection through the ident (auth/tap) protocol described in RFC1413 (which supersedes RFC931). Note that this requires the remote site to run a daemon (often called identd) to provide the requested information, so it is not always available for all TCP/IP connections.

DESCRIPTION

You can either use the simple interface, which does one ident lookup at a time, or use the asynchronous interface to perform (possibly) many simultaneous lookups, or simply continue serving other things while the lookup is proceeding.

Simple Interface

The simple interface comes in two varieties. An object oriented method call of a FileHandle object, and as a simple subroutine call. Other than the calling method, these routines behave exactly the same.

ident_lookup SOCKET [$timeout]

The Net::Ident module extends the FileHandle module with one extra method call, ident_lookup. It assumes that the object (a FileHandle) it is operating on, is a connected TCP/IP socket, ie. something which is either connect()ed or accept()ed. This method takes one optional parameter: a timeout value in seconds. If you don't specify a timeout, or an undef timeout, there will be no timeout. It's that simple.

Net::Ident::lookup (SOCKET [, $timeout])

Net::Ident::lookup is an exportable function (through EXPORT_OK, so you'll have to explicitly ask for it if you want the function lookup to be callable from your program). You can pass the socket using either a string, which doesn't have to be qualified with a package name, or using the more modern FileHandle calling styles: as a glob or preferably a reference to a glob. As in the method call, the Socket has to be a connected TCP/IP socket, and the timeout is optional.

What these functions return depends on the context:

scalar context

In scalar context, these functions return the remote username on success, or undef on error. "Error" is rather broad, it might mean: some network error occurred, my arguments are invalid, the remote site is not responding (in time) or is not running an ident daemon, or the remote site ident daemon says there's no user connected with that particular connection.

array context

In array context, these functions return: ($username, $opsys, $error). The $username is the remote username, as returned in the scalar context, or undef on error.

The $opsys is the remote operating system as reported by the remote ident daemon, or undef on a network error, or "ERROR" when the remote ident daemon reported an error. This could also contain the character set of the returned username. See RFC1413.

The $error is the error message, either the error reported by the remote ident daemon (in which case $opsys is "ERROR"), or the internal message from the Net::Ident module, which includes the system errno $! whenever possible. A likely candidate is "Connection refused" when the remote site isn't running an ident daemon, or "Connection timed out" when the remote site isn't answering our connection request.

When $username has a value, $error is always undef, and vice versa.

EXAMPLE

The following code is a complete example, implementing a server that waits for a connection on a port, tells you who you are and what time it is, and closes the connection again. The majority of the code will look very familiar if you just read perlipc.

Excersize this server by telnetting to it, preferably from a machine that has a suitable ident daemon installed.

    #!/usr/bin/perl -w

    use Net::Ident;
    # uncomment the below line if you want lots of debugging info
    # $Net::Ident::DEBUG = 2;
    use Socket;
    use strict;
    
    sub logmsg { print "$0 $$: @_ at ", scalar localtime, "\n" }
    
    my $port = shift || 2345;
    my $proto = getprotobyname('tcp');
    socket(Server, PF_INET, SOCK_STREAM, $proto) or die "socket: $!";
    setsockopt(Server, SOL_SOCKET, SO_REUSEADDR, pack("l", 1)) or
      die "setsockopt: $!";
    bind(Server, sockaddr_in($port, INADDR_ANY)) or die "bind: $!";
    listen(Server,SOMAXCONN) or die "listen: $!";
    
    logmsg "server started on port $port";
    
    my $paddr;
    
    for ( ; $paddr = accept(Client,Server); close Client) {
	my($port,$iaddr) = sockaddr_in($paddr);
	my $name = gethostbyaddr($iaddr,AF_INET) || inet_ntoa($iaddr);
	logmsg "connection from $name [" . inet_ntoa($iaddr) .
	  "] at port $port";
       
	my $username = Client->ident_lookup(30) || "~unknown";
	logmsg "User at $name:$port is $username";
        
	print Client "Hello there, $username\@$name, it's now ",
	   scalar localtime, "\n";
    }

Asynchronous Interface

The asynchronous interface is meant for those who know the ins and outs of the select() call (the 4-argument version of select(), but I didn't need saying that, did I?). This interface is completely object oriented. The following methods are available:

initconnect Net::Ident SOCKET, $timeout

This class method initiates the connection to the remote ident daemon, and returns an object representing the connection. This is actually a constructor, but it isn't called "new" for a change. The parameters are the same as described above for the Net::Ident::lookup subroutine. This method returns immediately, the supplied $timeout is only stored in the object and used in future methods.

If you want to implement your own timeout, that's fine. Simply throw away the object when you don't want it anymore.

Returns undef on error, like when the SOCKET isn't a TCP/IP connected socket. Actually, in a list context, will return a list where the error message is the second element of the list.

The timeout is not implemented using alarm(). In fact you can use alarm() completely independant of this library, they do not interfere.

query $obj

This object method queries the remote rfc931 deamon, and blocks until the connection to the ident daemon is writable, if necessary (but you are supposed to make sure it is, of course). Returns true on success (or rather it returns the $obj itself), or undef on error.

ready $obj [$blocking]

This object method returns whether the data received from the remote daemon is complete (true or false). Returns undef on error. Reads any data from the connection. If $blocking is true, it blocks and waits until all data is received (it never returns false when blocking is true, only true or undef). If $blocking is not true, it doesn't block at all (unless... see below).

If you didn't call query $obj yet, this method calls it for you, which means it can block, regardless of the value of $blocking, depending on whether the connection to the ident is writable.

Obviously, you are supposed to call this routine whenever you see that the connection to the ident daemon is readable, and act appropriately when this returns true.

Note that once ready returns true, there are no longer checks on timeout (because the networking part of the lookup is over anyway). This means that even ready $obj can return true way after the timeout has expired, provided it returned true at least once before the timeout expired. This is to be construed as a feature.

username $obj

This object method parses the return from the remote ident daemon, and blocks until the query is complete, if necessary (it effectively calls ready $obj 1 for you if you didn't do it yourself). Returns the parsed username on success, or undef on error. In an array context, the return values are the same as described for the Net::Ident::lookup subroutine.

getfh $obj

This object method returns the internal FileHandle used for the connection to the remote ident daemon. Invaluable if you want it to dance in your select() ring.

geterror $obj

This object method returns the error message in case there was an error. undef when there was no error.

An asynchronous example implementing the above server in a multi-threaded way via select, is left as an excersize for the interested reader.

DISCLAIMER

I make NO WARRANTY or representation, either express or implied, with respect to this software, its quality, accuracy, merchantability, or fitness for a particular purpose. This software is provided "AS IS", and you, its user, assume the entire risk as to its quality and accuracy.

AUTHOR

Jan-Pieter Cornet, <johnpc@xs4all.nl>

COPYRIGHT

Copyright (c) 1995, 1997 Jan-Pieter Cornet. All rights reserved. You can distribute and use this program under the same terms as Perl itself.

REVISION HISTORY

V1.10

Jan 11th, 1997. Complete rewrite for perl5. Requires perl5.002 or up.

V1.02

Jan 20th, 1995. Quite a big bugfix: "connection refused" to the ident port would kill the perl process with a SIGPIPE if the connect didn't immediately signal it (ie. almost always on remote machines). Also recognises the perl5 package separator :: now on fully qualified descriptors. This is still perl4-compatible, a perl5- only version would require a rewrite to make it neater. Fixed the constants normally found in .ph files (but you shouldn't use those anyway).

[this release wasn't called Net::Ident, of course, it was called rfc931.pl]

V1.01

Around November 1994. Removed a spurious perl5 -w complaint. First public release. Has been tested against perl 5.000 and perl 4.036.

V1.00

Dunno, somewhere 1994. First neat collection of dusty routines put in a package.

SEE ALSO

Socket RFC1413, RFC931