Skip to content

Instantly share code, notes, and snippets.

@atr000
Created December 18, 2010 05:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save atr000/746179 to your computer and use it in GitHub Desktop.
Save atr000/746179 to your computer and use it in GitHub Desktop.
nice util to aid shell/home scripts on finding the remote ip over a ssh connection
/*
* $Id: //websites/unixwiz/unixwiz.net/webroot/tools/whoamip.c#1 $
*
* written by : Stephen J. Friedl
* Software Consultant
* Tustin, California USA
* http://www.unixwiz.net/tools/
*
* ***********************************************************
* ** **
* ** This program is in the public domain, and can be used **
* ** by anybody, for any purpose. Have fun. **
* ** **
* ***********************************************************
*
* This program is used to make the best guess at a user's remote
* IP address. We do not have a good mechanism to obtain it directly,
* but given the user's tty (usually a pts), we can look in the
* utmpx file where it's recorded.
*
* The "who" program reads from /var/adm/utmpx, but sadly does not
* seem to have a way to report the hostname, so we have written
* this program to do so.
*
* Playing on the "whoami" program, we've named it "whoamip".
*
* WHAT'S THE HOSTNAME?
* --------------------
*
* We're not able to directly discover the IP address of the other
* end of this connection, because our program doesn't have any
* access to the direct socket in order to run getpeername(). An
* intermediate pseudo-tty isolates us from the socket, so we have
* no trivial way to learn this straightway.
*
* Some operating systems probably provide some kernel-based mechanism
* for digging into the network stack, but this is troublesome and
* highly non-portable. It's probably nearly unsolvable on many
* platforms.
*
* Instead, we'll get the information indirectly: the init and/or login
* program typically maintains this in the utmpx file (in /etc/ or
* /var/adm), associating the remote host with the current logged-in
* pseudo-tty.
*
* We locate the current tty and use that as a key to utmpx: this
* brings a record with the username and hostname: this is what's
* reported to the user.
*
* We're at the mercy of the login program to fill in the ut_host
* field: sometimes it contains the IP address (as a string), and
* other times it's a hostname (perhaps truncated). We have no
* control over this process and simply take what we're given.
*
* SSH SHORCUTS
* ------------
*
* As a short-circuit for users who come in via Secure Shell, we
* take a quick check for the $SSH_CLIENT environment variable,
* which would contain the IP address. If this is found, we return
* it directly without doing any I/O or mucking around with the TTY.
*
* Use the -S cmdline parameter to disable the $SSH_CLIENT check,
* and in any case we do not use the value unless there is a space
* after the remote IP address.
*
* BUILDING + RUNNING
* ------------------
*
* This requires just a C compiler:
*
* $ cc whoamip.c -o whoamip
*
* It should compile without errors or warnings.
*
* Running the program produces the hostname on the standard
* output, which can be captured in the shell (often in /etc/profile).
*
* $ host=`whoamip`
*
* We exit with zero (success) if we believe we've located the hostname,
* and nonzero (failure) if we can't for whatever reason.
*
* COMMAND LINE
* ------------
*
* -V
* Show the program's version information, then exit with success
*
* -S
* Disable the $SSH_CLIENT check.
*
* VERSION HISTORY
* ---------------
*
* 1.0.1 - 2006-07-31
* Initial release
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <utmpx.h>
#include <unistd.h>
#ifndef TRUE
# define TRUE 1
# define FALSE 0
#endif
static const char Version[] =
"whoamip 1.0.1 - 2006-07-31 - http://www.unixwiz.net/tools/";
static int no_ssh_client = FALSE;
int main(int argc, char **argv)
{
int c;
char *tty, *p, *env;
struct utmpx protox, *utp;
/*---------------------------------------------------------------
* COMMAND-LINE
*/
while ( (c = getopt(argc, argv, "VS")) != EOF )
{
switch (c)
{
case 'V':
puts(Version);
exit(EXIT_SUCCESS);
case 'S':
no_ssh_client = TRUE;
break;
default:
exit(EXIT_FAILURE);
}
}
/*---------------------------------------------------------------
* SHORTCUT: SSH variable?
*
* Most users don't use SSH, but for those that do, the $SSH_CLIENT
* reports the remote connection:
*
* SSH_CLIENT="64.170.162.98 51851 22"
*
* We only care about the IP address and not the ports involved,
* but this is a pretty reliable mechanism.
*/
if ( ! no_ssh_client
&& (env = getenv("SSH_CLIENT")) != 0
&& (p = strchr(env, ' ')) != 0 )
{
*p = '\0';
*p = '\0';
puts(env);
exit(EXIT_SUCCESS);
}
/*---------------------------------------------------------------
* FIND TTY NAME
*
* The utmp/wtmp files ONLY work when indexed by tty name, so we
* have to find the current tty. For network connections, this is
* virtually always /dev/ptsX (a pseudo-tty), and we remove the
* leading /dev/ part.
*
* Some systems work with /dev/pts123, while others use /dev/pts/123.
* We remove /dev/ in either case.
*
* NOTE: a tty is associated with a *file descriptor*, not a
* program, so we have to pick one. We use the standard input,
* because the standard output & error may well be attached to
* either an output file or a pipe:
*
* host=`whoamip`
*
* If we cannot find the tty name, we're done - sorry.
*
* Otherwise, rip off everything up to the final /
*/
if ( (tty = ttyname(fileno(stdin))) == 0 )
{
fprintf(stderr, "cannot get tty [%s]\n", strerror(errno) );
exit(EXIT_FAILURE);
}
if ( strncmp(tty, "/dev/", 5) == 0 )
tty += 5;
/*---------------------------------------------------------------
* LOCATE UTMPX
*
* Look in the utmpx file for a record matching this line, but
* the lookup is done with a prototype UTMPX record that has the
* ut_line member filled in.
*/
memset(&protox, 0, sizeof protox);
strcpy(protox.ut_line, tty);
if ( (utp = getutxline(&protox) ) == 0 )
{
fprintf(stderr, "cannot locate UTMPX for {%s}\n", tty);
exit(EXIT_FAILURE);
}
/*---------------------------------------------------------------
* FOUND IT!
*
* We should have a NUL-byte terminated string, but we believe
* that we've seen systems which use up to the full size of the
* buffer without the trailing NUL. That would mean we might end
* up with a runaway string. That would be bad.
*
* So we create a buffer one byte larger, copy the ut_host field
* into it, and assuredly add our own NUL byte.
*
* This may be overkill, but we don't get so snookered by funky
* data.
*/
{
#define SZ sizeof(utp->ut_host)
char linebuf[1 + SZ];
memcpy(linebuf, utp->ut_host, SZ);
linebuf[SZ] = '\0';
puts(linebuf);
}
return EXIT_SUCCESS;
}
Choose download locationDownload
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment