NPS内网穿透获取真实IP
本文最后更新于13 天前,其中的信息可能已经过时,如有错误请发送邮件到v1st233@gmail.com

  内网穿透情况下,无论雷池、群晖、web应用还有jumpserver的ssh都有拿到真实IP的需求,不然在日志中看到全是内网ip没办法进行针对性封锁。要获取真实ip,公网VPS和内网都需要进行不同的配置。

VPS配置

  VPS上我用的是NPS:相比FRP,不用在客户端写配置文件,最方便的是可以直接在公网web页面上管理哪些端口穿透。
NPS前面使用NginxProxyManager来代理群晖、博客、图床等web页面,方便资源缓存和证书管理。
SSH和RDP直接NPS的TCP隧道+Proxy Protocol代理协议连接。

NPS服务端

  原版NPS有不少bug,也不支持Proxy Protocol代理协议,使用的是这个NPS 内网穿透 (全修)

配置docker-compose.yml,然后docker compose up -d运行:

name: nps
services:
  nps:
    container_name: nps
    hostname: nps
    image: duan2001/nps:latest
    network_mode: host
    restart: always
    volumes:
      - ./conf:/conf
      - /etc/localtime:/etc/localtime:ro

启动后修改配置文件conf/npd.conf:

  • 关闭http和https代理
  • 修改公共密钥
  • 修改登录名和密码

然后docker compose restart重启:

#############################################
# 域名转发设置
#############################################
# HTTP/HTTPS 代理设置:端口为 0 时不启动代理服务
http_proxy_ip=0.0.0.0
http_proxy_port=0
https_proxy_port=0
#http3_proxy_port=443
...
# 公共密钥
public_vkey=xxxx
...
# 管理后台登录用户名和密码
web_username=admin
web_password=xxxx

NPC客户端

  浏览器访问http://vpsip:8080登录NPS,新建一个客户端(cpu内存弱的可以不选加密和压缩),记下验证密钥。
在路由器或nas、旁路等这些不常关机的设备上下载npc客户端,运行:
./npc -server=vpsip:8024 -vkey=key -type=tcp -log=off
或者:

docker run -d --restart=always --name npc --net=host duan2001/npc -server=vpsip:8024,yyy:456 -vkey=key1,key2 -type=tls,tcp -log=off

  在NPS网页上添加TCP隧道,把雷池的80和443端口映射出来:

端口

内网配置

雷池配置

  防护应用->高级配置->源IP获取方式改为从HTTP Heder获取,填入X-Real-IP

X-Real-IP

  每个应用都需要打开应用详情->高级配置->自定义NGINX配置,添加

set_real_ip_from 192.168.0.0/16;
# 高级版和专业版可以直接在 防护应用->高级配置->HTTP Heder操作统一添加

然后就能在日志中看到真实IP了

雷池日志

JumpServer配置

  JumpServer分为网页端和ssh(2222)终端两个不同的配置,分别对应操作日志和登录日志内的内容。

网页端

  在雷池添加防护并填上JumpServer上游,修改JumpServer的配置文件/opt/jumpserver/config/config.txt

DOMAINS=""  #添加上子域名
USE_LB=0  #改为0

执行jmsctl restart重启JumpServer。

ssh端

  在NPS新增一个客户端,并在运行JumpServer的机器上运行一个新的NPC客户端,在添加2222的TCP隧道时,代理协议 (Proxy Protocol)选择V2,这样在登录日志就能看到真实IP了。

2222映射

最终效果:
最终效果

真实IP:

Web应用

WordPress

  WordPress是从$_SERVER['REMOTE_ADDR']获取评论和用户IP的,可以用$_SERVER['HTTP_X_REAL_IP']覆盖$_SERVER['REMOTE_ADDR'],实现获取真实IP。
wp-config.php最上方添加:

// 获取真实IP并覆盖 REMOTE_ADDR
if ( isset($_SERVER['HTTP_X_REAL_IP']) && filter_var($_SERVER['HTTP_X_REAL_IP'], FILTER_VALIDATE_IP) ) {
    $_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_REAL_IP'];
} elseif ( isset($_SERVER['HTTP_X_FORWARDED_FOR']) ) {
    $xff_ips = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
    foreach ( $xff_ips as $ip ) {
        $ip = trim($ip);
        if (filter_var($ip, FILTER_VALIDATE_IP)) {
            $_SERVER['REMOTE_ADDR'] = $ip;
            break;
        }
    }
}

  如果是在雷池后面的K8s里安装的WordPress,可以使用$_SERVER['HTTP_X_ORIGINAL_FORWARDED_FOR']去覆盖$_SERVER['REMOTE_ADDR']:

if (isset($_SERVER['HTTP_X_ORIGINAL_FORWARDED_FOR'])) {
    // 多个 IP 情况下取第一个
    $list = explode(',', $_SERVER['HTTP_X_ORIGINAL_FORWARDED_FOR']);
    $_SERVER['REMOTE_ADDR'] = trim($list[0]);
}

