AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / server / 问题 / 1098827
Accepted
Lasse Michael Mølgaard
Lasse Michael Mølgaard
Asked: 2022-04-18 12:17:37 +0800 CST2022-04-18 12:17:37 +0800 CST 2022-04-18 12:17:37 +0800 CST

Freeradius 与 dhcp 服务器:调用 perl 模块返回错误

  • 772

这是我之前的问题的延续,即从 Freeradius DHCP 服务器实现结合 Strongswan VPN 服务器发送静态路由。

在使用 tcpdump 和 Wireshark 调试 Freeradius 时,我发现我可以通过向dhcp 服务器配置文件的我的和部分添加DHCP-Classless-Static-Route和DHCP-Site-specific-25(又名 Microsoft 静态路由)选项来从 Freeradius DHCP 服务器发送无类静态路由。DHCP-DiscoverDHCP-Request

但是:如果我将默认网关设置为Strongswan 文档0.0.0.0建议的那样,Microsoft VPN 客户端似乎不接受静态路由。

至少我在使用route print -4.

此外,当我0.0.0.0通过 VPN 接口用作标准网关时,我无法在 Windows 客户端上手动添加路由。

然而:

假设我想192.168.200.0/24通过 VPN 访问子网,我的 VPN 服务器将地址分配192.168.201.2/24给我的 Windows 客户端。然后实际上可以通过使用 windows 命令通过 192.168.201.2 访问子网 192.168.200.0/24 来在 windows 客户端创建静态路由:

route add 192.168.200.0 mask 255.255.255.0 192.168.201.2

我知道它看起来有点奇怪,但我可以 ping192.168.200.0子网上的任何主机,所以只要它有效,我就很高兴。:-)

但是:如果我可以通过从我的 VPN 服务器通告路由而不是在所有 VPN 客户端上手动进行,我会更高兴。:-)

这意味着我必须对 Freeradius 中的 DHCP 配置进行一些动态编程。在我的情况下,这意味着我必须在 DHCP-Discover 和 DHCP-request 中引用 perl 模块,该模块获取分配的客户端 vpn ip 地址,将其转换为八位字节并将其与也以八位字节形式给出的静态路由组合。

一个例子:

子网192.168.200.0/24将被编码为0x18c0a8c8首先编码子网掩码。

客户端192.168.201.2/24将被编码,0xc0a8c902因为它只是将 IP 地址中的每个数字转换为十六进制。

路由的最终编码将是:0x18c0a8c8c0a8c902因为它只是两个字符串的连接。

然后我必须使用update reply以下代码:

  update reply {
    &DHCP-Classless-Static-Route = 0x18c0a8c8c0a8c902
    &DHCP-Site-specific-25 = 0x18c0a8c8c0a8c902
  }

如果还有更多路由,则所有路由将连接成一个长字符串。

棘手的部分:

假设您具有freeradius/3.0/sites-available/dhcp文件中的 Freeradius DHCP 服务器的默认配置。

DHCP-Discover 和 DHCP-Request 文件的一般结构如下:

dhcp DHCP-Request {
  update reply {
    &DHCP-Message-Type = DHCP-Ack
  }

  update reply {
    # General DHCP options, such as default GW, DNS, IP-address lease time etc.
  }

  update control {
    &Pool-Name := "vpn_pool"
  }

  dhcp_sqlippool

  ok
}

然后据我所知,我需要在dhcp_sqlippool被调用之后和返回之前调用我的 perl 模块ok,因为dhcp_sqlippool它是将 ipaddress 分配给 VPN 客户端的模块。

这意味着我的版本将类似于:

dhcp DHCP-Request {
  update reply {
    &DHCP-Message-Type = DHCP-Ack
  }

  update reply {
    # General DHCP options, such as default GW, DNS, IP-address lease time etc.
  }

  update control {
    &Pool-Name := "vpn_pool"
  }

  dhcp_sqlippool

  perl

  # If perl module returned no error
  if(ok) {
    update reply {
      # Perl-Route contains a hex encoded string with all routes.
      &DHCP-Classless-Static-Route = Perl-Route
      &DHCP-Site-specific-25 = Perl-Route      
    }
  }

  # Not sure if this one is needed?
  update reply {
    &DHCP-End-Of-Options = 255
  }

  ok
}

为了使其工作,我必须在freeradius/3.0/mods-enabled文件夹下启用 perl 并修改文件名以freeradius/3.0/mods-enabled/perl将其指向我的 perl 模块。比如:

