[LON-CAPA-cvs] cvs: loncom / lontrans.pm /auth lonacc.pm lonauth.pm lonlogin.pm lonlogout.pm lonracc.pm lonroles.pm lonstatusacc.pm lontokacc.pm lonwebdavacc.pm lonwebdavauth.pm migrateuser.pm publiccheck.pm switchserver.pm /cgi lonauthcgi.pm /interface createaccount.pm domainprefs.pm lonaboutme.pm loncommon.pm lonfeedback.pm lonmsg.pm lonsupportreq.pm resetpw.pm /lonnet/perl lonnet.pm

raeburn raeburn at source.lon-capa.org
Fri Dec 18 10:23:04 EST 2020


raeburn		Fri Dec 18 15:23:04 2020 EDT

  Modified files:              
    /loncom/interface	createaccount.pm domainprefs.pm lonaboutme.pm 
                     	loncommon.pm lonfeedback.pm lonmsg.pm 
                     	lonsupportreq.pm resetpw.pm 
    /loncom/auth	lonacc.pm lonauth.pm lonlogin.pm lonlogout.pm 
                	lonracc.pm lonroles.pm lonstatusacc.pm lontokacc.pm 
                	lonwebdavacc.pm lonwebdavauth.pm migrateuser.pm 
                	publiccheck.pm switchserver.pm 
    /loncom/lonnet/perl	lonnet.pm 
    /loncom/cgi	lonauthcgi.pm 
    /loncom	lontrans.pm 
  Log:
  - Retrieval of requestor's IP address centralized in lonnet::get_requestor_ip()
  - Domain configuration to allow domain's LON-CAPA nodes to operate behind a
    WAF/Reverse Proxy using aliased hostname (CNAME).
  - Web requests from other nodes bypass the WAF as their requests are made
    directly to the server hostname (A record); same for internal LON-CAPA 
    connections for lonc -> lond.
  
  
-------------- next part --------------
Index: loncom/interface/createaccount.pm
diff -u loncom/interface/createaccount.pm:1.81 loncom/interface/createaccount.pm:1.82
--- loncom/interface/createaccount.pm:1.81	Tue Sep  8 19:38:59 2020
+++ loncom/interface/createaccount.pm	Fri Dec 18 15:23:02 2020
@@ -4,7 +4,7 @@
 # kerberos, or SSO) or an e-mail address. Requests to use an e-mail address as
 # username may be processed automatically, or may be queued for approval.
 #
-# $Id: createaccount.pm,v 1.81 2020/09/08 19:38:59 raeburn Exp $
+# $Id: createaccount.pm,v 1.82 2020/12/18 15:23:02 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -982,7 +982,8 @@
             $msg .= '</form></p>';
             return $msg;
         }
-        my %info = ('ip'         => $ENV{'REMOTE_ADDR'},
+        my $ip = &Apache::lonnet::get_requestor_ip();
+        my %info = ('ip'         => $ip,
                     'time'       => $now,
                     'domain'     => $domain,
                     'username'   => $email,
@@ -1098,8 +1099,9 @@
                             &create_account($r,$domain,$domdesc,\%data);
                         if ($result eq 'ok') {
                             $msg = $output;
+                            my $ip = &Apache::lonnet::get_requestor_ip();
                             my $shownow = &Apache::lonlocal::locallocaltime($now);
-                            my $mailmsg = &mt('A LON-CAPA account for the institution: [_1] has been created [_2] from IP address: [_3]. If you did not perform this action or authorize it, please contact the [_4] ([_5]).',$domdesc,$shownow,$ENV{'REMOTE_ADDR'},$contact_name,$contact_email)."\n";
+                            my $mailmsg = &mt('A LON-CAPA account for the institution: [_1] has been created [_2] from IP address: [_3]. If you did not perform this action or authorize it, please contact the [_4] ([_5]).',$domdesc,$shownow,$ip,$contact_name,$contact_email)."\n";
                             my $mailresult = &Apache::resetpw::send_mail($domdesc,$data{'email'},
                                                                         $mailmsg,$contact_name,
                                                                         $contact_email);
@@ -1578,7 +1580,8 @@
                     '<input type="hidden" name="udom" value="'.$domain.'" />'."\n".
                     '<input type="hidden" name="phase" value="username_activation" />';
         my $now = time;
-        my %info = ('ip'         => $ENV{'REMOTE_ADDR'},
+        my $ip = &Apache::lonnet::get_requestor_ip();
+        my %info = ('ip'         => $ip,
                     'time'       => $now,
                     'domain'     => $domain,
                     'username'   => $username);
Index: loncom/interface/domainprefs.pm
diff -u loncom/interface/domainprefs.pm:1.372 loncom/interface/domainprefs.pm:1.373
--- loncom/interface/domainprefs.pm:1.372	Thu Sep 17 00:35:04 2020
+++ loncom/interface/domainprefs.pm	Fri Dec 18 15:23:02 2020
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # Handler to set domain-wide configuration settings
 #
-# $Id: domainprefs.pm,v 1.372 2020/09/17 00:35:04 raeburn Exp $
+# $Id: domainprefs.pm,v 1.373 2020/12/18 15:23:02 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -176,6 +176,7 @@
 use DateTime::TimeZone;
 use DateTime::Locale;
 use Time::HiRes qw( sleep );
+use Net::CIDR;
 
 my $registered_cleanup;
 my $modified_urls;
@@ -220,7 +221,7 @@
                 'coursedefaults','usersessions','loadbalancing',
                 'requestauthor','selfenrollment','inststatus',
                 'ltitools','ssl','trust','lti','privacy','passwords',
-                'proctoring'],$dom);
+                'proctoring','wafproxy'],$dom);
     my %encconfig =
         &Apache::lonnet::get_dom('encconfig',['ltitools','lti','proctoring'],$dom);
     if (ref($domconfig{'ltitools'}) eq 'HASH') {
@@ -259,11 +260,11 @@
             }
         }
     }
-    my @prefs_order = ('rolecolors','login','defaults','passwords','quotas','autoenroll',
-                       'autoupdate','autocreate','directorysrch','contacts','privacy',
-                       'usercreation','selfcreation','usermodification','scantron',
-                       'requestcourses','requestauthor','coursecategories',
-                       'serverstatuses','helpsettings','coursedefaults',
+    my @prefs_order = ('rolecolors','login','defaults','wafproxy','passwords','quotas',
+                       'autoenroll','autoupdate','autocreate','directorysrch',
+                       'contacts','privacy','usercreation','selfcreation',
+                       'usermodification','scantron','requestcourses','requestauthor'
+                       'coursecategories','serverstatuses','helpsettings','coursedefaults',
                        'ltitools','proctoring','selfenrollment','usersessions','ssl',
                        'trust','lti');
     my %existing;
@@ -310,6 +311,17 @@
                       print => \&print_defaults,
                       modify => \&modify_defaults,
                     },
+        'wafproxy' =>  
+                    { text => 'Web Application Firewall/Reverse Proxy',  
+                      help => 'Domain_Configuration_WAF_Proxy',
+                      header => [{col1 => 'Domain server',
+                                  col2 => 'Alias for WAF/Reverse Proxy',
+                                 },
+                                 {col1 => 'Setting',
+                                  col2 => 'Value',}],
+                      print => \&print_wafproxy,
+                      modify => \&modify_wafproxy, 
+                    },
         'passwords' =>
                     { text => 'Passwords (Internal authentication)',
                       help => 'Domain_Configuration_Passwords',
@@ -805,6 +817,8 @@
         $output = &modify_privacy($dom,%domconfig);
     } elsif ($action eq 'passwords') {
         $output = &modify_passwords($r,$dom,$confname,$lastactref,%domconfig);
+    } elsif ($action eq 'wafproxy') {
+        $output = &modify_wafproxy($dom,$action,$lastactref,%domconfig);
     }
     return $output;
 }
@@ -882,7 +896,7 @@
             ($action eq 'usermodification') || ($action eq 'defaults') || ($action eq 'coursedefaults') ||
             ($action eq 'selfenrollment') || ($action eq 'usersessions') || ($action eq 'ssl') ||
             ($action eq 'directorysrch') || ($action eq 'trust') || ($action eq 'helpsettings') ||
