logo NodeSeekbeta

【oneman小知识】 whmcs NAT产品向用户展示的NAT端口信息

在用whmcs + Proxmox VE VPS For WHMCS插件,一直没找到什么向用户展示NAT端口信息的好的方法,目前大部分人在用的都是源自论坛Twilight佬的单独页面端口计算的方法,不是很方便,需要用户自行计算;同时到看有分享经验的小伙伴提到利用添加hook文件的方式在whmcs前端页面显示当前账户余额功能的代码,于是让ai简单的尝试写了一下,发现可行,于是分享出来。

具体效果:
image

如何实现:
将下面的代码保存在/includes/hooks/portmap.php即可。
这里查找页面私网IP网段为172.16.x.x的格式,ssh的端口范围从19000开始计算,NAT分配端口从20000开始每隔20为一组,可以根具自己的需求更改,iptable的端口转发大家应该都很熟练,这里不涉及配置方法。

<?php
use WHMCS\Database\Capsule;

if (!defined("WHMCS")) {
    die("This file cannot be accessed directly");
}

add_hook('ClientAreaProductDetailsOutput', 1, function($vars) {

    // 限定仅主产品详情页
    if (
        (isset($_GET['modop']) && $_GET['modop'] !== '') ||
        (isset($_GET['a']) && $_GET['a'] !== '') ||
        (isset($_GET['mg-page']) && $_GET['mg-page'] !== '') ||
        (isset($_GET['action']) && $_GET['action'] !== 'productdetails')
    ) {
        return '';
    }

    $service = $vars['service'] ?? [];

    // 找所有可能的 IP
    $candidates = [];

    if (!empty($service['dedicatedip'])) $candidates[] = $service['dedicatedip'];

    if (!empty($service['assignedips'])) {
        foreach (preg_split('/[\r\n,;]+/', $service['assignedips']) as $ip) {
            if (trim($ip)) $candidates[] = trim($ip);
        }
    }

    if (!empty($service['customfields'])) {
        foreach ($service['customfields'] as $cf) {
            if (!empty($cf['value'])) $candidates[] = $cf['value'];
        }
    }

    // 找私网 172.16.N.X
    $privateIp = null;
    $N = $X = 0;

    foreach ($candidates as $c) {
        if (preg_match('/^172\.16\.(\d{1,3})\.(\d{1,3})$/', $c, $m)) {
            $N = intval($m[1]);
            $X = intval($m[2]);
            if ($N >= 1 && $N <= 255 && $X >= 10 && $X <= 255) {
                $privateIp = $c;
                break;
            }
        }
    }

    if (!$privateIp) return '';

    // NAT 端口
    $ssh_port   = 19000 + ($X - 10);
    $start_port = 20000 + ($X - 10) * 20;
    $end_port   = $start_port + 19;

    // HTML
    $html = <<<HTML
<style>
.nat-item {
    cursor:pointer;
    font-weight:bold;
    padding:2px 4px;
    border-radius:4px;
}
.nat-ip { color:#1a73e8; }
.nat-port { color:#d93025; }
.copy-tip {
    display:none;
    margin-left:6px;
    color:green;
    font-size:12px;
}
</style>

<script>
function natCopy(val, tipId){
    navigator.clipboard.writeText(val).then(()=>{
        var tip = document.getElementById(tipId);
        tip.style.display = "inline";
        setTimeout(()=>{ tip.style.display="none"; }, 1200);
    });
}
</script>

<div class="panel panel-default" style="margin-top:20px;">
  <div class="panel-heading"><strong>NAT 端口信息</strong></div>
  <div class="panel-body">

    <!-- 公网 IP -->
    <p id="nat-public-ip-row" style="display:none;">
        <strong>公网 IP:</strong>
        <span 
            class="nat-item nat-ip" 
            id="nat-public-ip"
            onclick="natCopy(this.textContent,'tip-public-ip')"
        ></span>
        <span class="copy-tip" id="tip-public-ip">已复制</span>
    </p>

    <!-- SSH -->
    <p>
        <strong>SSH 端口:</strong>
        <span 
            class="nat-item nat-port" 
            id="nat-ssh"
            onclick="natCopy(this.textContent,'tip-ssh')"
        >{$ssh_port}</span>
        <span class="copy-tip" id="tip-ssh">已复制</span>
    </p>

    <!-- NAT 范围 -->
    <p>
        <strong>NAT 端口:</strong>
        <span 
            class="nat-item nat-ip"
            onclick="natCopy('{$start_port}','tip-range')"
        >{$start_port}</span>
        -
        <span 
            class="nat-item nat-ip"
            onclick="natCopy('{$end_port}','tip-range')"
        >{$end_port}</span>
        <span class="copy-tip" id="tip-range">已复制</span>
    </p>

  </div>
</div>

<!-- 解析 NAT 公网 IP -->
<script>
(function(){
    function fill() {
        try {
            document.querySelectorAll(".list-info-title").forEach(function(el){
                var txt = el.textContent.trim();
                var m = txt.match(/NAT公网IP[::]\\s*(\\d{1,3}(?:\\.\\d{1,3}){3})/);
                if (m && m[1]) {
                    document.getElementById("nat-public-ip").textContent = m[1];
                    document.getElementById("nat-public-ip-row").style.display = "block";
                }
            });
        } catch(e){}
    }
    if (document.readyState === "loading") {
        document.addEventListener("DOMContentLoaded", fill);
    } else {
        fill();
    }
})();
</script>
HTML;

    return $html;
});

在产品的配置页增加一个自定义字段如下图,x.x.x.x改为NAT的IP即可,勾选项都不选即可。
image

这里只测试了Proxmox VE VPS For WHMCS的插件,其他的没测试,实现方法就是从产品详情页面抓取IP计算端口,可自行修改代码尝试。

参考:
https://virt.spiritlhl.net/guide/pve/pve_install.html
https://www.nodeseek.com/post-12946-1
https://openssw.com/view/我要当oneman.md

  • xhj003

  • mark 鸡腿奉上

  • 快进到ONEMAN

  • 鸡腿鸡腿

  • 牛逼 收藏了~~~

  • 请问使用的Proxmox VE VPS For WHMCS插件是什么版本,收费吗

你好啊,陌生人!

我的朋友,看起来你是新来的,如果想参与到讨论中,点击下面的按钮!

📈用户数目📈

目前论坛共有72033位seeker

🎉欢迎新用户🎉