filename = ${modconfdir}/${.:instance}/dhcp/Options.pm

但是我如何以正确的方式引用对 perl 的调用呢?

我以为我必须启用该行并在我的 perl 模块func_post_auth = post_auth中freeradius/3.0/mods-enabled/perl创建一个sub post_auth部分来处理来自 Freeradius 的调用,但据我在日志中看到的,我在 Freeradius 中收到以下错误:

(8) perl: perl_embed:: module = /etc/freeradius/3.0/mods-config/perl/dhcp/Options.pm , 
func = post_auth exit status= Undefined subroutine &main::post_auth called.
...
(8)     [perl] = fail
(8)   } # dhcp DHCP-Discover = fail

那么我没有看到的是什么?

perl freeradius dhcp-server
  • 1 1 个回答
  • 108 Views

1 个回答

  • Voted
  1. Best Answer
    Lasse Michael Mølgaard
    2022-05-17T01:32:19+08:002022-05-17T01:32:19+08:00

    我把头撞在墙上几次,但至少我让 perl 模块工作,虽然我并不完全是我想要的,因为通过 DHCP 的静态路由不会从 Freeradius DHCP 服务器通过 Strongswan 传递到 VPN 客户端,但从 Freeradius DHCP 服务器调试 UDP 包意味着问题出在其他地方。

    无论如何,这就是我所做的:

    1. 启用 perl 模块freeradius/3.0/mods-enabled并至少设置以下几行:
    perl {
      # Perl code location: ("freeradius/3.0/mods-config/dhcp/Options.pm")
      filename = ${modconfdir}/${.:instance}/dhcp/Options.pm
    
      # DHCP module is called during freeradius post_auth
      func_post_auth = post_auth
    }
    
    1. 修改freeradius/3.0/sites-enabled/dhcp 相关的地方是DHCP-Discover和DHCP-Request:
    dhcp DHCP-Discover {
    
            update reply {
                   DHCP-Message-Type = DHCP-Offer
            }
    
            #  The contents here are invented.  Change them!
            update reply {
                    &DHCP-Domain-Name-Server = 192.168.200.1
                    &DHCP-Subnet-Mask = 255.255.255.0
                    &DHCP-IP-Address-Lease-Time = 86400
                    &DHCP-DHCP-Server-Identifier = 192.168.200.4
            }
    
            #  Or, allocate IPs from the DHCP pool in SQL. You may need to
            #  set the pool name here if you haven't set it elsewhere.
            update control {
                    &Pool-Name := "vpn_pool"
            }
    
            dhcp_sqlippool
    
            # Call static route generation.
            perl
    
            ok
    }
    
    dhcp DHCP-Request {
    
            # Response packet type. See DHCP-Discover section above.
            update reply {
                   &DHCP-Message-Type = DHCP-Ack
            }
    
            #  The contents here are invented.  Change them!
            update reply {
                    &DHCP-Domain-Name-Server = 192.168.200.1
                    &DHCP-Subnet-Mask = 255.255.255.0
                    &DHCP-IP-Address-Lease-Time = 86400
                    &DHCP-DHCP-Server-Identifier = 192.168.200.4
            }
    
            #  Or, allocate IPs from the DHCP pool in SQL. You may need to
            #  set the pool name here if you haven't set it elsewhere.
            update control {
                    &Pool-Name := "vpn_pool"
            }
     
            dhcp_sqlippool
    
            # Call static route generation.
            perl
    
            ok
    }
    
    1. 创建位于以下位置的 perl 代码freeradius/3.0/mods-config/perl/dhcp/Options.pm:
    use strict;
    use warnings;
    use Data::Dumper;
    use Net::IP;
    
    # Bring the global hashes into the package scope
    our (%RAD_REQUEST, %RAD_REPLY, %RAD_CHECK);
    
    #
    # This the remapping of return values
    #
    use constant {
        RLM_MODULE_REJECT   => 0, # immediately reject the request
        RLM_MODULE_OK       => 2, # the module is OK, continue
        RLM_MODULE_HANDLED  => 3, # the module handled the request, so stop
        RLM_MODULE_INVALID  => 4, # the module considers the request invalid
        RLM_MODULE_USERLOCK => 5, # reject the request (user is locked out)
        RLM_MODULE_NOTFOUND => 6, # user not found
        RLM_MODULE_NOOP     => 7, # module succeeded without doing anything
        RLM_MODULE_UPDATED  => 8, # OK (pairs modified)
        RLM_MODULE_NUMCODES => 9  # How many return codes there are
    };
    
    # Same as src/include/radiusd.h
    use constant    L_DBG=>   1;
    use constant    L_AUTH=>  2;
    use constant    L_INFO=>  3;
    use constant    L_ERR=>   4;
    use constant    L_PROXY=> 5;
    use constant    L_ACCT=>  6;
    
    # Function to handle post_auth
    
    sub post_auth {
    
        # Get VPN Client IP from Freeradius DHCP server.
        my $client_ip = new Net::IP ( $RAD_REQUEST{'DHCP-Requested-IP-Address'} ) or die (Net::IP::Error());
    
        # An example of 2 routing rules sent ('192.168.20.0/24' and '192.168.200.0/24') 
        my @routes = (new Net::IP('192.168.20/24'), new Net::IP('192.168.200/24'));
    
        # Measure how many elements there is in the routes array.
        my $size = @routes;
    
        # Convert client ip into hex code.
        my $client_octets = get_ip_octets ($client_ip->ip(),$client_ip->prefixlen());
    
        # Freeradius want the encoded string start with '0x'
        # followed by the encoded octets as hex.
        my $octet_str = "0x";
    
        for(my $i = 0; $i < $size; $i++)
        {
            # Convert subnet into octets, skipping ending zeroes.
            my $route_octets = get_ip_octets ($routes[$i]->ip(),$routes[$i]->prefixlen());
    
            # Convert network prefix into octets
            my $hex_prefix = sprintf("%02x", $routes[$i]->prefixlen());
    
            # Route is encoded by network octets followed by subnet octets
            $route_octets = $hex_prefix . $route_octets;
    
            # The entire route string is the route octets followed by gateway octets ('the client vpn ip').
            my $route_str = $route_octets . $client_octets;
    
            $octet_str = $octet_str . $route_str;
        }
    
        # Classless static routing (dhcp option 121)
        $RAD_REPLY{'DHCP-Classless-Static-Route'} = $octet_str;
    
        # Microsoft classless static routing (dhcp option 249)
        $RAD_REPLY{'DHCP-Site-specific-25'} = $octet_str;
    
        return RLM_MODULE_OK;
    
    }
    
    sub get_ip_octets {
        # First parameter: Source ip address
        my $sip = $_[0];
    
        # Second parameter: Bitlength of network (aka CIDR notation).
        my $cidr = $_[1];
    
        my @decimals = split('\.', $sip);
        my $index = int($cidr / 8) ;
    
        my $result = '';
        for(my $i = 0; $i < $index; $i++)
        {
            # Convert each number in ip address to hex and format with leading
            # zero in case converted number is less than 16.
            $result = $result . sprintf("%02x", $decimals[$i]);
        }
    
        return $result;
    }
    

    可以从这里调整 perl 代码,因此根据客户端操作系统发送选项 121或选项 249。

    我还保留了使代码更通用的可能性,因此静态路由可以直接在 Freeradius 配置文件中定义给读者。

    • 0