-            ($action eq 'contacts') || ($action eq 'privacy')) {
+            ($action eq 'contacts') || ($action eq 'privacy') || ($action eq 'wafproxy')) {
             $output .= $item->{'print'}->('top',$dom,$settings,\$rowtotal);
         } elsif ($action eq 'passwords') {
             $output .= $item->{'print'}->('top',$dom,$confname,$settings,\$rowtotal);
@@ -1005,7 +1019,7 @@
             $rowtotal ++;
         } elsif (($action eq 'usermodification') || ($action eq 'coursedefaults') ||
                  ($action eq 'defaults') || ($action eq 'directorysrch') ||
-                 ($action eq 'helpsettings')) {
+                 ($action eq 'helpsettings') || ($action eq 'wafproxy')) {
             $output .= $item->{'print'}->('bottom',$dom,$settings,\$rowtotal);
         } elsif ($action eq 'scantron') {
             $output .= $item->{'print'}->($r,'bottom',$dom,$confname,$settings,\$rowtotal);
@@ -7164,6 +7178,134 @@
     return $datatable;
 }
 
+sub print_wafproxy {
+    my ($position,$dom,$settings,$rowtotal) = @_;
+    my $css_class;
+    my $itemcount = 0;
+    my $datatable;
+    my %servers = &Apache::lonnet::internet_dom_servers($dom);
+    my (%othercontrol,%otherdoms,%aliases,%values,$setdom);
+    foreach my $server (sort(keys(%servers))) {
+        my $serverhome = &Apache::lonnet::get_server_homeID($servers{$server});
+        my $serverdom;
+        if ($serverhome ne $server) {
+            $serverdom = &Apache::lonnet::host_domain($serverhome);
+            $othercontrol{$server} = $serverdom;
+        } else {
+            $serverdom = &Apache::lonnet::host_domain($server);
+            if ($serverdom ne $dom) {
+                $othercontrol{$server} = $serverdom;
+            } else {
+                $setdom = 1;
+                if (ref($settings) eq 'HASH') {
+                    %{$values{$dom}} = ();
+                    if (ref($settings->{'alias'}) eq 'HASH') {
+                        $aliases{$dom} = $settings->{'alias'};
+                    }
+                    foreach my $item ('ipheader','trusted','exempt') {
+                        $values{$dom}{$item} = $settings->{$item};
+                    }
+                }
+            }
+        }
+    }
+    if (keys(%othercontrol)) {
+        %otherdoms = reverse(%othercontrol);
+        foreach my $domain (keys(%otherdoms)) {
+            %{$values{$domain}} = ();
+            my %config = &Apache::lonnet::get_dom('configuration',['wafproxy'],$domain);
+            if (ref($config{$domain}) eq 'HASH') {
+                if (ref($config{$domain}{'wafproxy'}) eq 'HASH') {
+                    $aliases{$domain} = $config{$domain}{'wafproxy'}{'alias'};
+                    foreach my $item ('exempt','trusted','ipheader') {
+                        $values{$domain}{$item} = $config{$domain}{'wafproxy'}{$item};
+                    }
+                }
+            }
+        }
+    }
+    if ($position eq 'top') {
+        my %servers = &Apache::lonnet::internet_dom_servers($dom);
+        foreach my $server (sort(keys(%servers))) {
+            $itemcount ++; 
+            $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
+            $datatable .= '<tr'.$css_class.'>'.
+                          '<td>'.&mt('Hostname').': '.
+                                &Apache::lonnet::hostname($server).'</td>'.
+                          '<td>';
+            if ($othercontrol{$server}) {
+                my $current;
+                if (ref($aliases{$othercontrol{$server}}) eq 'HASH') {
+                    $current = $aliases{$othercontrol{$server}{$server}};
+                }
+                if ($current) {
+                    $datatable .= $current;
+                } else {
+                    $datatable .= &mt('None in effect');
+                }
+                $datatable .= '<br /><span class="LC_small">('.
+                              &mt('WAF/Reverse Proxy controlled by domain: [_1]',
+                                  '<b>'.$othercontrol{$server}.'</b>').'</span>';
+            } else {
+                my $current;
+                if (ref($aliases{$dom}) eq 'HASH') {
+                    if ($aliases{$dom}{$server}) {
+                        $current = $aliases{$dom}{$server};
+                    }
+                }
+                $datatable .= '<input type="text" name="wafproxy_alias_'.$server.'" '.
+                              'value="'.$current.'" size="20" />';
+            }
+            $datatable .= '</td></tr>';
+        }
+    } else {
+        if ($setdom) {
+            $itemcount ++;
+            $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
+            $datatable .= '<tr'.$css_class.'>'.
+                          '<td>'.&mt('Domain: [_1]','<b>'.$dom.'</b>').'<br /><br />'.
+                          &mt('Format for comma separated IP blocks').':<br />'.
+                          &mt('A.B.C.D/N or A.B.C.D - E.F.G.H').'</td>'.
+                          '<td class="LC_left_item"><table>';
+            foreach my $item ('ipheader','trusted','exempt') {
+                $datatable .= '<tr>'.
+                              '<td>'.$lt{$item}.': '.
+                              '<input type="text" value="'.$values{$dom}{$item}.'" '.
+                              'name="wafproxy_'.$item.'" /></td></tr>';
+            }
+            $datatable .= '</table></td></tr>';
+        }
+        if (keys(%otherdoms)) {
+            foreach my $domain (sort(keys(%otherdoms))) {
+                $itemcount ++;
+                $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
+                $datatable .= '<tr'.$css_class.'>'.
+                              '<td>'.&mt('Domain: [_1]',$domain).
+                              '<table>';
+                foreach my $item ('ipheader','trusted','exempt') {
+                    my $showval = &mt('None');
+                    if ($values{$domain}{$item}) {
+                        $showval = $values{$domain}{$item}; 
+                    }
+                    $datatable .= '<tr>'.
+                                  '<td>'.$lt{$item}.': '.$showval.'</td></tr>';
+                }
+                $datatable .= '</table></td></tr>'; 
+            }
+        }
+    }
+    $$rowtotal += $itemcount;
+    return $datatable;
+}
+
+sub wafproxy_titles {
+    return &Apache::lonlocal::texthash(
+               exempt => 'Exempt IP range(s)',
+               trusted => 'Trusted IP range(s)',
+               ipheader => 'Custom request header',
+           );
+}
+
 sub print_usersessions {
     my ($position,$dom,$settings,$rowtotal) = @_;
     my ($css_class,$datatable,$itemcount,%checked,%choices);
@@ -19426,6 +19568,215 @@
     return $resulttext;
 }
 
