xref: /openbsd-src/gnu/usr.bin/perl/cpan/libnet/lib/Net/Domain.pm (revision e068048151d29f2562a32185e21a8ba885482260)
1b8851fccSafresh1# Net::Domain.pm
2b8851fccSafresh1#
35759b3d2Safresh1# Copyright (C) 1995-1998 Graham Barr.  All rights reserved.
4eac174f2Safresh1# Copyright (C) 2013-2014, 2020 Steve Hay.  All rights reserved.
5b8851fccSafresh1# This module is free software; you can redistribute it and/or modify it under
6b8851fccSafresh1# the same terms as Perl itself, i.e. under the terms of either the GNU General
7b8851fccSafresh1# Public License or the Artistic License, as specified in the F<LICENCE> file.
8b8851fccSafresh1
9b8851fccSafresh1package Net::Domain;
10b8851fccSafresh1
11b8851fccSafresh1use 5.008001;
12b8851fccSafresh1
13b8851fccSafresh1use strict;
14b8851fccSafresh1use warnings;
15b8851fccSafresh1
16b8851fccSafresh1use Carp;
17b8851fccSafresh1use Exporter;
18b8851fccSafresh1use Net::Config;
19b8851fccSafresh1
20b8851fccSafresh1our @ISA       = qw(Exporter);
21b8851fccSafresh1our @EXPORT_OK = qw(hostname hostdomain hostfqdn domainname);
22*e0680481Safresh1our $VERSION = "3.15";
23b8851fccSafresh1
24b8851fccSafresh1my ($host, $domain, $fqdn) = (undef, undef, undef);
25b8851fccSafresh1
26b8851fccSafresh1# Try every conceivable way to get hostname.
27b8851fccSafresh1
28b8851fccSafresh1
29b8851fccSafresh1sub _hostname {
30b8851fccSafresh1
31b8851fccSafresh1  # we already know it
32b8851fccSafresh1  return $host
33b8851fccSafresh1    if (defined $host);
34b8851fccSafresh1
35b8851fccSafresh1  if ($^O eq 'MSWin32') {
36b8851fccSafresh1    require Socket;
37b8851fccSafresh1    my ($name, $alias, $type, $len, @addr) = gethostbyname($ENV{'COMPUTERNAME'} || 'localhost');
38b8851fccSafresh1    while (@addr) {
39b8851fccSafresh1      my $a = shift(@addr);
40b8851fccSafresh1      $host = gethostbyaddr($a, Socket::AF_INET());
41b8851fccSafresh1      last if defined $host;
42b8851fccSafresh1    }
43b8851fccSafresh1    if (defined($host) && index($host, '.') > 0) {
44b8851fccSafresh1      $fqdn = $host;
45b8851fccSafresh1      ($host, $domain) = $fqdn =~ /^([^.]+)\.(.*)$/;
46b8851fccSafresh1    }
47b8851fccSafresh1    return $host;
48b8851fccSafresh1  }
49b8851fccSafresh1  elsif ($^O eq 'MacOS') {
50b8851fccSafresh1    chomp($host = `hostname`);
51b8851fccSafresh1  }
52b8851fccSafresh1  elsif ($^O eq 'VMS') {    ## multiple varieties of net s/w makes this hard
53b8851fccSafresh1    $host = $ENV{'UCX$INET_HOST'}      if defined($ENV{'UCX$INET_HOST'});
54b8851fccSafresh1    $host = $ENV{'MULTINET_HOST_NAME'} if defined($ENV{'MULTINET_HOST_NAME'});
55b8851fccSafresh1    if (index($host, '.') > 0) {
56b8851fccSafresh1      $fqdn = $host;
57b8851fccSafresh1      ($host, $domain) = $fqdn =~ /^([^.]+)\.(.*)$/;
58b8851fccSafresh1    }
59b8851fccSafresh1    return $host;
60b8851fccSafresh1  }
61b8851fccSafresh1  else {
62b8851fccSafresh1    local $SIG{'__DIE__'};
63b8851fccSafresh1
64b8851fccSafresh1    # syscall is preferred since it avoids tainting problems
65b8851fccSafresh1    eval {
66b8851fccSafresh1      my $tmp = "\0" x 256;    ## preload scalar
67b8851fccSafresh1      eval {
68b8851fccSafresh1        package main;
69b8851fccSafresh1        require "syscall.ph"; ## no critic (Modules::RequireBarewordIncludes)
70b8851fccSafresh1        defined(&main::SYS_gethostname);
71b8851fccSafresh1        }
72b8851fccSafresh1        || eval {
73b8851fccSafresh1        package main;
74b8851fccSafresh1        require "sys/syscall.ph"; ## no critic (Modules::RequireBarewordIncludes)
75b8851fccSafresh1        defined(&main::SYS_gethostname);
76b8851fccSafresh1        }
77b8851fccSafresh1        and $host =
78b8851fccSafresh1        (syscall(&main::SYS_gethostname, $tmp, 256) == 0)
79b8851fccSafresh1        ? $tmp
80b8851fccSafresh1        : undef;
81b8851fccSafresh1      }
82b8851fccSafresh1
83b8851fccSafresh1      # POSIX
84b8851fccSafresh1      || eval {
85b8851fccSafresh1      require POSIX;
86b8851fccSafresh1      $host = (POSIX::uname())[1];
87b8851fccSafresh1      }
88b8851fccSafresh1
89b8851fccSafresh1      # trusty old hostname command
90b8851fccSafresh1      || eval {
91b8851fccSafresh1      chop($host = `(hostname) 2>/dev/null`);    # BSD'ish
92b8851fccSafresh1      }
93b8851fccSafresh1
94b8851fccSafresh1      # sysV/POSIX uname command (may truncate)
95b8851fccSafresh1      || eval {
96b8851fccSafresh1      chop($host = `uname -n 2>/dev/null`);      ## SYSV'ish && POSIX'ish
97b8851fccSafresh1      }
98b8851fccSafresh1
99b8851fccSafresh1      # Apollo pre-SR10
100b8851fccSafresh1      || eval { $host = (split(/[:. ]/, `/com/host`, 6))[0]; }
101b8851fccSafresh1
102b8851fccSafresh1      || eval { $host = ""; };
103b8851fccSafresh1  }
104b8851fccSafresh1
105b8851fccSafresh1  # remove garbage
106b8851fccSafresh1  $host =~ s/[\0\r\n]+//go;
107b8851fccSafresh1  $host =~ s/(\A\.+|\.+\Z)//go;
108b8851fccSafresh1  $host =~ s/\.\.+/\./go;
109b8851fccSafresh1
110b8851fccSafresh1  $host;
111b8851fccSafresh1}
112b8851fccSafresh1
113b8851fccSafresh1
114b8851fccSafresh1sub _hostdomain {
115b8851fccSafresh1
116b8851fccSafresh1  # we already know it
117b8851fccSafresh1  return $domain
118b8851fccSafresh1    if (defined $domain);
119b8851fccSafresh1
120b8851fccSafresh1  local $SIG{'__DIE__'};
121b8851fccSafresh1
122b8851fccSafresh1  return $domain = $NetConfig{'inet_domain'}
123b8851fccSafresh1    if defined $NetConfig{'inet_domain'};
124b8851fccSafresh1
125b8851fccSafresh1  # try looking in /etc/resolv.conf
126b8851fccSafresh1  # putting this here and assuming that it is correct, eliminates
127b8851fccSafresh1  # calls to gethostbyname, and therefore DNS lookups. This helps
128b8851fccSafresh1  # those on dialup systems.
129b8851fccSafresh1
130b8851fccSafresh1  local ($_);
131b8851fccSafresh1
132b8851fccSafresh1  if (open(my $res, '<', "/etc/resolv.conf")) {
133b8851fccSafresh1    while (<$res>) {
134b8851fccSafresh1      $domain = $1
135b8851fccSafresh1        if (/\A\s*(?:domain|search)\s+(\S+)/);
136b8851fccSafresh1    }
137b8851fccSafresh1    close($res);
138b8851fccSafresh1
139b8851fccSafresh1    return $domain
140b8851fccSafresh1      if (defined $domain);
141b8851fccSafresh1  }
142b8851fccSafresh1
143b8851fccSafresh1  # just try hostname and system calls
144b8851fccSafresh1
145b8851fccSafresh1  my $host = _hostname();
146b8851fccSafresh1  my (@hosts);
147b8851fccSafresh1
148b8851fccSafresh1  @hosts = ($host, "localhost");
149b8851fccSafresh1
150b8851fccSafresh1  unless (defined($host) && $host =~ /\./) {
151b8851fccSafresh1    my $dom = undef;
152b8851fccSafresh1    eval {
153b8851fccSafresh1      my $tmp = "\0" x 256;    ## preload scalar
154b8851fccSafresh1      eval {
155b8851fccSafresh1        package main;
156b8851fccSafresh1        require "syscall.ph"; ## no critic (Modules::RequireBarewordIncludes)
157b8851fccSafresh1        }
158b8851fccSafresh1        || eval {
159b8851fccSafresh1        package main;
160b8851fccSafresh1        require "sys/syscall.ph"; ## no critic (Modules::RequireBarewordIncludes)
161b8851fccSafresh1        }
162b8851fccSafresh1        and $dom =
163b8851fccSafresh1        (syscall(&main::SYS_getdomainname, $tmp, 256) == 0)
164b8851fccSafresh1        ? $tmp
165b8851fccSafresh1        : undef;
166b8851fccSafresh1    };
167b8851fccSafresh1
168b8851fccSafresh1    if ($^O eq 'VMS') {
169b8851fccSafresh1      $dom ||= $ENV{'TCPIP$INET_DOMAIN'}
170b8851fccSafresh1        || $ENV{'UCX$INET_DOMAIN'};
171b8851fccSafresh1    }
172b8851fccSafresh1
173b8851fccSafresh1    chop($dom = `domainname 2>/dev/null`)
174b8851fccSafresh1      unless (defined $dom || $^O =~ /^(?:cygwin|MSWin32|android)/);
175b8851fccSafresh1
176b8851fccSafresh1    if (defined $dom) {
177b8851fccSafresh1      my @h = ();
178b8851fccSafresh1      $dom =~ s/^\.+//;
179b8851fccSafresh1      while (length($dom)) {
180b8851fccSafresh1        push(@h, "$host.$dom");
181b8851fccSafresh1        $dom =~ s/^[^.]+.+// or last;
182b8851fccSafresh1      }
183b8851fccSafresh1      unshift(@hosts, @h);
184b8851fccSafresh1    }
185b8851fccSafresh1  }
186b8851fccSafresh1
187b8851fccSafresh1  # Attempt to locate FQDN
188b8851fccSafresh1
189b8851fccSafresh1  foreach (grep { defined $_ } @hosts) {
190b8851fccSafresh1    my @info = gethostbyname($_);
191b8851fccSafresh1
192b8851fccSafresh1    next unless @info;
193b8851fccSafresh1
194b8851fccSafresh1    # look at real name & aliases
195b8851fccSafresh1    foreach my $site ($info[0], split(/ /, $info[1])) {
196b8851fccSafresh1      if (rindex($site, ".") > 0) {
197b8851fccSafresh1
198b8851fccSafresh1        # Extract domain from FQDN
199b8851fccSafresh1
200b8851fccSafresh1        ($domain = $site) =~ s/\A[^.]+\.//;
201b8851fccSafresh1        return $domain;
202b8851fccSafresh1      }
203b8851fccSafresh1    }
204b8851fccSafresh1  }
205b8851fccSafresh1
206b8851fccSafresh1  # Look for environment variable
207b8851fccSafresh1
208b8851fccSafresh1  $domain ||= $ENV{LOCALDOMAIN} || $ENV{DOMAIN};
209b8851fccSafresh1
210b8851fccSafresh1  if (defined $domain) {
211b8851fccSafresh1    $domain =~ s/[\r\n\0]+//g;
212b8851fccSafresh1    $domain =~ s/(\A\.+|\.+\Z)//g;
213b8851fccSafresh1    $domain =~ s/\.\.+/\./g;
214b8851fccSafresh1  }
215b8851fccSafresh1
216b8851fccSafresh1  $domain;
217b8851fccSafresh1}
218b8851fccSafresh1
219b8851fccSafresh1
220b8851fccSafresh1sub domainname {
221b8851fccSafresh1
222b8851fccSafresh1  return $fqdn
223b8851fccSafresh1    if (defined $fqdn);
224b8851fccSafresh1
225b8851fccSafresh1  _hostname();
226b8851fccSafresh1
227b8851fccSafresh1  # *.local names are special on darwin. If we call gethostbyname below, it
228b8851fccSafresh1  # may hang while waiting for another, non-existent computer to respond.
229b8851fccSafresh1  if($^O eq 'darwin' && $host =~ /\.local$/) {
230b8851fccSafresh1    return $host;
231b8851fccSafresh1  }
232b8851fccSafresh1
233b8851fccSafresh1  _hostdomain();
234b8851fccSafresh1
235b8851fccSafresh1  # Assumption: If the host name does not contain a period
236b8851fccSafresh1  # and the domain name does, then assume that they are correct
237b8851fccSafresh1  # this helps to eliminate calls to gethostbyname, and therefore
238b8851fccSafresh1  # eliminate DNS lookups
239b8851fccSafresh1
240b8851fccSafresh1  return $fqdn = $host . "." . $domain
241b8851fccSafresh1    if (defined $host
242b8851fccSafresh1    and defined $domain
243b8851fccSafresh1    and $host !~ /\./
244b8851fccSafresh1    and $domain =~ /\./);
245b8851fccSafresh1
246b8851fccSafresh1  # For hosts that have no name, just an IP address
247b8851fccSafresh1  return $fqdn = $host if defined $host and $host =~ /^\d+(\.\d+){3}$/;
248b8851fccSafresh1
249b8851fccSafresh1  my @host   = defined $host   ? split(/\./, $host)   : ('localhost');
250b8851fccSafresh1  my @domain = defined $domain ? split(/\./, $domain) : ();
251b8851fccSafresh1  my @fqdn   = ();
252b8851fccSafresh1
253b8851fccSafresh1  # Determine from @host & @domain the FQDN
254b8851fccSafresh1
255b8851fccSafresh1  my @d = @domain;
256b8851fccSafresh1
257b8851fccSafresh1LOOP:
258b8851fccSafresh1  while (1) {
259b8851fccSafresh1    my @h = @host;
260b8851fccSafresh1    while (@h) {
261b8851fccSafresh1      my $tmp = join(".", @h, @d);
262b8851fccSafresh1      if ((gethostbyname($tmp))[0]) {
263b8851fccSafresh1        @fqdn = (@h, @d);
264b8851fccSafresh1        $fqdn = $tmp;
265b8851fccSafresh1        last LOOP;
266b8851fccSafresh1      }
267b8851fccSafresh1      pop @h;
268b8851fccSafresh1    }
269b8851fccSafresh1    last unless shift @d;
270b8851fccSafresh1  }
271b8851fccSafresh1
272b8851fccSafresh1  if (@fqdn) {
273b8851fccSafresh1    $host = shift @fqdn;
274b8851fccSafresh1    until ((gethostbyname($host))[0]) {
275b8851fccSafresh1      $host .= "." . shift @fqdn;
276b8851fccSafresh1    }
277b8851fccSafresh1    $domain = join(".", @fqdn);
278b8851fccSafresh1  }
279b8851fccSafresh1  else {
280b8851fccSafresh1    undef $host;
281b8851fccSafresh1    undef $domain;
282b8851fccSafresh1    undef $fqdn;
283b8851fccSafresh1  }
284b8851fccSafresh1
285b8851fccSafresh1  $fqdn;
286b8851fccSafresh1}
287b8851fccSafresh1
288b8851fccSafresh1
289b8851fccSafresh1sub hostfqdn { domainname() }
290b8851fccSafresh1
291b8851fccSafresh1
292b8851fccSafresh1sub hostname {
293b8851fccSafresh1  domainname()
294b8851fccSafresh1    unless (defined $host);
295b8851fccSafresh1  return $host;
296b8851fccSafresh1}
297b8851fccSafresh1
298b8851fccSafresh1
299b8851fccSafresh1sub hostdomain {
300b8851fccSafresh1  domainname()
301b8851fccSafresh1    unless (defined $domain);
302b8851fccSafresh1  return $domain;
303b8851fccSafresh1}
304b8851fccSafresh1
305b8851fccSafresh11;    # Keep require happy
306b8851fccSafresh1
307b8851fccSafresh1__END__
308b8851fccSafresh1
309b8851fccSafresh1=head1 NAME
310b8851fccSafresh1
311b8851fccSafresh1Net::Domain - Attempt to evaluate the current host's internet name and domain
312b8851fccSafresh1
313b8851fccSafresh1=head1 SYNOPSIS
314b8851fccSafresh1
315b8851fccSafresh1    use Net::Domain qw(hostname hostfqdn hostdomain domainname);
316b8851fccSafresh1
317b8851fccSafresh1=head1 DESCRIPTION
318b8851fccSafresh1
319b8851fccSafresh1Using various methods B<attempt> to find the Fully Qualified Domain Name (FQDN)
320b8851fccSafresh1of the current host. From this determine the host-name and the host-domain.
321b8851fccSafresh1
322b8851fccSafresh1Each of the functions will return I<undef> if the FQDN cannot be determined.
323b8851fccSafresh1
324eac174f2Safresh1=head2 Functions
325eac174f2Safresh1
326b8851fccSafresh1=over 4
327b8851fccSafresh1
328eac174f2Safresh1=item C<hostfqdn()>
329b8851fccSafresh1
330b8851fccSafresh1Identify and return the FQDN of the current host.
331b8851fccSafresh1
332eac174f2Safresh1=item C<domainname()>
333b8851fccSafresh1
334b8851fccSafresh1An alias for hostfqdn().
335b8851fccSafresh1
336eac174f2Safresh1=item C<hostname()>
337b8851fccSafresh1
338b8851fccSafresh1Returns the smallest part of the FQDN which can be used to identify the host.
339b8851fccSafresh1
340eac174f2Safresh1=item C<hostdomain()>
341b8851fccSafresh1
342b8851fccSafresh1Returns the remainder of the FQDN after the I<hostname> has been removed.
343b8851fccSafresh1
344b8851fccSafresh1=back
345b8851fccSafresh1
346eac174f2Safresh1=head1 EXPORTS
347eac174f2Safresh1
348eac174f2Safresh1The following symbols are, or can be, exported by this module:
349eac174f2Safresh1
350eac174f2Safresh1=over 4
351eac174f2Safresh1
352eac174f2Safresh1=item Default Exports
353eac174f2Safresh1
354eac174f2Safresh1I<None>.
355eac174f2Safresh1
356eac174f2Safresh1=item Optional Exports
357eac174f2Safresh1
358eac174f2Safresh1C<hostname>,
359eac174f2Safresh1C<hostdomain>,
360eac174f2Safresh1C<hostfqdn>,
361eac174f2Safresh1C<domainname>.
362eac174f2Safresh1
363eac174f2Safresh1=item Export Tags
364eac174f2Safresh1
365eac174f2Safresh1I<None>.
366eac174f2Safresh1
367eac174f2Safresh1=back
368eac174f2Safresh1
369eac174f2Safresh1
370eac174f2Safresh1=head1 KNOWN BUGS
371eac174f2Safresh1
372eac174f2Safresh1See L<https://rt.cpan.org/Dist/Display.html?Status=Active&Queue=libnet>.
373eac174f2Safresh1
374b8851fccSafresh1=head1 AUTHOR
375b8851fccSafresh1
376eac174f2Safresh1Graham Barr E<lt>L<gbarr@pobox.com|mailto:gbarr@pobox.com>E<gt>.
3775759b3d2Safresh1
378eac174f2Safresh1Adapted from Sys::Hostname by David Sundstrom
379eac174f2Safresh1E<lt>L<sunds@asictest.sc.ti.com|mailto:sunds@asictest.sc.ti.com>E<gt>.
380b8851fccSafresh1
381eac174f2Safresh1Steve Hay E<lt>L<shay@cpan.org|mailto:shay@cpan.org>E<gt> is now maintaining
382eac174f2Safresh1libnet as of version 1.22_02.
383b8851fccSafresh1
384b8851fccSafresh1=head1 COPYRIGHT
385b8851fccSafresh1
3865759b3d2Safresh1Copyright (C) 1995-1998 Graham Barr.  All rights reserved.
3875759b3d2Safresh1
388eac174f2Safresh1Copyright (C) 2013-2014, 2020 Steve Hay.  All rights reserved.
3895759b3d2Safresh1
3905759b3d2Safresh1=head1 LICENCE
391b8851fccSafresh1
392b8851fccSafresh1This module is free software; you can redistribute it and/or modify it under the
393b8851fccSafresh1same terms as Perl itself, i.e. under the terms of either the GNU General Public
394b8851fccSafresh1License or the Artistic License, as specified in the F<LICENCE> file.
395b8851fccSafresh1
396eac174f2Safresh1=head1 VERSION
397eac174f2Safresh1
398*e0680481Safresh1Version 3.15
399eac174f2Safresh1
400eac174f2Safresh1=head1 DATE
401eac174f2Safresh1
402*e0680481Safresh120 March 2023
403eac174f2Safresh1
404eac174f2Safresh1=head1 HISTORY
405eac174f2Safresh1
406eac174f2Safresh1See the F<Changes> file.
407eac174f2Safresh1
408b8851fccSafresh1=cut
409