相关问题

  • CentOS 的依赖挑战

  • 将 perl 脚本作为 Windows 服务运行

  • debian 升级失败,导致 perl 问题

  • Perl 5.10 登录/注销脚本

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    新安装后 postgres 的默认超级用户用户名/密码是什么?

    • 5 个回答
  • Marko Smith

    SFTP 使用什么端口?

    • 6 个回答
  • Marko Smith

    命令行列出 Windows Active Directory 组中的用户?

    • 9 个回答
  • Marko Smith

    什么是 Pem 文件,它与其他 OpenSSL 生成的密钥文件格式有何不同?

    • 3 个回答
  • Marko Smith

    如何确定bash变量是否为空?

    • 15 个回答
  • Martin Hope
    Tom Feiner 如何按大小对 du -h 输出进行排序 2009-02-26 05:42:42 +0800 CST
  • Martin Hope
    Noah Goodrich 什么是 Pem 文件,它与其他 OpenSSL 生成的密钥文件格式有何不同? 2009-05-19 18:24:42 +0800 CST
  • Martin Hope
    Brent 如何确定bash变量是否为空? 2009-05-13 09:54:48 +0800 CST
  • Martin Hope
    cletus 您如何找到在 Windows 中打开文件的进程? 2009-05-01 16:47:16 +0800 CST

热门标签

linux nginx windows networking ubuntu domain-name-system amazon-web-services active-directory apache-2.4 ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve