#!/usr2/new/bin/perl                                  #-*-perl-*-
# a subroutine to resolve a Internet host name to IP address
# Copyright (C) Khun Yee Fung (clipper@csd.uwo.ca) 1991
# You can do anything to this file except to sell it and/or pretend
# you wrote it. You must preserve the copyright notice.
package resolver;

sub main'resolver {
  local($sockaddr) = 'S n a4 x8';
  local($hostname, $server) = @_;
  local($port) = 53;

  if ($server =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)/) {
      $saddr = pack('CCCC', $1, $2, $3, $4);
  }
  elsif (!(($name, $aliases, $type, $len, $saddr) = gethostbyname($server))) {
      return 0;
  }
  local($sin) = pack($sockaddr, 2, $port, $saddr);

  socket(NSERVER, 2, 1, 0) || return 0;
  connect(NSERVER, $sin) || return 0;

  select(NSERVER); $| = 1; select(STDOUT); $| = 1;

  local($len) = 18 + length($hostname);
  local(@names) = split('\.', $hostname);
  local($head) = pack('S6', 319, 256, 1, 0, 0, 0);
  print NSERVER pack('S', $len), $head;
  local($arg, $response);
  foreach $arg (@names) {
    print NSERVER pack('C', length($arg)), $arg;
  }
  print NSERVER pack('CS2', 0, 1, 1);

  read(NSERVER, $len, 2);
  read(NSERVER, $response, unpack('S', $len));
  close NSERVER;

  local(@shead) = unpack('S6', $response);
  ($shead[1] & 0x0F) == 0 || return 0;

  local($in) = 12;
  local($ans) = $shead[2];
  local($c);
  while ($ans > 0) {
    while (($c = ord(substr($response, $in++, 1))) != 0) {
      $in += $c;
    }
    $in += 4;
    $ans--;
  }

  $ans = $shead[3];
  local($type, $rdlength, $rdata);
  local(@return);
  while ($ans > 0) {
    while (($c = ord(substr($response, $in++, 1))) != 0) {
      ($c & 0xc0) != 0xc0 || $in++, last;
      $in += $c;
    }
    $type = substr($response, $in, 2);
    $in += 8;
    $rdlength = unpack('n', substr($response, $in, 2));
    $in += 2;
    $rdata = substr($response, $in, $rdlength);
    if (unpack('S', $type) == 1) {
	push(@return, $rdata);
    }
    $in += $rdlength;
    $ans--;
  }
  return @return;
}

sub main'rresolver {
  local($sockaddr) = 'S n a4 x8';
  local($hostname, $server) = @_;
  local($port) = 53;

  if ($server =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)/) {
      $saddr = pack('CCCC', $1, $2, $3, $4);
  }
  elsif (!(($name, $aliases, $type, $len, $saddr) = gethostbyname($server))) {
      return 0;
  }
  local($sin) = pack($sockaddr, 2, $port, $saddr);

  socket(NSERVER, 2, 1, 0) || return 0;
  connect(NSERVER, $sin) || return 0;

  select(NSERVER); $| = 1; select(STDOUT); $| = 1;

  local($len) = 18 + length($hostname);
  local(@names) = split('\.', $hostname);
  local($head) = pack('S6', 319, 256, 1, 0, 0, 0);
  print NSERVER pack('S', $len), $head;
  @names = reverse(@names);
  push(@names, "in-addr", "arpa");
  foreach $arg (@names) {
    print NSERVER pack('C', length($arg)), $arg;
  }
  print NSERVER pack('CS2', 0, 12, 1);

  read(NSERVER, $len, 2);
  read(NSERVER, $response, unpack('S', $len));
  close NSERVER;

  @shead = unpack('S6', $response);
  ($shead[1] & 0x0F) == 0 || return 0;

  $in = 12;
  $ans = $shead[2];
  while ($ans > 0) {
    while (($c = ord(substr($response, $in++, 1))) != 0) {
      $in += $c;
    }
    $in += 4;
    $ans--;
  }

  $ans = $shead[3];
  local($type, $rdlength, $rdata);
  local(@return);
  while ($ans > 0) {
    while (($c = ord(substr($response, $in++, 1))) != 0) {
      ($c & 0xc0) != 0xc0 || $in++, last;
      $in += $c;
    }
    $type = substr($response, $in, 2);
    $in += 8;
    $rdlength = unpack('n', substr($response, $in, 2));
    $in += 2;
    $rdata = substr($response, $in, $rdlength);
    if (unpack('S', $type) == 12) {
	return(&label());
    }
    $in += $rdlength;
    $ans--;
  }
  return 0;
}

sub label {
  $qname = "";
  $c = substr($response, $in, 1); $in++;
  $offset = $in;
  $forward = 1;
  loop: while ($c ne "\000") {
    $cc = ord($c);
    if (($cc & 0xc0) == 0xc0) {
      if ($forward) {
        $forward = 0;
        $in = $offset + 1;
      }
      $offset = ($cc - 192) * 256 + ord(substr($response, $offset, 1));
    }
    else {
      $qname = $qname . substr($response, $offset, $cc) . "."; $offset += $cc;
    }
    $c = substr($response, $offset, 1); $offset++;
  }
  if ($forward) {
    $in = $offset;
  }
  chop($qname);
  print "$qname\n";
}

1;
