diff options
Diffstat (limited to 'scripts/dns.pl')
| -rw-r--r-- | scripts/dns.pl | 199 | 
1 files changed, 199 insertions, 0 deletions
| diff --git a/scripts/dns.pl b/scripts/dns.pl new file mode 100644 index 0000000..989cdc3 --- /dev/null +++ b/scripts/dns.pl @@ -0,0 +1,199 @@ +# /DNS <nick>|<host>|<ip> ... +# version 2.1.1 +#  +# updated the script to fix a bug where the script would let +# a trailing whitespace go through (ex: tab completion) +# - inch <inch@stmpd.net> + +use strict; +use Socket; +use POSIX; + +use vars qw($VERSION %IRSSI);  +$VERSION = "2.1.1"; +%IRSSI = ( +    authors	=> "Timo \'cras\' Sirainen", +    contact	=> "tss\@iki.fi",  +    name	=> "dns", +    description	=> "/DNS <nick>|<host>|<ip> ...", +    license	=> "Public Domain", +    url		=> "http://irssi.org/", +    changed	=> "2002-03-04T22:47+0100" +); + +my (%resolve_hosts, %resolve_nicks, %resolve_print); # resolve queues +my $userhosts; # number of USERHOSTs currently waiting for reply +my $lookup_waiting; # 1 if we're waiting a reply for host lookup + +# for the current host lookup +my ($print_server, $print_host, $print_name, @print_ips); +my ($input_skip_next, $input_query); + +my $pipe_tag; + +sub cmd_dns { +  my ($nicks, $server) = @_; +  return if !$nicks; +  $nicks =~ s/\s+$//;  +  # get list of nicks/hosts we want to know +  my $tag = !$server ? undef : $server->{tag}; +  my $ask_nicks = ""; +  my $print_error = 0; +  foreach my $nick (split(" ", $nicks)) { +    $nick = lc($nick); +    if ($nick =~ /[\.:]/) { +      # it's an IP or hostname +      $resolve_hosts{$nick} = $tag; +    } else { +      # it's nick +      if (!$print_error && (!$server || !$server->{connected})) { +	$print_error = 1; +	Irssi::print("Not connected to server"); +      } else { +	$resolve_nicks{$nick} = 1; +	$ask_nicks .= "$nick "; +      } +    } +  } + +  if ($ask_nicks ne "") { +    # send the USERHOST query +    $userhosts++; +    $server->redirect_event('userhost', 1, $ask_nicks, 0, 'redir dns failure', { +                            'event 302' => 'redir dns host', +                            '' => 'event empty' } ); +    $server->send_raw("USERHOST :$nicks"); +  } + +  # ask the IPs/hostnames immediately +  host_lookup() if (!$lookup_waiting); +} + +sub sig_failure { +  Irssi::print("Error getting hostname for nick"); +  %resolve_nicks = () if (--$userhosts == 0); +} + +sub sig_userhost { +  my ($server, $data) = @_; +  $data =~ s/^[^ ]* :?//; +  my @hosts = split(/ +/, $data); + +  # move resolve_nicks -> resolve_hosts +  foreach my $host (@hosts) { +    if ($host =~ /^([^=\*]*)\*?=.(.*)@(.*)/) { +      my $nick = lc($1); +      my $user = $2; +      $host = lc($3); + +      $resolve_hosts{$host} = $resolve_nicks{$nick}; +      delete $resolve_nicks{$nick}; +      $resolve_print{$host} = "[$nick!$user"."@"."$host]"; +    } +  } + +  if (--$userhosts == 0 && %resolve_nicks) { +    # unknown nicks - they didn't contain . or : so it can't be +    # IP or hostname. +    Irssi::print("Unknown nicks: ".join(' ', keys %resolve_nicks)); +    %resolve_nicks = (); +  } + +  host_lookup() if (!$lookup_waiting); +} + +sub host_lookup { +  return if (!%resolve_hosts); + +  my ($host) = keys %resolve_hosts; +  $print_server = $resolve_hosts{$host}; + +  $print_host = undef; +  $print_name = $resolve_print{$host}; +  @print_ips = (); + +  delete $resolve_hosts{$host}; +  delete $resolve_print{$host}; + +  $input_query = $host; +  $input_skip_next = 0; + +  # pipe is used to get the reply from child +  my ($rh, $wh); +  pipe($rh, $wh); + +  # non-blocking host lookups with fork()ing +  my $pid = fork(); +  if (!defined($pid)) { +    %resolve_hosts = (); +    %resolve_print = (); +    Irssi::print("Can't fork() - aborting"); +    close($rh); close($wh); +    return; +  } +  $lookup_waiting++; + +  if ($pid > 0) { +    # parent, wait for reply +    close($wh); +    Irssi::pidwait_add($pid); +    $pipe_tag = Irssi::input_add(fileno($rh), INPUT_READ, \&pipe_input, $rh); +    return; +  } + +  my $text; +  eval { +    # child, do the lookup +    my $name = ""; +    if ($host =~ /^[0-9\.]*$/) { +      # ip -> host +      $name = gethostbyaddr(inet_aton($host), AF_INET); +    } else { +      # host -> ip +      my @addrs = gethostbyname($host); +      if (@addrs) { +	@addrs = map { inet_ntoa($_) } @addrs[4 .. $#addrs]; +	$name = join (" ", @addrs); +      } +    } + +    $print_name = $input_query if !$print_name; +    if (!$name) { +      $text = "No information for $print_name"; +    } else { +      $text = "$print_name: $name"; +    } +  }; +  $text = $! if (!$text); + +  eval { +    # write the reply +    print($wh $text); +    close($wh); +  }; +  POSIX::_exit(1); +} + +sub pipe_input { +  my $rh = shift; +  my $text = <$rh>; +  close($rh); + +  Irssi::input_remove($pipe_tag); +  $pipe_tag = -1; + +  my $server = Irssi::server_find_tag($print_server); +  if ($server) { +    $server->print('', $text); +  } else { +    Irssi::print($text); +  } + +  $lookup_waiting--; +  host_lookup(); +} + +Irssi::command_bind('dns', 'cmd_dns'); +Irssi::signal_add( { +        'redir dns failure' => \&sig_failure, +        'redir dns host' => \&sig_userhost } ); | 
