Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions .github/workflows/Build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,11 @@ jobs:

- name: Update OS and Compilers
run: |
sudo apt install -y cmake ninja-build
sudo apt install -y cmake ninja-build libpam0g-dev

- name: Build proxy
run: |
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DENABLE_BUILD_WERROR=OFF -G Ninja
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DENABLE_BUILD_WERROR=OFF -DENABLE_USE_PAM_AUTH=ON -G Ninja
cmake --build build --config Release

- name: Archive artifacts
Expand All @@ -72,7 +72,7 @@ jobs:
image: alpine:3.20.1
steps:
- name: Install packages
run: apk add bash git nasm yasm pkgconfig build-base clang cmake ninja linux-headers
run: apk add bash git nasm yasm pkgconfig build-base clang cmake ninja linux-headers linux-pam-dev

- uses: actions/checkout@v4

Expand All @@ -94,7 +94,7 @@ jobs:

- name: Update OS and Compilers
run: |
sudo apt install -y cmake ninja-build
sudo apt install -y cmake ninja-build libpam0g-dev

- name: Build mimalloc
run: |
Expand All @@ -108,7 +108,7 @@ jobs:

- name: Build proxy
run: |
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DENABLE_BUILD_WERROR=OFF -DENABLE_MIMALLOC_STATIC=ON -G Ninja
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DENABLE_BUILD_WERROR=OFF -DENABLE_MIMALLOC_STATIC=ON -DENABLE_USE_PAM_AUTH=ON -G Ninja
cmake --build build --config Release

- name: Archive artifacts
Expand All @@ -124,7 +124,7 @@ jobs:

- name: Update OS and Compilers
run: |
sudo apt install -y cmake ninja-build
sudo apt install -y cmake ninja-build libpam0g-dev

- name: Build proxy
run: |
Expand Down
11 changes: 11 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,9 @@ option(ENABLE_REUSEPORT "Build with REUSEPORT support" OFF)

option(ENABLE_SYSTEM_ZLIB "Build with system zlib support" OFF)
option(ENABLE_SYSTEM_OPENSSL "Build with system openssl support" OFF)

option(ENABLE_USE_SYSTEMD_LOG "Build with systemd log support" OFF)
option(ENABLE_USE_PAM_AUTH "Build with PAM authentication support" OFF)

option(ENABLE_USE_OPENSSL "Build with openssl support" ON)
option(ENABLE_USE_BORINGSSL "Build with boringssl support" OFF)
Expand Down Expand Up @@ -136,6 +138,15 @@ endif()

################################################################################

if (UNIX AND NOT APPLE)
if (ENABLE_USE_PAM_AUTH)
add_definitions(-DUSE_PAM_AUTH)
link_libraries(pam)
endif()
endif()

################################################################################

if (WIN32)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")

Expand Down
3 changes: 2 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ RUN echo "https://dl-cdn.alpinelinux.org/alpine/edge/main" > /etc/apk/repositori
RUN apk add -u alpine-keys --allow-untrusted
RUN apk update
RUN apk upgrade
RUN apk add --no-cache bash git nasm yasm pkgconfig build-base clang cmake ninja linux-headers
RUN apk add --no-cache bash git nasm yasm pkgconfig build-base clang cmake ninja linux-headers linux-pam-dev linux-pam
RUN ln -s /lib/libpam.* /usr/lib/

ADD . /proxy

Expand Down
6 changes: 3 additions & 3 deletions Dockerfile.ubuntu
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ FROM ubuntu:22.04 AS builder
RUN apt-get update && apt-get install --fix-missing -y ca-certificates
RUN sed -i "s@http://.*archive.ubuntu.com@https://mirrors.pku.edu.cn@g" /etc/apt/sources.list && sed -i "s@http://.*security.ubuntu.com@https://mirrors.pku.edu.cn@g" /etc/apt/sources.list
RUN apt-get update && apt-get upgrade -y
RUN apt-get install -y cmake gcc g++ ninja-build
RUN apt-get install -y cmake gcc g++ ninja-build linux-pam-dev
ADD . /proxy
RUN cd /proxy && mkdir -p build && cd build && cmake .. -DCMAKE_BUILD_TYPE=Release -DENABLE_SNMALLOC_STATIC=ON -G Ninja && ninja
RUN cd /proxy && mkdir -p wolfssl && cd wolfssl && cmake .. -DENABLE_USE_OPENSSL=OFF -DENABLE_USE_WOLFSSL=ON -DENABLE_SNMALLOC_STATIC=ON -DCMAKE_BUILD_TYPE=Release -G Ninja && ninja
RUN cd /proxy && mkdir -p build && cd build && cmake .. -DCMAKE_BUILD_TYPE=Release -DENABLE_SNMALLOC_STATIC=ON -DENABLE_USE_PAM_AUTH=ON -G Ninja && ninja
RUN cd /proxy && mkdir -p wolfssl && cd wolfssl && cmake .. -DENABLE_USE_OPENSSL=OFF -DENABLE_USE_WOLFSSL=ON -DENABLE_SNMALLOC_STATIC=ON -DENABLE_USE_PAM_AUTH=ON -DCMAKE_BUILD_TYPE=Release -G Ninja && ninja

FROM ubuntu:22.04
RUN apt-get update && apt-get install -y ca-certificates
Expand Down
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ docker build . -t proxy:v1
| transparent | 启用透明代理,默认禁用,此选项仅 linux 平台有效 |
| so_mark | 用于发起向 `proxy_pass` 连接时设置 so_mark 以方便实现代理流量的策略路由,仅在 transparent 启动时有效 |
| local_ip | 用于向上游服务或目标服务发起连接时使用指定的本地网口 `ip` 地址,通常用于机器上有多个 `ip` 时使用特定 `ip` 向外发起连接 |
| pam_auth | 用于指定使用 `PAM` 认证模块进行认证,参数值为 `PAM` 服务名称,`PAM` 能和使用 `auth_users` 参数同时用于认证,优先使用 `auth_users` 参数进行认证,需要在编译时添加 `-DENABLE_USE_PAM_AUTH=ON` 选项以启用 `PAM` 模块认证功能 |
| auth_users | 认证信息列表,客户端必须满足其中一对用户/密码才能握手通过,默认用户密码是 `jack:1111`(默认需要认证是为了避免不小心被当成别人免费的跳板),若需要设置为无需要认证代理模式,必须置 `auth_users` 参数为 "" |
| proxy_pass | 当前服务作为中间级联服务时,`proxy_pass` 指定上游代理服务地址,格式为 `url` 格式,如果有认证信息并必须包含认证信息,如: `https://jack:1111@example.com:1080/` |
| proxy_pass_ssl | 向 `proxy_pass` 指定的上游代理服务连接时,是否通过 `ssl` 安全传输,注意必须在上游代理服务启用 `ssl` 相关证书域名密钥等信息. |
Expand Down Expand Up @@ -180,6 +181,16 @@ Host example

然后当使用 `ssh` 连接主机 `example` 时将会按上述配置文件中参数创建 `proxy_server` 代理隧道,通过 `proxy_pass` 指定的代理服务器连接目标 `HostName` 所指的服务器。

## 使用 PAM 模块认证介绍

`proxy_server` 支持使用 `PAM` 模块进行认证(仅支持 `pam` 的 `linux` 平台,编译 `proxy_server` 时需要在 `cmake` 中添加 `-DENABLE_USE_PAM_AUTH=ON` 选项以启用 `PAM` 模块认证功能),具体使用方法如下:

1. 配置 `PAM` 服务,如将 `doc` 目录下 `pam.example` 下的文件 `proxy-service` 复制到 `/etc/pam.d/` 目录中,文件名即为 `PAM` 服务名称。
2. 在 `proxy_server` 中指定 `PAM` 服务名称,如 `--pam_auth proxy-service`。
3. 使用 `linux` 命令添加用户到 `PAM` 服务中,如 `useradd jack`,其中 `jack` 为用户名,使用 `passwd jack` 设置密码如 `1111`。
4. 测试认证是否生效,如 `curl -x http://jack:1111@localhost:1080/ https://google.com`,如果返回 `200 OK` 则说明认证生效。

`PAM` 模块认证可以使用 `linux` 命令添加或管理用户,可以极大的方便 `proxy_server` 的用户管理,而不必依赖复杂的数据库系统,当然如果你是开发人员,也可以开发一个支持数据库认证的 `PAM` 的 `so` 模块(可参考 `doc` 下 `pam.example` 的 `pam_sqlite.c` 如何实现 `PAM` 认证模块),或者使用 `PAM` 模块认证来实现 `LDAP` 认证等等各种方式。

