File Coverage

blib/lib/Net/Domain.pm
Criterion Covered Total %
statement 50 132 37.8
branch 17 76 22.3
condition 8 56 14.2
subroutine 12 12 100.0
pod 4 4 100.0
total 91 280 32.5


line stmt bran cond sub pod time code
1             # Net::Domain.pm
2             #
3             # Copyright (C) 1995-1998 Graham Barr. All rights reserved.
4             # Copyright (C) 2013-2014, 2020 Steve Hay. All rights reserved.
5             # This module is free software; you can redistribute it and/or modify it under
6             # the same terms as Perl itself, i.e. under the terms of either the GNU General
7             # Public License or the Artistic License, as specified in the F file.
8              
9             package Net::Domain;
10              
11 2     2   4861 use 5.008001;
  2         14  
12              
13 2     2   9 use strict;
  2         11  
  2         39  
14 2     2   8 use warnings;
  2         4  
  2         61  
15              
16 2     2   9 use Carp;
  2         3  
  2         123  
17 2     2   10 use Exporter;
  2         3  
  2         72  
18 2     2   330 use Net::Config;
  2         4  
  2         3567  
19              
20             our @ISA = qw(Exporter);
21             our @EXPORT_OK = qw(hostname hostdomain hostfqdn domainname);
22             our $VERSION = "3.13";
23              
24             my ($host, $domain, $fqdn) = (undef, undef, undef);
25              
26             # Try every conceivable way to get hostname.
27              
28              
29             sub _hostname {
30              
31             # we already know it
32 1 50   1   4 return $host
33             if (defined $host);
34              
35 1 50       7 if ($^O eq 'MSWin32') {
    50          
    50          
36 0         0 require Socket;
37 0   0     0 my ($name, $alias, $type, $len, @addr) = gethostbyname($ENV{'COMPUTERNAME'} || 'localhost');
38 0         0 while (@addr) {
39 0         0 my $a = shift(@addr);
40 0         0 $host = gethostbyaddr($a, Socket::AF_INET());
41 0 0       0 last if defined $host;
42             }
43 0 0 0     0 if (defined($host) && index($host, '.') > 0) {
44 0         0 $fqdn = $host;
45 0         0 ($host, $domain) = $fqdn =~ /^([^.]+)\.(.*)$/;
46             }
47 0         0 return $host;
48             }
49             elsif ($^O eq 'MacOS') {
50 0         0 chomp($host = `hostname`);
51             }
52             elsif ($^O eq 'VMS') { ## multiple varieties of net s/w makes this hard
53 0 0       0 $host = $ENV{'UCX$INET_HOST'} if defined($ENV{'UCX$INET_HOST'});
54 0 0       0 $host = $ENV{'MULTINET_HOST_NAME'} if defined($ENV{'MULTINET_HOST_NAME'});
55 0 0       0 if (index($host, '.') > 0) {
56 0         0 $fqdn = $host;
57 0         0 ($host, $domain) = $fqdn =~ /^([^.]+)\.(.*)$/;
58             }
59 0         0 return $host;
60             }
61             else {
62 1         3 local $SIG{'__DIE__'};
63              
64             # syscall is preferred since it avoids tainting problems
65             eval {
66 1         2 my $tmp = "\0" x 256; ## preload scalar
67             eval {
68             package main;
69 1         166 require "syscall.ph"; ## no critic (Modules::RequireBarewordIncludes)
70 0         0 defined(&main::SYS_gethostname);
71             }
72 1 0 33     2 || eval {
    50          
73             package main;
74 1         123 require "sys/syscall.ph"; ## no critic (Modules::RequireBarewordIncludes)
75 0         0 defined(&main::SYS_gethostname);
76             }
77             and $host =
78             (syscall(&main::SYS_gethostname, $tmp, 256) == 0)
79             ? $tmp
80             : undef;
81             }
82              
83             # POSIX
84             || eval {
85 1         398 require POSIX;
86 1         5271 $host = (POSIX::uname())[1];
87             }
88              
89             # trusty old hostname command
90             || eval {
91 0         0 chop($host = `(hostname) 2>/dev/null`); # BSD'ish
92             }
93              
94             # sysV/POSIX uname command (may truncate)
95             || eval {
96 0         0 chop($host = `uname -n 2>/dev/null`); ## SYSV'ish && POSIX'ish
97             }
98              
99             # Apollo pre-SR10
100 0         0 || eval { $host = (split(/[:. ]/, `/com/host`, 6))[0]; }
101              
102 1 0 33     2 || eval { $host = ""; };
  0   33     0  
      33        
      0        
103             }
104              
105             # remove garbage
106 1         4 $host =~ s/[\0\r\n]+//go;
107 1         5 $host =~ s/(\A\.+|\.+\Z)//go;
108 1         3 $host =~ s/\.\.+/\./go;
109              
110 1         2 $host;
111             }
112              
113              
114             sub _hostdomain {
115              
116             # we already know it
117 1 50   1   3 return $domain
118             if (defined $domain);
119              
120 1         3 local $SIG{'__DIE__'};
121              
122             return $domain = $NetConfig{'inet_domain'}
123 1 50       5 if defined $NetConfig{'inet_domain'};
124              
125             # try looking in /etc/resolv.conf
126             # putting this here and assuming that it is correct, eliminates
127             # calls to gethostbyname, and therefore DNS lookups. This helps
128             # those on dialup systems.
129              
130 1         1 local ($_);
131              
132 1 50       33 if (open(my $res, '<', "/etc/resolv.conf")) {
133 1         17 while (<$res>) {
134 6 100       28 $domain = $1
135             if (/\A\s*(?:domain|search)\s+(\S+)/);
136             }
137 1         9 close($res);
138              
139 1 50       7 return $domain
140             if (defined $domain);
141             }
142              
143             # just try hostname and system calls
144              
145 0         0 my $host = _hostname();
146 0         0 my (@hosts);
147              
148 0         0 @hosts = ($host, "localhost");
149              
150 0 0 0     0 unless (defined($host) && $host =~ /\./) {
151 0         0 my $dom = undef;
152 0         0 eval {
153 0         0 my $tmp = "\0" x 256; ## preload scalar
154             eval {
155             package main;
156 0         0 require "syscall.ph"; ## no critic (Modules::RequireBarewordIncludes)
157             }
158 0 0 0     0 || eval {
    0          
159             package main;
160 0         0 require "sys/syscall.ph"; ## no critic (Modules::RequireBarewordIncludes)
161             }
162             and $dom =
163             (syscall(&main::SYS_getdomainname, $tmp, 256) == 0)
164             ? $tmp
165             : undef;
166             };
167              
168 0 0       0 if ($^O eq 'VMS') {
169             $dom ||= $ENV{'TCPIP$INET_DOMAIN'}
170 0   0     0 || $ENV{'UCX$INET_DOMAIN'};
      0        
171             }
172              
173 0 0 0     0 chop($dom = `domainname 2>/dev/null`)
174             unless (defined $dom || $^O =~ /^(?:cygwin|MSWin32|android)/);
175              
176 0 0       0 if (defined $dom) {
177 0         0 my @h = ();
178 0         0 $dom =~ s/^\.+//;
179 0         0 while (length($dom)) {
180 0         0 push(@h, "$host.$dom");
181 0 0       0 $dom =~ s/^[^.]+.+// or last;
182             }
183 0         0 unshift(@hosts, @h);
184             }
185             }
186              
187             # Attempt to locate FQDN
188              
189 0         0 foreach (grep { defined $_ } @hosts) {
  0         0  
190 0         0 my @info = gethostbyname($_);
191              
192 0 0       0 next unless @info;
193              
194             # look at real name & aliases
195 0         0 foreach my $site ($info[0], split(/ /, $info[1])) {
196 0 0       0 if (rindex($site, ".") > 0) {
197              
198             # Extract domain from FQDN
199              
200 0         0 ($domain = $site) =~ s/\A[^.]+\.//;
201 0         0 return $domain;
202             }
203             }
204             }
205              
206             # Look for environment variable
207              
208 0   0     0 $domain ||= $ENV{LOCALDOMAIN} || $ENV{DOMAIN};
      0        
209              
210 0 0       0 if (defined $domain) {
211 0         0 $domain =~ s/[\r\n\0]+//g;
212 0         0 $domain =~ s/(\A\.+|\.+\Z)//g;
213 0         0 $domain =~ s/\.\.+/\./g;
214             }
215              
216 0         0 $domain;
217             }
218              
219              
220             sub domainname {
221              
222 3 100   3 1 27 return $fqdn
223             if (defined $fqdn);
224              
225 1         3 _hostname();
226              
227             # *.local names are special on darwin. If we call gethostbyname below, it
228             # may hang while waiting for another, non-existent computer to respond.
229 1 50 33     4 if($^O eq 'darwin' && $host =~ /\.local$/) {
230 0         0 return $host;
231             }
232              
233 1         3 _hostdomain();
234              
235             # Assumption: If the host name does not contain a period
236             # and the domain name does, then assume that they are correct
237             # this helps to eliminate calls to gethostbyname, and therefore
238             # eliminate DNS lookups
239              
240 1 50 33     16 return $fqdn = $host . "." . $domain
      33        
      33        
241             if (defined $host
242             and defined $domain
243             and $host !~ /\./
244             and $domain =~ /\./);
245              
246             # For hosts that have no name, just an IP address
247 0 0 0     0 return $fqdn = $host if defined $host and $host =~ /^\d+(\.\d+){3}$/;
248              
249 0 0       0 my @host = defined $host ? split(/\./, $host) : ('localhost');
250 0 0       0 my @domain = defined $domain ? split(/\./, $domain) : ();
251 0         0 my @fqdn = ();
252              
253             # Determine from @host & @domain the FQDN
254              
255 0         0 my @d = @domain;
256              
257             LOOP:
258 0         0 while (1) {
259 0         0 my @h = @host;
260 0         0 while (@h) {
261 0         0 my $tmp = join(".", @h, @d);
262 0 0       0 if ((gethostbyname($tmp))[0]) {
263 0         0 @fqdn = (@h, @d);
264 0         0 $fqdn = $tmp;
265 0         0 last LOOP;
266             }
267 0         0 pop @h;
268             }
269 0 0       0 last unless shift @d;
270             }
271              
272 0 0       0 if (@fqdn) {
273 0         0 $host = shift @fqdn;
274 0         0 until ((gethostbyname($host))[0]) {
275 0         0 $host .= "." . shift @fqdn;
276             }
277 0         0 $domain = join(".", @fqdn);
278             }
279             else {
280 0         0 undef $host;
281 0         0 undef $domain;
282 0         0 undef $fqdn;
283             }
284              
285 0         0 $fqdn;
286             }
287              
288              
289 1     1 1 8 sub hostfqdn { domainname() }
290              
291              
292             sub hostname {
293 5 50   5 1 28 domainname()
294             unless (defined $host);
295 5         10 return $host;
296             }
297              
298              
299             sub hostdomain {
300 5 50   5 1 15 domainname()
301             unless (defined $domain);
302 5         9 return $domain;
303             }
304              
305             1; # Keep require happy
306              
307             __END__