+sub modify_wafproxy {
+    my ($dom,$action,$lastactref,%domconfig) = @_;
+    my %servers = &Apache::lonnet::internet_dom_servers($dom);
+    my (%othercontrol,%canset,%values,%curralias,%currvalue, at warnings,%wafproxy,
+        %changes,%expirecache);
+    foreach my $server (sort(keys(%servers))) {
+        my $serverhome = &Apache::lonnet::get_server_homeID($servers{$server});
+        if ($serverhome eq $server) {
+            my $serverdom = &Apache::lonnet::host_domain($server);
+            if ($serverdom eq $dom) {
+                $canset{$server} = 1;
+                if (ref($domconfig{'wafproxy'}) eq 'HASH') {
+                    %{$values{$dom}} = ();
+                    if (ref($domconfig{'wafproxy'}{'alias'}) eq 'HASH') {
+                        %curralias = %{$domconfig{'wafproxy'}{'alias'}};
+                    }
+                    foreach my $item ('ipheader','trusted','exempt') {
+                        $currvalue{$item} = $domconfig{'wafproxy'}{$item};
+                    }
+                }
+            }
+        }
+    }
+    my $output;
+    if (keys(%canset)) {
+        %{$wafproxy{'alias'}} = ();
+        foreach my $key (sort(keys(%canset))) {
+            $wafproxy{'alias'}{$key} = $env{'form.wafproxy_alias_'.$key};
+            $wafproxy{'alias'}{$key} =~ s/^\s+|\s+$//g;
+            if ($wafproxy{'alias'}{$key} ne $curralias{$key}) {
+                $changes{'alias'} = 1;
+            }
+            if ($wafproxy{'alias'}{$key} eq '') {
+                if ($curralias{$key}) {
+                    $expirecache{$key} = 1;
+                }
+                delete($wafproxy{'alias'}{$key});
+            }
+        }
+        unless (keys(%{$wafproxy{'alias'}})) {
+            delete($wafproxy{'alias'});
+        }
+        # Localization for values in %warn occus in &mt() calls separately.
+        my %warn = (
+                     trusted => 'trusted IP range(s)',
+                     exempt => 'exempt IP range(s)', 
+                   );
+        foreach my $item ('ipheader','trusted','exempt') {
+            my $possible = $env{'form.wafproxy_'.$item};
+            $possible =~ s/^\s+|\s+$//g;
+            if ($possible ne '') {
+                if ($item eq 'ipheader') {
+                    $wafproxy{$item} = $possible;
+                } else {
+                    my (@ok,$count);
+                    $possible =~ s/[\r\n]+/\s/g;
+                    $possible =~ s/\s*-\s*/-/g;
+                    $possible =~ s/\s+/,/g;
+                    $count = 0;
+                    if ($possible) {
+                        foreach my $poss (split(/\,/,$possible)) {
+                            $count ++;
+                            if (&validate_ip_pattern($poss)) {
+                                push(@ok,$poss);
+                            }
+                        }
+                        if (@ok) {
+                            $wafproxy{$item} = join(',', at ok);
+                        }
+                        my $diff = $count - scalar(@ok);
+                        if ($diff) {
+                            push(@warnings,'<li>'.
+                                 &mt('[quant,_1,IP] invalid and excluded from saved value for [_2]',
+                                     $diff,$warn{$item}).
+                                 '</li>');
+                        }
+                        if ($wafproxy{$item} ne $currvalue{$item}) {
+                            $changes{$item} = 1; 
+                        }
+                    }
+                }
+            } else {
+                if ($currvalue{$item}) {
+                    $changes{$item} = 1;
+                }
+            }
+        }
+    }
+    if (keys(%changes)) {
+        my %defaultshash = (
+                              wafproxy => \%wafproxy,
+                           ); 
+        my $putresult = &Apache::lonnet::put_dom('configuration',\%defaultshash,
+                                                 $dom);
+        if ($putresult eq 'ok') {
+            my $cachetime = 24*60*60;
+            my (%domdefaults,$updatedomdefs);
+            foreach my $item ('ipheader','trusted','exempt') {
+                if ($changes{$item}) {
+                    unless ($updatedomdefs) {
+                        %domdefaults = &Apache::lonnet::get_domain_defaults($dom);
+                        $updatedomdefs = 1;
+                    }
+                    if ($wafproxy{$item}) {
+                        $domdefaults{'waf_'.$item} = $wafproxy{$item};
+                    } elsif (exists($domdefaults{'waf_'.$item})) {
+                        delete($domdefaults{'waf_'.$item});
+                    } 
+                }
+            }
+            if ($updatedomdefs) {
+                &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);
+                if (ref($lastactref) eq 'HASH') {
+                    $lastactref->{'domdefaults'} = 1;
+                }
+            }
+            if ((exists($wafproxy{'alias'})) || (keys(%expirecache))) {
+                my %updates = %expirecache;
+                foreach my $key (keys(%expirecache)) {
+                    &Apache::lonnet::devalidate_cache_new('proxyalias',$key);
+                }
+                if (ref($wafproxy{'alias'}) eq 'HASH') {
+                    my $cachetime = 24*60*60;
+                    foreach my $key (keys(%{$wafproxy{'alias'}})) {
+                        $updates{$key} = 1;
+                        &Apache::lonnet::do_cache_new('proxyalias',$key,$wafproxy{'alias'}{$key},
+                                                      $cachetime);
+                    }
+                }
+                if (ref($lastactref) eq 'HASH') {
+                    $lastactref->{'proxyalias'} = \%updates;
+                }
+            }
+            $output = &mt('Changes were made to Web Application Firewall/Reverse Proxy').'<ul>';
+            foreach my $item ('alias','ipheader','trusted','exempt') {
+                if ($changes{$item}) {
+                    if ($item eq 'alias') {
+                        my $numaliased = 0;
+                        if (ref($wafproxy{'alias'}) eq 'HASH') {
+                            my $shown;
+                            if (keys(%{$wafproxy{'alias'}})) {
+                                foreach my $server (sort(keys(%{$wafproxy{'alias'}}))) {
+                                    $shown .= '<li>'.&mt('[_1] aliased by [_2]',
+                                                         &Apache::lonnet::hostname($server),
+                                                         $wafproxy{'alias'}{$server}).'</li>';
+                                    $numaliased ++;
+                                }
+                                if ($numaliased) {
+                                    $output .= '<li>'.&mt('Aliases for hostnames set to: [_1]',
+                                                          '<ul>'.$shown.'</ul>').'</li>';
+                                }
+                            }
+                        }
+                        unless ($numaliased) {
+                            $output .= '<li>'.&mt('Aliases deleted for hostnames').'</li>';
+                        }
+                    } else {
+                        if ($item eq 'ipheader') {
+                            if ($wafproxy{$item}) {
+                                $output .= '<li>'.&mt('Custom request header set to [_1]',
+                                                      $wafproxy{$item}).'</li>';
+                            } else {
+                                $output .= '<li>'.&mt('Custom request header deleted').'</li>';
+                            }
+                        } elsif ($item eq 'trusted') {
+                            if ($wafproxy{$item}) {
+                                $output .= '<li>'.&mt('Trusted IP range(s) set to [_1]',
+                                                      $wafproxy{$item}).'</li>';
+                            } else {
+                                $output .= '<li>'.&mt('Trusted IP range(s) deleted').'</li>';
+                            }
+                        } elsif ($item eq 'exempt') {
+                            if ($wafproxy{$item}) {
+                                $output .= '<li>'.&mt('Exempt IP range(s) set to [_1]',
+                                                       $wafproxy{$item}).'</li>';
+                            } else {
+                                $output .= '<li>'.&mt('Exempt IP range(s) deleted').'</li>';
+                            }
+                        }
+                    }
+                }
+            }
+        } else {
+            $output = '<span class="LC_error">'.
+                      &mt('An error occurred: [_1]',$putresult).'</span>';
+        }
+    } elsif (keys(%canset)) {
+        $output = &mt('No changes made to Web Application Firewall/Reverse Proxy settings');
+    }
+    if (@warnings) {
+        $output .= '<br />'.&mt('Warnings:').'<ul>'.
+                       join("\n", at warnings).'</ul>';
+    }
+    return $output;
+}
+
+sub validate_ip_pattern {
+    my ($pattern) = @_;
+    if ($pattern =~ /^([^-]+)\-([^-]+)$/) {
+        my ($start,$end) = ($1,$2);
+        if ((&Net::CIDR::cidrvalidate($start)) && (&Net::CIDR::cidrvalidate($end))) {
+            return 1;
+        }
+    } elsif (&Net::CIDR::cidrvalidate($pattern)) {
+        return 1;
+    }
+    return
+}
+
 sub modify_usersessions {
     my ($dom,$lastactref,%domconfig) = @_;
     my @hostingtypes = ('version','excludedomain','includedomain');
@@ -21140,14 +21491,22 @@
     my %thismachine;
     map { $thismachine{$_} = 1; } &Apache::lonnet::current_machine_ids();
     my @posscached = ('domainconfig','domdefaults','ltitools','usersessions',
-                      'directorysrch','passwdconf','cats');
+                      'directorysrch','passwdconf','cats','proxyalias');
     if (keys(%servers)) {
         foreach my $server (keys(%servers)) {
             next if ($thismachine{$server});
             my @cached;
             foreach my $name (@posscached) {
                 if ($cachekeys->{$name}) {
-                    push(@cached,&escape($name).':'.&escape($dom));
+                    if ($name eq 'proxyalias') {
+                        if (ref($cachekeys->{$name}) eq 'HASH') {  
+                            foreach my $key (keys(%{$cachekeys->{$name}})) {
+                                push(@cached,&escape($name).':'.&escape($key));
+                            }
+                        }
+                    } else {
+                        push(@cached,&escape($name).':'.&escape($dom));
+                    }
                 }
             }
             if (@cached) {
Index: loncom/interface/lonaboutme.pm
diff -u loncom/interface/lonaboutme.pm:1.158 loncom/interface/lonaboutme.pm:1.159
--- loncom/interface/lonaboutme.pm:1.158	Mon Dec  1 22:52:48 2014
+++ loncom/interface/lonaboutme.pm	Fri Dec 18 15:23:02 2020
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # Personal Information Page
 #
-# $Id: lonaboutme.pm,v 1.158 2014/12/01 22:52:48 raeburn Exp $
+# $Id: lonaboutme.pm,v 1.159 2020/12/18 15:23:02 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -671,7 +671,7 @@
 sub build_hierarchy {
     my ($r,$cdom,$cnum,$portaccess,$is_course,$filecounts,$mode,$access_info,
         $allfileshash,$group) = @_;
-    my $clientip = $r->get_remote_host();
+    my $clientip = &Apache::lonnet::get_requestor_ip($r);
     foreach my $filename (sort(keys(%{$access_info}))) {
         my $access_status =
            &Apache::lonnet::get_portfolio_access($cdom,$cnum,$filename,$group,$clientip,
Index: loncom/interface/loncommon.pm
diff -u loncom/interface/loncommon.pm:1.1349 loncom/interface/loncommon.pm:1.1350
--- loncom/interface/loncommon.pm:1.1349	Tue Nov 10 17:19:17 2020
+++ loncom/interface/loncommon.pm	Fri Dec 18 15:23:02 2020
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # a pile of common routines
 #
-# $Id: loncommon.pm,v 1.1349 2020/11/10 17:19:17 raeburn Exp $
+# $Id: loncommon.pm,v 1.1350 2020/12/18 15:23:02 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -5590,7 +5590,8 @@
         ($ENV{'REMOTE_ADDR'} eq &Apache::lonnet::get_host_ip($Apache::lonnet::perlvar{'lonHostID'}))) {
         $ip = $env{'request.host'} || $ENV{'REMOTE_ADDR'} || $clientip;
     } else {
-        $ip = $ENV{'REMOTE_ADDR'} || $env{'request.host'} || $clientip;
+        my $remote_ip = &Apache::lonnet::get_requestor_ip();
+        $ip = $remote_ip || $env{'request.host'} || $clientip;
     }
 
     my $name;
@@ -16801,6 +16802,7 @@
 # --------------------------------------------------------- Write first profile
 
     {
+        my $ip = &Apache::lonnet::get_requestor_ip($r);
 	my %initial_env = 
 	    ("user.name"          => $username,
 	     "user.domain"        => $domain,
@@ -16819,7 +16821,7 @@
 	     "request.course.sec" => '',
 	     "request.role"       => 'cm',
 	     "request.role.adv"   => $env{'user.adv'},
-	     "request.host"       => $ENV{'REMOTE_ADDR'},);
+	     "request.host"       => $ip,);
 
         if ($form->{'localpath'}) {
 	    $initial_env{"browser.localpath"}  = $form->{'localpath'};
@@ -18158,11 +18160,12 @@
 sub check_recaptcha {
     my ($privkey,$version) = @_;
     my $captcha_chk;
+    my $ip = &Apache::lonnet::get_requestor_ip();
     if ($version >= 2) {
         my %info = (
                      secret   => $privkey, 
                      response => $env{'form.g-recaptcha-response'},
-                     remoteip => $ENV{'REMOTE_ADDR'},
+                     remoteip => $ip,
                    );
         my $request=new HTTP::Request('POST','https://www.google.com/recaptcha/api/siteverify');
         $request->content(join('&',map {
@@ -18185,7 +18188,7 @@
         my $captcha_result =
             $captcha->check_answer(
                                     $privkey,
-                                    $ENV{'REMOTE_ADDR'},
+                                    $ip,
                                     $env{'form.recaptcha_challenge_field'},
                                     $env{'form.recaptcha_response_field'},
                                   );
Index: loncom/interface/lonfeedback.pm
diff -u loncom/interface/lonfeedback.pm:1.383 loncom/interface/lonfeedback.pm:1.384
--- loncom/interface/lonfeedback.pm:1.383	Mon Aug 12 16:45:48 2019
+++ loncom/interface/lonfeedback.pm	Fri Dec 18 15:23:02 2020
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # Feedback
 #
-# $Id: lonfeedback.pm,v 1.383 2019/08/12 16:45:48 raeburn Exp $
+# $Id: lonfeedback.pm,v 1.384 2020/12/18 15:23:02 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -3183,7 +3183,7 @@
     if (($symb) && ($email)) {
         my $now = time;
         if ($env{'form.editdisc'}) {
-            $contrib{'ip'}=$ENV{'REMOTE_ADDR'};
+            $contrib{'ip'}=&Apache::lonnet::get_requestor_ip();
             $contrib{'host'}=$Apache::lonnet::perlvar{'lonHostID'};
             $contrib{'timestamp'} = $now;
             $contrib{'history'} = '';
Index: loncom/interface/lonmsg.pm
diff -u loncom/interface/lonmsg.pm:1.245 loncom/interface/lonmsg.pm:1.246
--- loncom/interface/lonmsg.pm:1.245	Tue Jun  9 21:32:32 2020
+++ loncom/interface/lonmsg.pm	Fri Dec 18 15:23:02 2020
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # Routines for messaging
 #
-# $Id: lonmsg.pm,v 1.245 2020/06/09 21:32:32 raeburn Exp $
+# $Id: lonmsg.pm,v 1.246 2020/12/18 15:23:02 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -231,6 +231,7 @@
     $attachmenturl =&HTML::Entities::encode($attachmenturl,'<>&"');
     my $course_context = &get_course_context();
     my $now=time;
+    my $ip = &Apache::lonnet::get_requestor_ip();
     my $msgcount = &get_uniq();
     unless(defined($msgid)) {
         $msgid = &buildmsgid($now,$subject,$env{'user.name'},$env{'user.domain'},
@@ -250,7 +251,7 @@
     }
     $result .= '<servername>'.$ENV{'SERVER_NAME'}.'</servername>'.
            '<host>'.$ENV{'HTTP_HOST'}.'</host>'.
-	   '<client>'.$ENV{'REMOTE_ADDR'}.'</client>'.
+	   '<client>'.$ip.'</client>'.
 	   '<browsertype>'.$env{'browser.type'}.'</browsertype>'.
 	   '<browseros>'.$env{'browser.os'}.'</browseros>'.
 	   '<browserversion>'.$env{'browser.version'}.'</browserversion>'.
Index: loncom/interface/lonsupportreq.pm
diff -u loncom/interface/lonsupportreq.pm:1.100 loncom/interface/lonsupportreq.pm:1.101
--- loncom/interface/lonsupportreq.pm:1.100	Tue Jun  9 21:32:32 2020
+++ loncom/interface/lonsupportreq.pm	Fri Dec 18 15:23:02 2020
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # Helpdesk request form
 #
-# $Id: lonsupportreq.pm,v 1.100 2020/06/09 21:32:32 raeburn Exp $
+# $Id: lonsupportreq.pm,v 1.101 2020/12/18 15:23:02 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -663,7 +663,8 @@
             return;
         }
     }
-    my @ENVvars = ('HTTP_HOST','HTTP_USER_AGENT','REMOTE_ADDR','SERVER_ADDR','SERVER_NAME');
+    my $ip = &Apache::lonnet::get_requestor_ip();
+    my @ENVvars = ('HTTP_HOST','HTTP_USER_AGENT','SERVER_ADDR','SERVER_NAME');
     my @envvars = ('browser.os','browser.type','browser.version','user.home','request.role');
     my @loncvars = ('user.name','user.domain','request.course.sec','request.course.id');
     my @cookievars;
@@ -1072,6 +1073,7 @@
         foreach my $var(@ENVvars) {
             $supportmsg .= "$var: $ENV{$var}\n";
         }
+        $supportmsg .= "REMOTE_ADDR: $ip\n";
         foreach my $var (@envvars) {
             $supportmsg .= "$var: $env{$var}\n";
         }
@@ -1095,6 +1097,7 @@
         foreach my $var (@ENVvars) {
             $attachment_text .= "$var: $ENV{$var}\n";
         }
+        $attachment_text .= "REMOTE_ADDR: $ip\n";
         foreach my $var (@envvars) {
             $attachment_text .= "$var: $env{$var}\n";
         }
@@ -1142,6 +1145,9 @@
                        $var.'</span>: '.$ENV{$var}.', ';
         }
     }
+    if ($ip ne '') {
+        $envmsg .= '<span class="LC_helpform_receipt_cat">'.
+    }              'REMOTE_ADDR</span>: '.$ip.', ';
     foreach my $var (@envvars) {
         if ($env{$var} ne '') { 
             $envmsg .= '<span class="LC_helpform_receipt_cat">'.
Index: loncom/interface/resetpw.pm
diff -u loncom/interface/resetpw.pm:1.47 loncom/interface/resetpw.pm:1.48
--- loncom/interface/resetpw.pm:1.47	Sun Feb  9 04:43:20 2020
+++ loncom/interface/resetpw.pm	Fri Dec 18 15:23:02 2020
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # Allow access to password changing via a token sent to user's e-mail. 
 #
-# $Id: resetpw.pm,v 1.47 2020/02/09 04:43:20 raeburn Exp $
+# $Id: resetpw.pm,v 1.48 2020/12/18 15:23:02 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -482,7 +482,8 @@
 
     my $now = time;
     my $temppasswd = &create_passwd();
-    my %info = ('ip'         => $ENV{'REMOTE_ADDR'},
+    my $ip = &Apache::lonnet::get_requestor_ip(); 
+    my %info = ('ip'         => $ip,
 		'time'       => $now,
 		'domain'     => $udom,
 		'username'   => $uname,
@@ -723,7 +724,8 @@
                     my $now = &Apache::lonlocal::locallocaltime(time);
                     my $domdesc = 
 			&Apache::lonnet::domain($data{'domain'},'description');
-                    my $mailmsg = &mt('The password for your LON-CAPA account in the [_1] domain was changed [_2] from IP address: [_3].  If you did not perform this change or authorize it, please contact the [_4] ([_5]).',$domdesc,$now,$ENV{'REMOTE_ADDR'},$contact_name,$contact_email)."\n";
+                    my $ip = &Apache::lonnet::get_requestor_ip();
+                    my $mailmsg = &mt('The password for your LON-CAPA account in the [_1] domain was changed [_2] from IP address: [_3].  If you did not perform this change or authorize it, please contact the [_4] ([_5]).',$domdesc,$now,$ip,$contact_name,$contact_email)."\n";
                     my $result = &send_mail($domdesc,$data{'email'},$mailmsg,
                                             $contact_name,$contact_email);
                     my $confirm_msg;
Index: loncom/auth/lonacc.pm
diff -u loncom/auth/lonacc.pm:1.183 loncom/auth/lonacc.pm:1.184
--- loncom/auth/lonacc.pm:1.183	Tue Oct 20 01:38:12 2020
+++ loncom/auth/lonacc.pm	Fri Dec 18 15:23:03 2020
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # Cookie Based Access Handler
 #
-# $Id: lonacc.pm,v 1.183 2020/10/20 01:38:12 raeburn Exp $
+# $Id: lonacc.pm,v 1.184 2020/12/18 15:23:03 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -386,7 +386,7 @@
 	} else {
 	    # need to login them in, so generate the need data that
 	    # migrate expects to do login
-	    my $ip = $r->get_remote_host();
+	    my $ip = &Apache::lonnet::get_requestor_ip($r);
 	    my %info=('ip'        => $ip,
 		      'domain'    => $domain,
 		      'username'  => $user,
@@ -718,7 +718,7 @@
                         }
                     }
                 } elsif (($handle =~ /^publicuser_\d+$/) && (&Apache::lonnet::is_portfolio_url($requrl))) {
-                    my $clientip = $r->get_remote_host();
+                    my $clientip = &Apache::lonnet::get_requestor_ip($r); 
                     if (&Apache::lonnet::allowed('bre',$requrl,undef,undef,$clientip) ne 'F') {
                         $env{'user.error.msg'}="$requrl:bre:1:1:Access Denied";
                         return HTTP_NOT_ACCEPTABLE;
@@ -908,7 +908,7 @@
     }
 # ------------------------------------ See if this is a viewable portfolio file
     if (&Apache::lonnet::is_portfolio_url($requrl)) {
-        my $clientip = $r->get_remote_host();
+        my $clientip = &Apache::lonnet::get_requestor_ip($r);
         my $access=&Apache::lonnet::allowed('bre',$requrl,undef,undef,$clientip);
 	if ($access eq 'A') {
 	    &Apache::restrictedaccess::setup_handler($r);
Index: loncom/auth/lonauth.pm
diff -u loncom/auth/lonauth.pm:1.161 loncom/auth/lonauth.pm:1.162
--- loncom/auth/lonauth.pm:1.161	Tue Oct 20 01:38:12 2020
+++ loncom/auth/lonauth.pm	Fri Dec 18 15:23:03 2020
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # User Authentication Module
 #
-# $Id: lonauth.pm,v 1.161 2020/10/20 01:38:12 raeburn Exp $
+# $Id: lonauth.pm,v 1.162 2020/12/18 15:23:03 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -60,8 +60,9 @@
 
 # -------------------------------------------------------------------- Log this
 
+    my $ip = &Apache::lonnet::get_requestor_ip();
     &Apache::lonnet::log($domain,$username,$authhost,
-                         "Login $ENV{'REMOTE_ADDR'}");
+                         "Login $ip");
 
 # ------------------------------------------------- Check for critical messages
 
Index: loncom/auth/lonlogin.pm
diff -u loncom/auth/lonlogin.pm:1.181 loncom/auth/lonlogin.pm:1.182
--- loncom/auth/lonlogin.pm:1.181	Mon Oct 26 01:52:15 2020
+++ loncom/auth/lonlogin.pm	Fri Dec 18 15:23:03 2020
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # Login Screen
 #
-# $Id: lonlogin.pm,v 1.181 2020/10/26 01:52:15 raeburn Exp $
+# $Id: lonlogin.pm,v 1.182 2020/12/18 15:23:03 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -605,7 +605,7 @@
         my $omitextra;
         if ($headextra_exempt ne '') {
             my @exempt = split(',',$headextra_exempt);
-            my $ip = $ENV{'REMOTE_ADDR'};
+            my $ip = &Apache::lonnet::get_requestor_ip();
             if (grep(/^\Q$ip\E$/, at exempt)) {
                 $omitextra = 1;
             }
@@ -848,7 +848,7 @@
     my $output;
     if ($loginvia ne '') {
         my $noredirect;
-        my $ip = $ENV{'REMOTE_ADDR'};
+        my $ip = &Apache::lonnet::get_requestor_ip();   
         if ($ip eq '127.0.0.1') {
             $noredirect = 1;
         } else {
Index: loncom/auth/lonlogout.pm
diff -u loncom/auth/lonlogout.pm:1.56 loncom/auth/lonlogout.pm:1.57
--- loncom/auth/lonlogout.pm:1.56	Sat Nov 24 16:19:04 2018
+++ loncom/auth/lonlogout.pm	Fri Dec 18 15:23:03 2020
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # Logout Handler
 #
-# $Id: lonlogout.pm,v 1.56 2018/11/24 16:19:04 raeburn Exp $
+# $Id: lonlogout.pm,v 1.57 2020/12/18 15:23:03 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -82,11 +82,12 @@
         &Apache::lonlocal::get_language_handle($r);
     }
     my %temp=('logout' => time);
+    my $ip = &Apache::lonnet::get_requestor_ip();
     &Apache::lonnet::put('email_status',\%temp);
     &Apache::lonnet::log($env{'user.domain'},
 			 $env{'user.name'},
 			 $env{'user.home'},
-			 "Logout $ENV{'REMOTE_ADDR'}");
+			 "Logout $ip");
 
     &Apache::loncommon::content_type($r,'text/html');
 
Index: loncom/auth/lonracc.pm
diff -u loncom/auth/lonracc.pm:1.23 loncom/auth/lonracc.pm:1.24
--- loncom/auth/lonracc.pm:1.23	Wed Nov 12 20:01:09 2008
+++ loncom/auth/lonracc.pm	Fri Dec 18 15:23:03 2020
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # Access Handler for File Transfers
 #
-# $Id: lonracc.pm,v 1.23 2008/11/12 20:01:09 jms Exp $
+# $Id: lonracc.pm,v 1.24 2020/12/18 15:23:03 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -111,7 +111,7 @@
 	return NOT_FOUND;
     }
 
-    my $reqhost = $r->get_remote_host(REMOTE_NOLOOKUP);
+    my $reqhost = &Apache::lonnet::get_requestor_ip($r,REMOTE_NOLOOKUP,1);
     my @hostids= &Apache::lonnet::get_hosts_from_ip($reqhost);
     if (!@hostids && $reqhost ne '127.0.0.1' ) {
 	$r->log_reason("Unable to find a host for ".
Index: loncom/auth/lonroles.pm
diff -u loncom/auth/lonroles.pm:1.343 loncom/auth/lonroles.pm:1.344
--- loncom/auth/lonroles.pm:1.343	Tue Feb  4 01:27:04 2020
+++ loncom/auth/lonroles.pm	Fri Dec 18 15:23:03 2020
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # User Roles Screen
 #
-# $Id: lonroles.pm,v 1.343 2020/02/04 01:27:04 raeburn Exp $
+# $Id: lonroles.pm,v 1.344 2020/12/18 15:23:03 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -505,6 +505,7 @@
 				 my $end_page=&Apache::loncommon::end_page();
 				 my $buttontext=&mt('Enter Course');
 				 my $message=&mt('Successfully registered key');
+                                 my $ip = &Apache::lonnet::get_requestor_ip();
 				 my $assignresult=
 				     &Apache::lonnet::assign_access_key(
 						     $env{'form.newkey'},
@@ -513,7 +514,7 @@
                                                      $env{'user.domain'},
 						     $env{'user.name'},
                                                      &mt('Assigned from [_1] at [_2] for [_3]'
-                                                        ,$ENV{'REMOTE_ADDR'}
+                                                        ,$ip
                                                         ,&Apache::lonlocal::locallocaltime()
                                                         ,$trolecode)
                                                      );
Index: loncom/auth/lonstatusacc.pm
diff -u loncom/auth/lonstatusacc.pm:1.7 loncom/auth/lonstatusacc.pm:1.8
--- loncom/auth/lonstatusacc.pm:1.7	Sat Jun 13 20:28:56 2009
+++ loncom/auth/lonstatusacc.pm	Fri Dec 18 15:23:03 2020
@@ -1,7 +1,7 @@
 #
 # LON-CAPA authorization for pages generated by server-status reports 
 #
-# $Id: lonstatusacc.pm,v 1.7 2009/06/13 20:28:56 raeburn Exp $
+# $Id: lonstatusacc.pm,v 1.8 2020/12/18 15:23:03 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -38,7 +38,7 @@
 
 sub handler {
     my $r = shift;
-    my $reqhost = $r->get_remote_host(REMOTE_NOLOOKUP);
+    my $reqhost = &Apache::lonnet::get_requestor_ip($r,REMOTE_NOLOOKUP);
     my $page = 'server-status';
     if (($r->uri eq '/adm/domainstatus') ||
         ($r->uri eq '/adm/test')) {
Index: loncom/auth/lontokacc.pm
diff -u loncom/auth/lontokacc.pm:1.19 loncom/auth/lontokacc.pm:1.20
--- loncom/auth/lontokacc.pm:1.19	Wed May 16 09:45:58 2007
+++ loncom/auth/lontokacc.pm	Fri Dec 18 15:23:03 2020
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # Access Handler for User File Transfers
 #
-# $Id: lontokacc.pm,v 1.19 2007/05/16 09:45:58 albertel Exp $
+# $Id: lontokacc.pm,v 1.20 2020/12/18 15:23:03 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -36,7 +36,7 @@
 
 sub handler {
     my $r = shift;
-    my $reqhost = $r->get_remote_host(REMOTE_NOLOOKUP);
+    my $reqhost = &Apache::lonnet::get_requestor_ip($r,REMOTE_NOLOOKUP,1);
     my @hostids= &Apache::lonnet::get_hosts_from_ip($reqhost);
     if (!@hostids && $reqhost ne '127.0.0.1' ) {
 	$r->log_reason("Unable to find a host for ".
Index: loncom/auth/lonwebdavacc.pm
diff -u loncom/auth/lonwebdavacc.pm:1.6 loncom/auth/lonwebdavacc.pm:1.7
--- loncom/auth/lonwebdavacc.pm:1.6	Fri Sep 15 12:53:34 2017
+++ loncom/auth/lonwebdavacc.pm	Fri Dec 18 15:23:03 2020
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # Authorization Handler for webDAV access to Authoring Space. 
 #
-# $Id: lonwebdavacc.pm,v 1.6 2017/09/15 12:53:34 raeburn Exp $
+# $Id: lonwebdavacc.pm,v 1.7 2020/12/18 15:23:03 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -234,8 +234,9 @@
         if (&Apache::lonnet::usertools_access($uname,$udom,'webdav')) {
             my ($webdav) =
                 ($r->uri =~ m{^(/webdav/$match_domain/$match_username/)});
+            my $ip = &Apache::lonnet::get_requestor_ip();
             &Apache::lonnet::log($udom,$uname,$uhome,
-                                 "SSO log-in to $webdav from $ENV{'REMOTE_ADDR'}");
+                                 "SSO log-in to $webdav from $ip");
             my $cookie = "lonDAV=$handle; path=/webdav/; secure; HttpOnly;";
             $r->header_out('Set-cookie' => $cookie);
             $r->send_http_header;
Index: loncom/auth/lonwebdavauth.pm
diff -u loncom/auth/lonwebdavauth.pm:1.7 loncom/auth/lonwebdavauth.pm:1.8
--- loncom/auth/lonwebdavauth.pm:1.7	Mon Jan 30 00:16:31 2017
+++ loncom/auth/lonwebdavauth.pm	Fri Dec 18 15:23:03 2020
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # Authentication Handler for webDAV access to Authoring Space.
 #
-# $Id: lonwebdavauth.pm,v 1.7 2017/01/30 00:16:31 raeburn Exp $
+# $Id: lonwebdavauth.pm,v 1.8 2020/12/18 15:23:03 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -298,7 +298,7 @@
                                                   \%userenv,\%domdef,\%is_adv);
             @env{keys(%disk_env)} = @disk_env{keys(%disk_env)};
             untie(%disk_env);
-            my $ip = $r->get_remote_host();
+            my $ip = &Apache::lonnet::get_requestor_ip($r);
             &Apache::lonnet::log($udom,$uname,$uhome,
                                  "Login webdav/$author $ip");
         }
Index: loncom/auth/migrateuser.pm
diff -u loncom/auth/migrateuser.pm:1.48 loncom/auth/migrateuser.pm:1.49
--- loncom/auth/migrateuser.pm:1.48	Thu Oct 22 19:23:22 2020
+++ loncom/auth/migrateuser.pm	Fri Dec 18 15:23:03 2020
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # Starts a user off based of an existing token.
 #
-# $Id: migrateuser.pm,v 1.48 2020/10/22 19:23:22 raeburn Exp $
+# $Id: migrateuser.pm,v 1.49 2020/12/18 15:23:03 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -319,10 +319,11 @@
     }
     my %temp=('logout' => time);
     &Apache::lonnet::put('email_status',\%temp);
+    my $ip = &Apache::lonnet::get_requestor_ip();
     &Apache::lonnet::log($env{'user.domain'},
                          $env{'user.name'},
                          $env{'user.home'},
-                         "Logout $ENV{'REMOTE_ADDR'}");
+                         "Logout $ip");
 
     &Apache::loncommon::content_type($r,'text/html');
 
@@ -345,7 +346,7 @@
     }
     my $lonhost = $r->dir_config('lonHostID');
     if (ref($data) eq 'HASH') {
-        %user_info=('ip'       => $ENV{'REMOTE_ADDR'},
+        %user_info=('ip'       => $ip,
                     'domain'   => $data->{'domain'},
                     'username' => $data->{'username'},
                     'home'     => $data->{'home'},
@@ -541,7 +542,7 @@
 }
 
 sub log_switch {
-    my ($r,$data,$lti_env) = @_;
+    my ($r,$data,$lti_env,$ip) = @_;
     my $lonhost = $r->dir_config('lonHostID');
     return unless ((ref($data) eq 'HASH') && (ref($lti_env) eq 'HASH'));
     my $now = time;
@@ -557,7 +558,7 @@
     } else {
         $logmsg .= " (no role)";
     }
-    $logmsg .= ' '.$ENV{'REMOTE_ADDR'};
+    $logmsg .= ' '.$ip;
     &Apache::lonnet::log($data->{'domain'},$data->{'username'},$data->{'home'},$logmsg);
 }
 
@@ -587,9 +588,10 @@
     }
     my ($home, at ids);
     @ids=&Apache::lonnet::current_machine_ids();
-    if ($data{'ip'} ne $ENV{'REMOTE_ADDR'}) {
+    my $ip = &Apache::lonnet::get_requestor_ip(); 
+    if ($data{'ip'} ne $ip) {
         &Apache::lonnet::logthis('IP change when session migration requested -- was: '.
-                 $data{'ip'}.'; now: '.$ENV{'REMOTE_ADDR'}.' for '.$data{'username'}.':'.$data{'domain'});
+                 $data{'ip'}.'; now: '.$ip.' for '.$data{'username'}.':'.$data{'domain'});
 	return &ip_changed($r,$data{'domain'},$data{'server'},\@ids,\%data);
     }
     if ($data{'loncfail'}) {
@@ -680,7 +682,7 @@
         my $switchfrom = $data{'server'};
         if (@conlosts) {
             if (grep(/^\Q$switchfrom\E$/, at conlosts)) {
-                &log_switch($r,\%data,$extra_env);
+                &log_switch($r,\%data,$extra_env,$ip);
             }
         }
     }
Index: loncom/auth/publiccheck.pm
diff -u loncom/auth/publiccheck.pm:1.26 loncom/auth/publiccheck.pm:1.27
--- loncom/auth/publiccheck.pm:1.26	Sat Feb 25 19:56:09 2017
+++ loncom/auth/publiccheck.pm	Fri Dec 18 15:23:03 2020
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # Cookie Based Access Handler
 #
-# $Id: publiccheck.pm,v 1.26 2017/02/25 19:56:09 raeburn Exp $
+# $Id: publiccheck.pm,v 1.27 2020/12/18 15:23:03 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -107,7 +107,7 @@
     my %access_controls = &Apache::lonnet::get_access_controls($current_perms,$group,$file_name);
     my $access = '';
     my $now = time;
-    my $clientip = $r->get_remote_host();
+    my $clientip = &Apache::lonnet::get_requestor_ip($r);
     foreach my $key (keys(%{$access_controls{$file_name}})) {
         my ($num,$scope,$end,$start) = ($key =~ /^([^:]+):([a-z]+)_(\d*)_?(\d*)$/);
         if ($start > $now) {
Index: loncom/auth/switchserver.pm
diff -u loncom/auth/switchserver.pm:1.51 loncom/auth/switchserver.pm:1.52
--- loncom/auth/switchserver.pm:1.51	Thu Oct 22 19:23:22 2020
+++ loncom/auth/switchserver.pm	Fri Dec 18 15:23:03 2020
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # Switch Servers Handler
 #
-# $Id: switchserver.pm,v 1.51 2020/10/22 19:23:22 raeburn Exp $
+# $Id: switchserver.pm,v 1.52 2020/12/18 15:23:03 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -211,7 +211,8 @@
     } else {
         $logmsg .= " (no role)";
     }
-    $logmsg .= ' '.$ENV{'REMOTE_ADDR'};
+    my $ip = &Apache::lonnet::get_requestor_ip();
+    $logmsg .= ' '.$ip;
     &Apache::lonnet::log($env{'user.domain'},$env{'user.name'},
 			 $env{'user.home'},$logmsg);
 
Index: loncom/lonnet/perl/lonnet.pm
diff -u loncom/lonnet/perl/lonnet.pm:1.1433 loncom/lonnet/perl/lonnet.pm:1.1434
--- loncom/lonnet/perl/lonnet.pm:1.1433	Tue Nov 24 16:36:35 2020
+++ loncom/lonnet/perl/lonnet.pm	Fri Dec 18 15:23:03 2020
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # TCP networking package
 #
-# $Id: lonnet.pm,v 1.1433 2020/11/24 16:36:35 raeburn Exp $
+# $Id: lonnet.pm,v 1.1434 2020/12/18 15:23:03 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -96,6 +96,7 @@
 use Digest::MD5;
 use Math::Random;
 use File::MMagic;
+use Net::CIDR;
 use LONCAPA qw(:DEFAULT :match);
 use LONCAPA::Configuration;
 use LONCAPA::lonmetadata;
@@ -128,12 +129,13 @@
 	$logid ++;
         my $now = time();
 	my $id=$now.'00000'.$$.'00000'.$logid;
+        my $ip = &get_requestor_ip();
         my $logentry = { 
                           $id => {
                                    'exe_uname' => $env{'user.name'},
                                    'exe_udom'  => $env{'user.domain'},
                                    'exe_time'  => $now,
-                                   'exe_ip'    => $ENV{'REMOTE_ADDR'},
+                                   'exe_ip'    => $ip,
                                    'delflag'   => $delflag,
                                    'logentry'  => $storehash,
                                    'uname'     => $uname,
@@ -2594,7 +2596,7 @@
                                   'coursedefaults','usersessions',
                                   'requestauthor','selfenrollment',
                                   'coursecategories','ssl','autoenroll',
-                                  'trust','helpsettings'],$domain);
+                                  'trust','helpsettings','wafproxy'],$domain);
     my @coursetypes = ('official','unofficial','community','textbook','placement');
     if (ref($domconfig{'defaults'}) eq 'HASH') {
         $domdefaults{'lang_def'} = $domconfig{'defaults'}{'lang_def'}; 
@@ -2754,6 +2756,13 @@
             $domdefaults{'adhocroles'} = $domconfig{'helpsettings'}{'adhoc'};
         }
     }
+    if (ref($domconfig{'wafproxy'}) eq 'HASH') {
+        foreach my $item ('ipheader','trusted','exempt') {
+            if ($domconfig{'wafproxy'}{$item}) {
+                $domdefaults{'waf_'.$item} = $domconfig{'wafproxy'}{$item};
+            }
+        }
+    } 
     &do_cache_new('domdefaults',$domain,\%domdefaults,$cachetime);
     return %domdefaults;
 }
@@ -6100,7 +6109,7 @@
   if (!$domain) { $domain=$env{'user.domain'}; }
   if (!$stuname) { $stuname=$env{'user.name'}; }
   if ($domain eq 'public' && $stuname eq 'public') {
-      $stuname=$ENV{'REMOTE_ADDR'};
+      $stuname=&get_requestor_ip();
   }
   my $path=LONCAPA::tempdir();
   my %hash;
@@ -6137,7 +6146,7 @@
   if (!$domain) { $domain=$env{'user.domain'}; }
   if (!$stuname) { $stuname=$env{'user.name'}; }
   if ($domain eq 'public' && $stuname eq 'public') {
-      $stuname=$ENV{'REMOTE_ADDR'};
+      $stuname=&get_requestor_ip();
   }
   my $now=time;
   my %hash;
@@ -6181,7 +6190,7 @@
   if (!$domain) { $domain=$env{'user.domain'}; }
   if (!$stuname) { $stuname=$env{'user.name'}; }
   if ($domain eq 'public' && $stuname eq 'public') {
-      $stuname=$ENV{'REMOTE_ADDR'};
+      $stuname=&get_requestor_ip();
   }
   my %returnhash;
   $namespace=~s/\//\_/g;
@@ -6237,7 +6246,7 @@
     }
     if (!$home) { $home=$env{'user.home'}; }
 
-    $$storehash{'ip'}=$ENV{'REMOTE_ADDR'};
+    $$storehash{'ip'}=&get_requestor_ip();
     $$storehash{'host'}=$perlvar{'lonHostID'};
 
     my $namevalue='';
@@ -6273,7 +6282,7 @@
     }
     if (!$home) { $home=$env{'user.home'}; }
 
-    $$storehash{'ip'}=$ENV{'REMOTE_ADDR'};
+    $$storehash{'ip'}=&get_requestor_ip();
     $$storehash{'host'}=$perlvar{'lonHostID'};
 
     my $namevalue='';
@@ -7268,7 +7277,8 @@
        foreach my $key (keys(%{$storehash})) {
            $namevalue.=&escape($key).'='.&freeze_escape($storehash->{$key}).'&';
        }
-       $namevalue .= 'ip='.&escape($ENV{'REMOTE_ADDR'}).
+       my $ip = &get_requestor_ip();
+       $namevalue .= 'ip='.&escape($ip).
                      '&host='.&escape($perlvar{'lonHostID'}).
                      '&version='.$esc_v.
                      '&by='.&escape($env{'user.name'}.':'.$env{'user.domain'});
@@ -10315,9 +10325,10 @@
              ' in domain '.$env{'request.role.domain'});  
     my $reply=&reply('encrypt:changeuserauth:'.$udom.':'.$uname.':'.$umode.':'.
 		     &escape($upass),$uhome);
+    my $ip = &get_requestor_ip();
     &log($env{'user.domain'},$env{'user.name'},$env{'user.home'},
         'Authentication changed for '.$udom.', '.$uname.', '.$umode.
-         '(Remote '.$ENV{'REMOTE_ADDR'}.'): '.$reply);
+         '(Remote '.$ip.'): '.$reply);
     &log($udom,,$uname,$uhome,
         'Authentication changed by '.$env{'user.domain'}.', '.
                                      $env{'user.name'}.', '.$umode.
@@ -10847,7 +10858,7 @@
             if (($uhome eq '') || ($uhome eq 'no_host')) {
                 $result = 'error: no_host';
             } else {
-                $storehash->{'ip'} = $ENV{'REMOTE_ADDR'};
+                $storehash->{'ip'} = &get_requestor_ip();
                 $storehash->{'host'} = $perlvar{'lonHostID'};
 
                 my $namevalue='';
@@ -14264,6 +14275,100 @@
     return;
 }
 
+sub get_requestor_ip {
+    my ($r,$nolookup,$noproxy) = @_;
+    my $from_ip;
+    if (ref($r)) {
+        $from_ip = $r->get_remote_host($nolookup);
+    } else {
+        $from_ip = $ENV{'REMOTE_ADDR'};
+    }
+    return $from_ip if ($noproxy); 
+    # Who controls proxy settings for server
+    my $dom_in_use = $Apache::lonnet::perlvar{'lonDefDomain'};
+    my $proxyinfo = &get_proxy_settings($dom_in_use);
+    if ((ref($proxyinfo) eq 'HASH') && ($from_ip)) {
+        if ($proxyinfo->{'exempt'}) {
+            if (&ip_match($from_ip,$proxyinfo->{'exempt'})) {
+                return $from_ip;
+            }
+        }
+        if ($proxyinfo->{'trusted'}) {
+            if (&ip_match($from_ip,$proxyinfo->{'trusted'})) {
+                my $ipheader = $proxyinfo->{'ipheader'};
+                my ($ip,$xfor);
+                if (ref($r)) {
+                    if ($ipheader) {
+                        $ip = $r->headers_in->{$ipheader};
+                    }
+                    $xfor = $r->headers_in->{'X-Forwarded-For'};
+                } else {
+                    if ($ipheader) {
+                        $ip = $ENV{'HTTP_'.uc($ipheader)};
+                    }
+                    $xfor = $ENV{'HTTP_X_FORWARDED_FOR'};
+                }
+                if (($ip eq '') && ($xfor ne '')) {
+                    my @ips = reverse(split(/\s*,\s*/,$xfor));
+                    foreach my $poss_ip (reverse(split(/\s*,\s*/,$xfor))) {
+                        unless (&ip_match($poss_ip,$proxyinfo->{'trusted'})) {
+                            $ip = $poss_ip;
+                        }
+                    }
+                }
+                if ($ip ne '') {
+                    return $ip;
+                }
+            }
+        }
+    }
+    return $from_ip;
+}
+
+sub get_proxy_settings {
+    my ($dom_in_use) = @_;
+    my %domdefaults = &Apache::lonnet::get_domain_defaults($dom_in_use);
+    my $proxyinfo = {
+                       ipheader => $domdefaults{'waf_ipheader'},
+                       trusted  => $domdefaults{'waf_trusted'},
+                       exempt   => $domdefaults{'waf_exempt'},
+                    };
+    return $proxyinfo;
+}
+
+sub ip_match {
+    my ($ip,$pattern_str) = @_;
+    $ip=Net::CIDR::cidrvalidate($ip);
+    if ($ip) {
+        return Net::CIDR::cidrlookup($ip,split(/\s*,\s*/,$pattern_str));
+    }
+    return;
+}
+
+sub get_proxy_alias {
+    my $lonhost = $perlvar{'lonHostID'};
+    if ($lonhost ne '') {
+        my ($alias,$cached) = &is_cached_new('proxyalias',$lonhost);
+        if ($cached) {
+            return $alias;
+        }
+        my $dom = &Apache::lonnet::host_domain($lonhost);
+        if ($dom ne '') {
+            my $cachetime = 60*60*24;
+            my %domconfig =
+                &Apache::lonnet::get_dom('configuration',['proxy'],$dom);
+            my $alias;
+            if (ref($domconfig{'proxy'}) eq 'HASH') {
+                if (ref($domconfig{'proxy'}{'alias'}) eq 'HASH') {
+                    $alias = $domconfig{'proxy'}{'alias'}{$lonhost};
+                }
+            }
+            return &do_cache_new('proxyalias',$lonhost,$alias,$cachetime);
+        }
+    }
+    return;
+}
+
 # ------------------------------------------------------------- Declutters URLs
 
 sub declutter {
Index: loncom/cgi/lonauthcgi.pm
diff -u loncom/cgi/lonauthcgi.pm:1.16 loncom/cgi/lonauthcgi.pm:1.17
--- loncom/cgi/lonauthcgi.pm:1.16	Sat Dec 22 21:04:56 2018
+++ loncom/cgi/lonauthcgi.pm	Fri Dec 18 15:23:04 2020
@@ -1,7 +1,7 @@
 #
 # LON-CAPA authorization for cgi-bin scripts
 #
-# $Id: lonauthcgi.pm,v 1.16 2018/12/22 21:04:56 raeburn Exp $
+# $Id: lonauthcgi.pm,v 1.17 2020/12/18 15:23:04 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -92,7 +92,7 @@
     my ($page,$ip) = @_;
     my $allowed;
     if (!defined($ip)) {
-        $ip = $ENV{'REMOTE_ADDR'};
+        $ip = &Apache::lonnet::get_requestor_ip();
     }
     if ($ip eq '127.0.0.1') {
         $allowed = 1;
Index: loncom/lontrans.pm
diff -u loncom/lontrans.pm:1.26 loncom/lontrans.pm:1.27
--- loncom/lontrans.pm:1.26	Sat Feb 29 16:05:21 2020
+++ loncom/lontrans.pm	Fri Dec 18 15:23:04 2020
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # URL translation for User Files
 #
-# $Id: lontrans.pm,v 1.26 2020/02/29 16:05:21 raeburn Exp $
+# $Id: lontrans.pm,v 1.27 2020/12/18 15:23:04 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -38,11 +38,11 @@
     my $r = shift;
     # FIXME line remove when mod_perl fixes BUG#4948
     $r->notes->set('error-notes' => '');
+    my $actualhost = $r->headers_in->get('Host');
     if ($r->uri=~m{^/raw/}) {
-        my $host = $r->headers_in->get('Host');
-        if ($host) {
+        if ($actualhost) {
             unless ($host =~ /^internal\-/) {
-                my $remote_ip = $r->get_remote_host();
+                my $remote_ip = &Apache::lonnet::get_requestor_ip($r,REMOTE_NOLOOKUP,1);
                 my $lonhost = $r->dir_config('lonHostID');
                 if (&redirect_raw($remote_ip,$lonhost)) {
                     my $location = 'https://internal-'.$host.$r->uri;
@@ -52,6 +52,36 @@
             }
         }
     }
+    my $alias = &Apache::lonnet::get_proxy_alias();
+    if ($alias) {
+        my $lonhost = $r->dir_config('lonHostID');
+        my $expected_host = &Apache::lonnet::hostname($lonhost);
+        if (($actualhost eq $expected_host) && ($actualhost ne $alias)) {
+            my $remote_ip = &Apache::lonnet::get_requestor_ip($r,REMOTE_NOLOOKUP,1);
+            unless ($remote_ip eq '127.0.0.1') {
+                my $hostip = &Apache::lonnet::get_host_ip($lonhost);
+                unless ($remote_ip eq $hostip) {
+                    my $do_redirect = 1;
+                    if ($r->uri=~m{^/raw/}){
+                        my %iphost = &Apache::lonnet::get_iphost();
+                        if (exists($iphost{$remote_ip})) {
+                            undef($do_redirect);
+                        }
+                    }
+                    if ($do_redirect) {
+                        my $uri = $r->uri;
+                        my $protocol = 'http';
+                        my $port = $r->get_server_port();
+                        if ($port eq '443') {
+                            $protocol = 'https';
+                        }
+                        $r->header_out(Location => $protocol.'://'.$alias.$uri);
+                        return REDIRECT;
+                    }
+                }
+            }
+        }
+    }
     if ($r->uri=~m|^(/raw)?/uploaded/|) {
         my $fn = $r->uri();
         $fn=~s/^\/raw//;


More information about the LON-CAPA-cvs mailing list