## 静态文件 http 服务器(可配置为云音乐播放器)

Expand Down
106 changes: 106 additions & 0 deletions doc/pam.example/pam_sqlite.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
//
// 使用下面命令编译并安装到 pam 模块目录
// gcc -fPIC -fstack-protector -c pam_sqlite.c
// gcc -shared -o pam_sqlite.so pam_sqlite.o -lpam -lsqlite3
// cp pam_sqlite.so /usr/lib/security/
//
// pam_sqlite.so 模块用到的数据库的表结构如下:
//
// 表名:users
// 字段:username(用户名,主键)、password(密码,非空)
//
// CREATE TABLE users (
// username TEXT PRIMARY KEY,
// password TEXT NOT NULL
// );
//

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <security/pam_modules.h>
#include <security/pam_ext.h>
#include <security/pam_appl.h>
#include <syslog.h>

#include <sqlite3.h>

#define DB_PATH "/tmp/users.db"

// 核心函数:处理身份验证
PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) {
const char *user;
const char *password;
int retval;

const char* db_path = DB_PATH;
if (argc >= 1) {
db_path = argv[0];
}

pam_syslog(pamh, LOG_INFO, "db path: %s", db_path);

// 1. 获取认证的用户名
retval = pam_get_user(pamh, &user, "Username: ");
if (retval != PAM_SUCCESS || user == NULL) {
pam_syslog(pamh, LOG_ERR, "pam_get_user failed!");
return PAM_AUTH_ERR;
}

// 2. 获取认证的密码
retval = pam_get_authtok(pamh, PAM_AUTHTOK, &password, NULL);
if (retval != PAM_SUCCESS) {
pam_syslog(pamh, LOG_ERR, "pam_get_authtok failed!");
return PAM_AUTH_ERR;
}

// 3. 查询 SQLite 数据库
sqlite3 *db;
sqlite3_stmt *res;

if (sqlite3_open(db_path, &db) != SQLITE_OK) {
pam_syslog(pamh, LOG_ERR, "sqlite open failed: %s", sqlite3_errmsg(db));
return PAM_SERVICE_ERR;
}

const char *sql = "SELECT password FROM users WHERE username = ?;";
if (sqlite3_prepare_v2(db, sql, -1, &res, 0) != SQLITE_OK) {
pam_syslog(pamh, LOG_ERR, "sqlite prepare failed: %s", sqlite3_errmsg(db));
sqlite3_close(db);
return PAM_SERVICE_ERR;
}

sqlite3_bind_text(res, 1, user, -1, SQLITE_STATIC);

int step = sqlite3_step(res);
int authenticated = 0;

if (step == SQLITE_ROW) {
const char *db_password = (const char *)sqlite3_column_text(res, 0);
// 注意:生产环境应使用密码哈希(如 bcrypt)进行比对
if (strcmp(password, db_password) == 0) {
pam_syslog(pamh, LOG_NOTICE, "auth ok: %s", user);
authenticated = 1;
} else {
pam_syslog(pamh, LOG_NOTICE, "bad password: %s", user);
}
}

sqlite3_finalize(res);
sqlite3_close(db);

if (authenticated == 0) {
pam_syslog(pamh, LOG_NOTICE, "authenticated failed: %s", user);
}

return authenticated ? PAM_SUCCESS : PAM_AUTH_ERR;
}

PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv) {
return PAM_SUCCESS;
}

PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv) {
return PAM_SUCCESS;
}
12 changes: 12 additions & 0 deletions doc/pam.example/proxy-service
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# 这是一个 PAM 示例,将此配置文件 proxy-service 复制到 /etc/pam.d/ 目录中,然后
# 就可以使用 proxy_server 的 --pam_auth 参数指定为 "proxy-service" 即可.

# 以下为使用 pam_sqlite.c 编译的 pam_sqlite.so 通过 sqlite 数据库中的用户密码认证配置
#auth required pam_sqlite.so /var/users.db
#account required pam_permit.so

# 以下为使用 linux 用户密码认证的配置
auth required pam_unix.so
account required pam_unix.so
session required pam_unix.so

Loading