兰空图床

  修改app/Services/ImageService.php的206行,修改为一下代码:

        if ($request->hasHeader('X-Original-Forwarded-For')) {
            // 优先使用 X-Original-Forwarded-For(取第一个)
            $xff = $request->header('X-Original-Forwarded-For');
            $xoffIp = trim(explode(',', $xff)[0]);
            $ip = filter_var($xoffIp, FILTER_VALIDATE_IP) ? $xoffIp : $request->ip();
        } elseif ($request->hasHeader('X-Real-IP')) {
            $realIp = $request->header('X-Real-IP');
            $ip = filter_var($realIp, FILTER_VALIDATE_IP) ? $realIp : $request->ip();
        } elseif ($request->hasHeader('X-Forwarded-For')) {
            $xff = $request->header('X-Forwarded-For');
            $firstIp = trim(explode(',', $xff)[0]);
            $ip = filter_var($firstIp, FILTER_VALIDATE_IP) ? $firstIp : $request->ip();
        } else {
            // 默认回退
            $ip = $request->ip();
        }

        $image->fill([
            'md5' => md5_file($file->getRealPath()),
            'sha1' => sha1_file($file->getRealPath()),
            'path' => $configs->get(GroupConfigKey::PathNamingRule) ? dirname($pathname) : '',
            'name' => basename($pathname),
            'origin_name' => $file->getClientOriginalName(),
            'size' => $file->getSize() / 1024,
            'mimetype' => $file->getMimeType(),
            'extension' => strtolower($extension),
            'width' => $width,
            'height' => $height,
            'is_unhealthy' => false,
            'uploaded_ip' => $ip,
            // 'uploaded_ip' => $request->ip(),
        ]);

群晖

  控制面板->安全性->信任的代理服务器->新增->192.167.0.0/16->保存。

群晖

go程序

  内网有少量go写的微服务,如随机背景、ip地址定位等,使用的是github.com/gin-gonic/gin库,修改起来比较方便,在路由前添加下面代码就行:

r.SetTrustedProxies([]string{
    "10.0.0.0/8",
    "192.168.0.0/16",
})
r.RemoteIPHeaders = []string{"X-Original-Forwarded-For", "X-Real-IP"}

普通TCP端口

能且只能让运行npc客户端的设备获取真实ip

目前只在Linux系统上实验成功。Win的local路由还没摸清

  实现逻辑如下:

mmproxy

nps/npc配置

参考链接:https://github.com/fatedier/frp/issues/4692#issuecomment-2728547880

  nps和JumpServer一样,在需要获取真实IP的机器上运行npc。
在运行npc的设备上mkdir mmproxy && cd mmproxy,创建一个名为Dockerfile的文件,粘贴如下内容:

FROM golang:1.21-alpine AS builder
RUN apk add --no-cache git
WORKDIR /app
RUN git clone https://github.com/path-network/go-mmproxy .
RUN go build -o mmproxy .

FROM alpine:latest
WORKDIR /app
COPY --from=builder /app/mmproxy .
RUN echo '#!/bin/sh' > /app/start.sh && \
    echo '' >> /app/start.sh && \
    echo '# 设置路由规则' >> /app/start.sh && \
    echo 'ip rule add from 127.0.0.1/8 iif lo table 123 2>/dev/null || true' >> /app/start.sh && \
    echo 'ip route add local 0.0.0.0/0 dev lo table 123 2>/dev/null || true' >> /app/start.sh && \
    echo '' >> /app/start.sh && \
    echo '# 如果没有提供端口映射,使用默认的' >> /app/start.sh && \
    echo 'if [ -z "$PORT_MAPPINGS" ]; then' >> /app/start.sh && \
    echo '  PORT_MAPPINGS="222:22"' >> /app/start.sh && \
    echo 'fi' >> /app/start.sh && \
    echo '' >> /app/start.sh && \
    echo '# 解析并启动所有端口映射' >> /app/start.sh && \
    echo 'for mapping in $(echo $PORT_MAPPINGS | tr "," " "); do' >> /app/start.sh && \
    echo '  listen_port=$(echo $mapping | cut -d: -f1)' >> /app/start.sh && \
    echo '  target_port=$(echo $mapping | cut -d: -f2)' >> /app/start.sh && \
    echo '  echo "启动端口映射: $listen_port -> 127.0.0.1:$target_port"' >> /app/start.sh && \
    echo '  /app/mmproxy -l "0.0.0.0:$listen_port" -4 "127.0.0.1:$target_port" -6 "[::1]:$target_port" &' >> /app/start.sh && \
    echo 'done' >> /app/start.sh && \
    echo '' >> /app/start.sh && \
    echo '# 保持容器运行' >> /app/start.sh && \
    echo 'wait' >> /app/start.sh && \
    chmod +x /app/start.sh

ENTRYPOINT ["/app/start.sh"]

然后使用这个命令编译:
docker build -t mmproxy:latest .
然后新增一个docker-compose.yml:

version: '3'
services:
  mmproxy:
    image: mmproxy:latest
    container_name: mmproxy
    restart: always
    network_mode: host
    cap_add:
      - NET_ADMIN
    environment:
      - PORT_MAPPINGS=222:22,333:33

在nps上添加一个TCP隧道,内网端口填222(不填写ip),代理协议 (Proxy Protocol)选择V2。

其他端口的隧道一样操作,也适用于80和443。

文章地址:https://www.qingh.xyz/nps-get-real-ip/

暂无评论 IP地址位置数据由 纯真CZ88 提供支持

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