Compare commits
177 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d9ff2e1a62 | ||
|
|
3396100bc4 | ||
|
|
c53693be69 | ||
|
|
855f602e2f | ||
|
|
fd9a5ae249 | ||
|
|
61d5243678 | ||
|
|
e75a4dda25 | ||
|
|
65bfe5c03c | ||
|
|
b7c3e1f80b | ||
|
|
3fb01ce735 | ||
|
|
f14562b26b | ||
|
|
d4f35909c5 | ||
|
|
1ee2b1ff56 | ||
|
|
cab6e8a20f | ||
|
|
e53f8e1c94 | ||
|
|
23819fcb44 | ||
|
|
51930c855f | ||
|
|
690a6f4feb | ||
|
|
56e4020969 | ||
|
|
e06a9a40a3 | ||
|
|
767d2859f9 | ||
|
|
fa0a273865 | ||
|
|
030a7b8784 | ||
|
|
d2cd54d831 | ||
|
|
9c90f6b5cd | ||
|
|
d1e2f549a7 | ||
|
|
ffa9e1ad97 | ||
|
|
ca64905266 | ||
|
|
6b1f70407c | ||
|
|
5d298156e4 | ||
|
|
37f124ffe7 | ||
|
|
675e47ef43 | ||
|
|
176e4006f6 | ||
|
|
d91d5d91ef | ||
|
|
36eba09bbe | ||
|
|
4ac16540b7 | ||
|
|
ab4da37e72 | ||
|
|
b49dd4e97c | ||
|
|
6fb2e167d6 | ||
|
|
4b633a7c2a | ||
|
|
29a854e5d6 | ||
|
|
d49331426a | ||
|
|
fc3b88c2d6 | ||
|
|
fa8b8c5463 | ||
|
|
34ff461506 | ||
|
|
4d850336a9 | ||
|
|
a3eb3de9d9 | ||
|
|
c390f1c9c9 | ||
|
|
e30d191b4a | ||
|
|
d315792cc8 | ||
|
|
8ac3ef77bf | ||
|
|
ab46826072 | ||
|
|
73f88ee92d | ||
|
|
a52f59f629 | ||
|
|
848120d15b | ||
|
|
2fc5ea8bdd | ||
|
|
734f5e5448 | ||
|
|
da55d8ac32 | ||
|
|
2de5c3681f | ||
|
|
37badbee7c | ||
|
|
1f90d9ab93 | ||
|
|
33f2bd5648 | ||
|
|
bac0ab888d | ||
|
|
a557194e9f | ||
|
|
f0d29bc624 | ||
|
|
808cda5a6b | ||
|
|
1fa59df3f5 | ||
|
|
c2b5e9cc92 | ||
|
|
e41aee6dd0 | ||
|
|
f199b6acba | ||
|
|
a8886a1a95 | ||
|
|
38f47a28fa | ||
|
|
60d93b7022 | ||
|
|
b38e96e268 | ||
|
|
88a1f6ecb7 | ||
|
|
ae37ae4e40 | ||
|
|
4fd793b183 | ||
|
|
3288e55453 | ||
|
|
e9fa00409c | ||
|
|
60427893f2 | ||
|
|
ecfa12eb42 | ||
|
|
f8a2dfaf3a | ||
|
|
ae0d65b31f | ||
|
|
c2aac15b29 | ||
|
|
7ff52050dc | ||
|
|
b71a7c2490 | ||
|
|
36671d76c0 | ||
|
|
5130aabeb5 | ||
|
|
bacf92da68 | ||
|
|
757b5db65a | ||
|
|
f3a0668217 | ||
|
|
6d1bbbc4df | ||
|
|
c31106689a | ||
|
|
ce522f5675 | ||
|
|
6bd859747a | ||
|
|
7d5f53aebb | ||
|
|
f28efdf2b1 | ||
|
|
a9a75c6554 | ||
|
|
26f49d26db | ||
|
|
508ddd60e0 | ||
|
|
08b908273a | ||
|
|
8402967a0e | ||
|
|
a2e4264b01 | ||
|
|
ce057a05a7 | ||
|
|
7515c15123 | ||
|
|
60871860ae | ||
|
|
f8d065b09e | ||
|
|
2f2e64ae31 | ||
|
|
a4812dd596 | ||
|
|
2e420e921c | ||
|
|
99972f257a | ||
|
|
8e4ca75d36 | ||
|
|
360019d1a4 | ||
|
|
204c086a03 | ||
|
|
316834ffd0 | ||
|
|
aefbd2e062 | ||
|
|
ff6f60f079 | ||
|
|
b2a34fa18f | ||
|
|
984192c200 | ||
|
|
5747426565 | ||
|
|
0f78a61082 | ||
|
|
fa852f0b7d | ||
|
|
ff9ecd1b48 | ||
|
|
620c05b6bc | ||
|
|
5fffc80367 | ||
|
|
52ce3d69b4 | ||
|
|
259592e35c | ||
|
|
8866fc3a3a | ||
|
|
3dca97a235 | ||
|
|
9511680227 | ||
|
|
acb79bcf1f | ||
|
|
75adc0a669 | ||
|
|
2ef0200276 | ||
|
|
7940a4f949 | ||
|
|
81779637ba | ||
|
|
91d6129426 | ||
|
|
d333533639 | ||
|
|
2429f79721 | ||
|
|
044626152c | ||
|
|
0d7643ceb1 | ||
|
|
0e581ebf6f | ||
|
|
2fcfa6a001 | ||
|
|
546dfb74d3 | ||
|
|
a02a5a19c7 | ||
|
|
09b67f7dc6 | ||
|
|
731584cbd3 | ||
|
|
25a994213f | ||
|
|
c4a9f4c97e | ||
|
|
a56d0d4d58 | ||
|
|
9f01265981 | ||
|
|
1e96d85f88 | ||
|
|
a668a6deff | ||
|
|
9ae47ffaa4 | ||
|
|
8d1c6f69ca | ||
|
|
4bcc36489b | ||
|
|
e9e2bf759a | ||
|
|
c6e3af8ac8 | ||
|
|
5ab2ac455d | ||
|
|
ddc3aff29b | ||
|
|
8f75d7c40c | ||
|
|
3c02e4fbc4 | ||
|
|
5b2b3a63ab | ||
|
|
b96e3d9364 | ||
|
|
f9636ce89c | ||
|
|
c1b7585cd5 | ||
|
|
6f350a33d5 | ||
|
|
b3efc1087a | ||
|
|
e57a99cf6a | ||
|
|
571de7556d | ||
|
|
2ffa39e7cb | ||
|
|
1aba513a05 | ||
|
|
5d0d1f105e | ||
|
|
cb95f86b08 | ||
|
|
7028aa3baa | ||
|
|
94314af51a | ||
|
|
b587a2d30f | ||
|
|
f2e482aa2e |
31
.github/workflows/linux.yml
vendored
Normal file
31
.github/workflows/linux.yml
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
name: compile xfrpc in ubuntu-latest
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
# Allows you to run this workflow manually from the Actions tab
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: install other depend lib
|
||||
run: |
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y libjson-c-dev
|
||||
sudo apt-get install -y libevent-dev
|
||||
|
||||
- name: compile xfrpc
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -37,9 +37,10 @@ CMakeFiles/
|
||||
CMakeCache.txt
|
||||
Makefile
|
||||
cmake_install.cmake
|
||||
install_manifest.txt
|
||||
|
||||
# bin generated
|
||||
xfrp_client
|
||||
xfrpc
|
||||
xfrp_test_server
|
||||
bin
|
||||
.vscode
|
||||
|
||||
@@ -2,24 +2,41 @@ cmake_minimum_required(VERSION 2.6)
|
||||
|
||||
project(xfrp C)
|
||||
|
||||
set(src_xfrp_client
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
|
||||
|
||||
find_package(LibEvent)
|
||||
if(NOT LibEvent_FOUND)
|
||||
message(FATAL_ERROR "libevent2 not found!")
|
||||
endif(NOT LibEvent_FOUND)
|
||||
|
||||
find_package(OpenSSL)
|
||||
if(NOT OPENSSL_FOUND)
|
||||
message(FATAL_ERROR "OpenSSL not found!")
|
||||
endif(NOT OPENSSL_FOUND)
|
||||
|
||||
find_package(JSON-C REQUIRED)
|
||||
include_directories(${JSON-C_INCLUDE_DIR})
|
||||
|
||||
set(src_xfrpc
|
||||
main.c
|
||||
client.c
|
||||
config.c
|
||||
control.c
|
||||
frame.c
|
||||
ini.c
|
||||
msg.c
|
||||
xfrp_client.c
|
||||
xfrpc.c
|
||||
debug.c
|
||||
zip.c
|
||||
commandline.c
|
||||
crypto.c
|
||||
fastpbkdf2.c
|
||||
utils.c
|
||||
session.c
|
||||
common.c
|
||||
login.c
|
||||
proxy_tcp.c
|
||||
proxy_ftp.c
|
||||
proxy.c
|
||||
tcpmux.c
|
||||
)
|
||||
|
||||
set(libs
|
||||
@@ -34,11 +51,11 @@ set(test_libs
|
||||
event
|
||||
)
|
||||
|
||||
ADD_DEFINITIONS(-Wall -g --std=gnu99 -Wmissing-declarations)
|
||||
ADD_DEFINITIONS(-Wall -g --std=gnu99)
|
||||
|
||||
add_executable(xfrp_client ${src_xfrp_client})
|
||||
target_link_libraries(xfrp_client ${libs})
|
||||
add_executable(xfrpc ${src_xfrpc})
|
||||
target_link_libraries(xfrpc ${libs})
|
||||
|
||||
install(TARGETS xfrp_client
|
||||
install(TARGETS xfrpc
|
||||
RUNTIME DESTINATION bin
|
||||
)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Contributing
|
||||
================================================================================
|
||||
|
||||
If you want to contribute to [xfrp](https://github.com/kuntengrom/xfrp), please follow these simple rules:
|
||||
If you want to contribute to [xfrpc](https://github.com/liudf0716/xfrpc), please follow these simple rules:
|
||||
|
||||
1. Press the fork button:
|
||||
|
||||
@@ -27,7 +27,7 @@ If you want to contribute to [xfrp](https://github.com/kuntengrom/xfrp), please
|
||||
6. Commit and push your changes, then make a pull request from Github.
|
||||
|
||||
git commit --signoff
|
||||
git push -f
|
||||
git push
|
||||
|
||||
7. Awaiting review, if accepted, merged!
|
||||
|
||||
|
||||
231
README.md
231
README.md
@@ -1,73 +1,199 @@
|
||||

|
||||

|
||||
|
||||
[![Build Status][1]][2]
|
||||
[![license][3]][4]
|
||||
[![Supported][7]][8]
|
||||
[![PRs Welcome][5]][6]
|
||||
[![Issue Welcome][9]][10]
|
||||
[![OpenWRT][11]][12]
|
||||
[![KunTeng][13]][14]
|
||||
|
||||
[1]: https://img.shields.io/travis/KunTengRom/xfrp.svg?style=plastic
|
||||
[2]: https://travis-ci.org/KunTengRom/xfrp
|
||||
[3]: https://img.shields.io/badge/license-GPLV3-brightgreen.svg?style=plastic
|
||||
[4]: https://github.com/KunTengRom/xfrp/blob/master/LICENSE
|
||||
[5]: https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=plastic
|
||||
[6]: https://github.com/KunTengRom/xfrp/pulls
|
||||
[7]: https://img.shields.io/badge/XFRPS-Supported-blue.svg?style=plastic
|
||||
[8]: https://github.com/KunTengRom/xfrps
|
||||
[9]: https://img.shields.io/badge/Issues-welcome-brightgreen.svg?style=plastic
|
||||
[10]: https://github.com/KunTengRom/xfrp/issues/new
|
||||
[11]: https://img.shields.io/badge/Platform-%20OpenWRT%20%7CLEDE%20-brightgreen.svg?style=plastic
|
||||
[12]: https://github.com/KunTengRom/LEDE
|
||||
[13]: https://img.shields.io/badge/KunTeng-Inside-blue.svg?style=plastic
|
||||
[14]: http://rom.kunteng.org
|
||||
## What is xfrpc
|
||||
|
||||
## What is xfrp and why start xfrp
|
||||
`xfrpc` is [frp](https://github.com/fatedier/frp) client implemented by c language for [OpenWRT](https://github.com/openwrt/openwrt)
|
||||
The motivation to start xfrpc project is that we are OpenWRTer, and openwrt usually run in devices which have limit ROM and RAM space, however frpc always need more space and memory; therefore we launched xfrpc project.
|
||||
|
||||
xfrp was [xfrps](https://github.com/KunTengRom/xfrp) client implemented by c for OpenWRT system
|
||||
## Development Status
|
||||
|
||||
The motivation to start xfrp project is that we are OpenWRTer, and openwrt usually ran in device which has little ROM and RAM space, however golang always need more space and memory; therefore we start xfrp project
|
||||
xfrpc partially compitable with latest frp release feature, It targets to fully compatible with latest frp release.
|
||||
|
||||
## Compile
|
||||
the following table is detail compatible feature:
|
||||
|
||||
| Feature | xfrpc | frpc |
|
||||
| ------------- | ------------- | ---------|
|
||||
| tcp | Yes | Yes |
|
||||
| tcpmux | Yes | Yes |
|
||||
| http | Yes | Yes |
|
||||
| https | Yes | Yes |
|
||||
| subdomain | No | Yes |
|
||||
| use_encryption | No | Yes |
|
||||
| use_compression | No | Yes |
|
||||
| udp | No | Yes |
|
||||
| p2p | No | Yes |
|
||||
| xtcp | No | Yes |
|
||||
| vistor | No | Yes |
|
||||
|
||||
|
||||
|
||||
## Architecture
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
## Sequence Diagram
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
title: xfrpc与frps通信交互时序图
|
||||
participant 本地服务
|
||||
participant xfrpc
|
||||
participant frps
|
||||
participant 远程访问用户
|
||||
|
||||
xfrpc ->> frps : TypeLogin Message
|
||||
frps ->> xfrpc : TypeLoginResp Message
|
||||
Note right of frps : 根据Login信息里面的pool值,决定给xfrpc发送几条TypeReqWorkConn请求信息
|
||||
frps ->> xfrpc : frps aes-128-cfb iv[16] data
|
||||
frps -->> xfrpc : TypeReqWorkConn Message
|
||||
loop 根据Login中的PoolCount创建工作连接数
|
||||
xfrpc -->> frps : TypeNewWorkConn Message
|
||||
Note left of xfrpc : 与服务器创建代理服务工作连接,并请求新的工作连接请求
|
||||
Note right of frps : 处理xfrpc端发送的TypeNewWorkConn消息,注册该工作连接到连接池中
|
||||
frps ->> xfrpc : TypeStartWorkConn Message
|
||||
Note left of xfrpc : 将新创建的工作连接与代理的本地服务连接做绑定
|
||||
end
|
||||
xfrpc ->> frps : xfrpc aes-128-cfb iv[16] data
|
||||
loop 用户配置的代理服务数
|
||||
xfrpc -->> frps : TypeNewProxy Message
|
||||
frps -->> xfrpc : NewProxyResp Message
|
||||
end
|
||||
|
||||
loop 心跳包检查
|
||||
xfrpc -->> frps : TypePing Message
|
||||
frps -->> xfrpc : TypePong Message
|
||||
end
|
||||
|
||||
远程访问用户 ->> frps : 发起访问
|
||||
frps ->> xfrpc : TypeStartWorkconn Message
|
||||
loop 远程访问用户与本地服务之间的交互过程
|
||||
frps ->> xfrpc : 用户数据
|
||||
xfrpc ->> 本地服务 : 用户数据
|
||||
本地服务 ->> xfrpc : 本地服务数据
|
||||
xfrpc ->> frps : 本地服务数据
|
||||
frps ->> 远程访问用户 : 本地服务数据
|
||||
end
|
||||
|
||||
```
|
||||
|
||||
## Compile on Ubuntu 20.04.3 LTS
|
||||
|
||||
xfrp need [libevent](https://github.com/libevent/libevent) [openssl-dev](https://github.com/openssl/openssl) and [json-c](https://github.com/json-c/json-c) support
|
||||
|
||||
Before compile xfrp, please install `libevent` `openssl-dev` and `json-c` in your system.
|
||||
Before compile xfrp, please install `libevent` and `json-c` in your system.
|
||||
|
||||
Install json-c libevent in ubuntu 20.04 LTS
|
||||
|
||||
```shell
|
||||
git clone https://github.com/KunTengRom/xfrp.git
|
||||
sudo apt-get install -y libjson-c-dev
|
||||
sudo apt-get install -y libevent-dev
|
||||
```
|
||||
|
||||
```shell
|
||||
git clone https://github.com/liudf0716/xfrpc.git
|
||||
cd xfrp
|
||||
cmake .
|
||||
mkdir build
|
||||
cmake ..
|
||||
make
|
||||
```
|
||||
|
||||
## Compile on OpenWrt
|
||||
|
||||
xfrpc was recruited by openwrt community since version 1.04.515
|
||||
|
||||
anyway I highly recommend you to use latest version
|
||||
|
||||
in order to compile xfrpc in openwrt sdk environment, you should firstly `make menuconfig`, then select `Network --> Web Servers/Proxies ---> xfrpc`
|
||||
|
||||
## Quick start
|
||||
|
||||
**before using xfrpc, you should get frps server: [frps](https://github.com/fatedier/frp/releases)**
|
||||
|
||||
Run in debug mode :
|
||||
+ frps
|
||||
|
||||
```shell
|
||||
xfrp_client -c frpc_mini.ini -f -d 7
|
||||
frps use latest release 0.42.0
|
||||
|
||||
```
|
||||
# frps.ini
|
||||
[common]
|
||||
bind_port = 7000
|
||||
```
|
||||
|
||||
Run in release mode :
|
||||
run frps
|
||||
|
||||
```shell
|
||||
xfrp_client -c frpc_mini.ini -d 0
|
||||
```
|
||||
./frps -c frps.ini
|
||||
```
|
||||
|
||||
----
|
||||
+ xfrpc tcp
|
||||
|
||||
## Todo list
|
||||
```
|
||||
#xfrpc_mini.ini
|
||||
[common]
|
||||
server_addr = your_server_ip
|
||||
server_port = 7000
|
||||
|
||||
- support compression
|
||||
- support encrypt
|
||||
[ssh]
|
||||
type = tcp
|
||||
local_ip = 127.0.0.1
|
||||
local_port = 22
|
||||
remote_port = 6128
|
||||
```
|
||||
|
||||
+ xfrpc http&https
|
||||
|
||||
compare with supporting tcp, supporting http&https need to add vhost_http_port&vhost_https_port in frps.ini as the following
|
||||
|
||||
```
|
||||
# frps.ini
|
||||
[common]
|
||||
bind_port = 7000
|
||||
vhost_http_port = 80
|
||||
vhost_https_port = 443
|
||||
```
|
||||
|
||||
```
|
||||
# xfrpc_mini.ini
|
||||
[common]
|
||||
server_addr = x.x.x.x
|
||||
server_port = 7000
|
||||
|
||||
[http]
|
||||
type = http
|
||||
local_port = 80
|
||||
custom_domains = www.example.com
|
||||
|
||||
[https]
|
||||
type = https
|
||||
local_port = 443
|
||||
custom_domains = www.example.com
|
||||
```
|
||||
|
||||
+ Run in debug mode
|
||||
|
||||
```shell
|
||||
xfrpc -c frpc_mini.ini -f -d 7
|
||||
```
|
||||
|
||||
+ Run in release mode :
|
||||
|
||||
```shell
|
||||
xfrpc -c frpc_mini.ini -d 0
|
||||
```
|
||||
|
||||
## Openwrt luci configure ui
|
||||
|
||||
If running xfrpc in openwrt box, [luci-app-xfrpc](https://github.com/liudf0716/luci-app-xfrpc) is a good choice
|
||||
|
||||
luci-app-xfrpc was recruited by [luci project](https://github.com/openwrt/luci)
|
||||
|
||||
## How to contribute our project
|
||||
|
||||
See [CONTRIBUTING](https://github.com/KunTengRom/xfrp/blob/master/CONTRIBUTING.md) for details on submitting patches and the contribution workflow.
|
||||
See [CONTRIBUTING](https://github.com/liudf0716/xfrpc/blob/master/CONTRIBUTING.md) for details on submitting patches and the contribution workflow.
|
||||
|
||||
## Contact
|
||||
|
||||
@@ -75,3 +201,28 @@ QQ群 : [331230369](https://jq.qq.com/?_wv=1027&k=47QGEhL)
|
||||
|
||||
|
||||
## Please support us and star our project
|
||||
|
||||
[](https://star-history.com/#liudf0716/xfrpc&Date)
|
||||
|
||||
## 打赏
|
||||
|
||||
支付宝打赏
|
||||
|
||||

|
||||
|
||||
|
||||
微信打赏
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
<!--
|
||||
|
||||
## 广告
|
||||
|
||||
想学习OpenWrt开发,但是摸不着门道?自学没毅力?基础太差?怕太难学不会?跟着佐大学OpenWrt开发入门培训班助你能学有所成
|
||||
|
||||
报名地址:https://forgotfun.org/2018/04/openwrt-training-2018.html
|
||||
|
||||
-->
|
||||
|
||||
10
bin/frpc.ini
10
bin/frpc.ini
@@ -1,10 +0,0 @@
|
||||
[common]
|
||||
server_addr = 127.0.0.1
|
||||
server_port = 7001
|
||||
tcp_mux = false
|
||||
|
||||
[G_22]
|
||||
type = tcp
|
||||
local_port = 22
|
||||
remote_port = 20099
|
||||
|
||||
255
client.c
255
client.c
@@ -21,7 +21,7 @@
|
||||
|
||||
/** @file client.c
|
||||
@brief client surrogate for local service
|
||||
@author Copyright (C) 2016 Dengfeng Liu <liudengfeng@kunteng.org>
|
||||
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
@@ -29,20 +29,12 @@
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <syslog.h>
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
#include <event2/bufferevent.h>
|
||||
#include <event2/buffer.h>
|
||||
#include <event2/listener.h>
|
||||
#include <event2/util.h>
|
||||
#include <event2/event.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "client.h"
|
||||
@@ -52,190 +44,149 @@
|
||||
#include "const.h"
|
||||
#include "uthash.h"
|
||||
#include "zip.h"
|
||||
#include "msg.h"
|
||||
#include "common.h"
|
||||
#include "proxy.h"
|
||||
#include "utils.h"
|
||||
#include "tcpmux.h"
|
||||
|
||||
#define MAX_OUTPUT (512*1024)
|
||||
|
||||
static void drained_writecb(struct bufferevent *bev, void *ctx);
|
||||
static void xfrp_event_cb(struct bufferevent *bev, short what, void *ctx);
|
||||
static struct proxy_client *all_pc = NULL;
|
||||
|
||||
static void
|
||||
xfrp_read_cb(struct bufferevent *bev, void *ctx)
|
||||
xfrp_worker_event_cb(struct bufferevent *bev, short what, void *ctx)
|
||||
{
|
||||
struct bufferevent *partner = ctx;
|
||||
struct evbuffer *src, *dst;
|
||||
size_t len;
|
||||
src = bufferevent_get_input(bev);
|
||||
len = evbuffer_get_length(src);
|
||||
if (!partner) {
|
||||
evbuffer_drain(src, len);
|
||||
return;
|
||||
}
|
||||
dst = bufferevent_get_output(partner);
|
||||
evbuffer_add_buffer(dst, src);
|
||||
|
||||
if (evbuffer_get_length(dst) >= MAX_OUTPUT) {
|
||||
/* We're giving the other side data faster than it can
|
||||
* pass it on. Stop reading here until we have drained the
|
||||
* other side to MAX_OUTPUT/2 bytes. */
|
||||
bufferevent_setcb(partner, xfrp_read_cb, drained_writecb,
|
||||
xfrp_event_cb, bev);
|
||||
bufferevent_setwatermark(partner, EV_WRITE, MAX_OUTPUT/2,
|
||||
MAX_OUTPUT);
|
||||
bufferevent_disable(bev, EV_READ);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
drained_writecb(struct bufferevent *bev, void *ctx)
|
||||
{
|
||||
struct bufferevent *partner = ctx;
|
||||
|
||||
/* We were choking the other side until we drained our outbuf a bit.
|
||||
* Now it seems drained. */
|
||||
bufferevent_setcb(bev, xfrp_read_cb, NULL, xfrp_event_cb, partner);
|
||||
bufferevent_setwatermark(bev, EV_WRITE, 0, 0);
|
||||
if (partner)
|
||||
bufferevent_enable(partner, EV_READ);
|
||||
}
|
||||
|
||||
static void
|
||||
close_on_finished_writecb(struct bufferevent *bev, void *ctx)
|
||||
{
|
||||
struct evbuffer *b = bufferevent_get_output(bev);
|
||||
|
||||
if (evbuffer_get_length(b) == 0) {
|
||||
if (what & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) {
|
||||
debug(LOG_DEBUG, "working connection closed!");
|
||||
bufferevent_free(bev);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xfrp_event_cb(struct bufferevent *bev, short what, void *ctx)
|
||||
static void
|
||||
xfrp_proxy_event_cb(struct bufferevent *bev, short what, void *ctx)
|
||||
{
|
||||
struct bufferevent *partner = ctx;
|
||||
struct proxy_client *client = ctx;
|
||||
assert(client);
|
||||
|
||||
if (what & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) {
|
||||
debug(LOG_DEBUG, "working connection closed");
|
||||
if (partner) {
|
||||
/* Flush all pending data */
|
||||
xfrp_read_cb(bev, ctx);
|
||||
|
||||
if (evbuffer_get_length(bufferevent_get_output(partner))) {
|
||||
/* We still have to flush data from the other
|
||||
* side, but when that's done, close the other
|
||||
* side. */
|
||||
bufferevent_setcb(partner,
|
||||
NULL, close_on_finished_writecb,
|
||||
xfrp_event_cb, NULL);
|
||||
|
||||
bufferevent_disable(partner, EV_READ);
|
||||
} else {
|
||||
/* We have nothing left to say to the other
|
||||
* side; close it. */
|
||||
bufferevent_free(partner);
|
||||
}
|
||||
debug(LOG_DEBUG, "xfrpc proxy close connect server [%s:%d] stream_id %d: %s",
|
||||
client->ps->local_ip, client->ps->local_port,
|
||||
client->stream_id, strerror(errno));
|
||||
tmux_stream_close(client->ctl_bev, &client->stream);
|
||||
} else if (what & BEV_EVENT_CONNECTED) {
|
||||
debug(LOG_DEBUG, "client [%d] connected", client->stream_id);
|
||||
//client->stream.state = ESTABLISHED;
|
||||
if (client->data_tail_size > 0) {
|
||||
debug(LOG_DEBUG, "send client data ...");
|
||||
send_client_data_tail(client);
|
||||
}
|
||||
bufferevent_free(bev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xfrp_decrypt_cb(struct bufferevent *bev, void *ctx)
|
||||
int
|
||||
is_ftp_proxy(const struct proxy_service *ps)
|
||||
{
|
||||
struct bufferevent *partner = ctx;
|
||||
struct evbuffer *src, *dst;
|
||||
src = bufferevent_get_input(bev);
|
||||
dst = bufferevent_get_output(partner);
|
||||
evbuffer_add_buffer(dst, src);
|
||||
}
|
||||
if (! ps || ! ps->proxy_type)
|
||||
return 0;
|
||||
|
||||
static void
|
||||
xfrp_encrypt_cb(struct bufferevent *bev, void *ctx)
|
||||
{
|
||||
struct bufferevent *partner = ctx;
|
||||
struct evbuffer *src, *dst;
|
||||
size_t len;
|
||||
src = bufferevent_get_input(bev);
|
||||
len = evbuffer_get_length(src);
|
||||
if (len > 0) {
|
||||
dst = bufferevent_get_output(partner);
|
||||
evbuffer_add_buffer(dst, src);
|
||||
}
|
||||
if (0 == strcmp(ps->proxy_type, "ftp") && ps->remote_data_port > 0)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// create frp tunnel for service
|
||||
void start_frp_tunnel(struct proxy_client *client)
|
||||
void
|
||||
start_xfrp_tunnel(struct proxy_client *client)
|
||||
{
|
||||
if (! client->ctl_bev) {
|
||||
debug(LOG_ERR, "proxy client control bev is invalid!");
|
||||
return;
|
||||
}
|
||||
|
||||
struct event_base *base = client->base;
|
||||
struct common_conf *c_conf = get_common_config();
|
||||
struct proxy_service *ps = client->ps;
|
||||
if (! ps) {
|
||||
|
||||
if ( !base ) {
|
||||
debug(LOG_ERR, "service event base get failed");
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !ps ) {
|
||||
debug(LOG_ERR, "service tunnel started failed, no proxy service resource.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (! ps->local_port) {
|
||||
if ( !ps->local_port ) {
|
||||
debug(LOG_ERR, "service tunnel started failed, proxy service resource unvalid.");
|
||||
return;
|
||||
}
|
||||
|
||||
client->local_proxy_bev = connect_server(base, ps->local_ip, ps->local_port);
|
||||
if (!client->local_proxy_bev) {
|
||||
if ( !client->local_proxy_bev ) {
|
||||
debug(LOG_ERR, "frpc tunnel connect local proxy port [%d] failed!", ps->local_port);
|
||||
bufferevent_free(client->ctl_bev);
|
||||
del_proxy_client(client);
|
||||
return;
|
||||
}
|
||||
|
||||
debug(LOG_DEBUG, "proxy server [%s:%d] <---> client [%s:%d]",
|
||||
c_conf->server_addr,
|
||||
c_conf->server_port,
|
||||
ps->remote_port,
|
||||
ps->local_ip ? ps->local_ip:"::1",
|
||||
ps->local_port);
|
||||
|
||||
bufferevent_setcb(client->ctl_bev,
|
||||
xfrp_decrypt_cb,
|
||||
bufferevent_data_cb proxy_s2c_recv, proxy_c2s_recv;
|
||||
if (is_ftp_proxy(client->ps)) {
|
||||
proxy_c2s_recv = ftp_proxy_c2s_cb;
|
||||
proxy_s2c_recv = ftp_proxy_s2c_cb;
|
||||
} else {
|
||||
proxy_c2s_recv = tcp_proxy_c2s_cb; // local service ---> xfrpc
|
||||
proxy_s2c_recv = tcp_proxy_s2c_cb; // frps ---> xfrpc
|
||||
}
|
||||
|
||||
if (!c_conf->tcp_mux) {
|
||||
bufferevent_setcb(client->ctl_bev,
|
||||
proxy_s2c_recv,
|
||||
NULL,
|
||||
xfrp_event_cb,
|
||||
client->local_proxy_bev);
|
||||
xfrp_worker_event_cb,
|
||||
client);
|
||||
bufferevent_enable(client->ctl_bev, EV_READ|EV_WRITE);
|
||||
}
|
||||
|
||||
bufferevent_setcb(client->local_proxy_bev,
|
||||
xfrp_encrypt_cb,
|
||||
proxy_c2s_recv,
|
||||
NULL,
|
||||
xfrp_event_cb,
|
||||
client->ctl_bev);
|
||||
xfrp_proxy_event_cb,
|
||||
client);
|
||||
|
||||
bufferevent_enable(client->ctl_bev, EV_READ|EV_WRITE);
|
||||
bufferevent_enable(client->local_proxy_bev, EV_READ|EV_WRITE);
|
||||
}
|
||||
|
||||
int send_client_data_tail(struct proxy_client *client)
|
||||
int
|
||||
send_client_data_tail(struct proxy_client *client)
|
||||
{
|
||||
int send_l = 0;
|
||||
if (client->data_tail && client->data_tail_size && client->local_proxy_bev) {
|
||||
send_l = bufferevent_write(client->local_proxy_bev, client->data_tail, client->data_tail_size);
|
||||
client->data_tail = NULL;
|
||||
client->data_tail_size = 0;
|
||||
}
|
||||
|
||||
return send_l;
|
||||
}
|
||||
|
||||
void free_proxy_client(struct proxy_client *client)
|
||||
static void
|
||||
free_proxy_client(struct proxy_client *client)
|
||||
{
|
||||
if (client->name) free(client->name);
|
||||
if (client->local_ip) free(client->local_ip);
|
||||
if (client->custom_domains) free(client->custom_domains);
|
||||
if (client->locations) free(client->locations);
|
||||
|
||||
free_base_config(client->bconf);
|
||||
|
||||
evtimer_del(client->ev_timeout);
|
||||
debug(LOG_DEBUG, "free client %d", client->stream_id);
|
||||
if (client->local_proxy_bev) bufferevent_free(client->local_proxy_bev);
|
||||
free(client);
|
||||
}
|
||||
|
||||
void del_proxy_client(struct proxy_client *client)
|
||||
void
|
||||
del_proxy_client(struct proxy_client *client)
|
||||
{
|
||||
struct proxy_client *all_pc = get_all_pc();
|
||||
if (!client || !all_pc ) {
|
||||
debug(LOG_INFO, "Error: all_pc or client is NULL");
|
||||
debug(LOG_INFO, "all_pc or client is NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -244,11 +195,43 @@ void del_proxy_client(struct proxy_client *client)
|
||||
free_proxy_client(client);
|
||||
}
|
||||
|
||||
// Return NULL if proxy service not found with proxy_name
|
||||
struct proxy_service *get_proxy_service(const char *proxy_name)
|
||||
void
|
||||
del_proxy_client_by_stream_id(uint32_t sid)
|
||||
{
|
||||
struct proxy_service *ps = NULL;
|
||||
struct proxy_service *all_ps = get_all_proxy_services();
|
||||
HASH_FIND_STR(all_ps, proxy_name, ps);
|
||||
return ps;
|
||||
}
|
||||
del_stream(sid);
|
||||
|
||||
struct proxy_client *pc = get_proxy_client(sid);
|
||||
del_proxy_client(pc);
|
||||
}
|
||||
|
||||
struct proxy_client *
|
||||
get_proxy_client(uint32_t sid)
|
||||
{
|
||||
struct proxy_client *pc = NULL;
|
||||
HASH_FIND_INT(all_pc, &sid, pc);
|
||||
return pc;
|
||||
}
|
||||
|
||||
struct proxy_client *
|
||||
new_proxy_client()
|
||||
{
|
||||
struct proxy_client *client = calloc(1, sizeof(struct proxy_client));
|
||||
assert(client);
|
||||
client->stream_id = get_next_session_id();
|
||||
init_tmux_stream(&client->stream, client->stream_id, INIT);
|
||||
HASH_ADD_INT(all_pc, stream_id, client);
|
||||
|
||||
return client;
|
||||
}
|
||||
|
||||
void
|
||||
clear_all_proxy_client()
|
||||
{
|
||||
if (!all_pc) return;
|
||||
|
||||
struct proxy_client *client, *tmp;
|
||||
HASH_ITER(hh, all_pc, client, tmp) {
|
||||
HASH_DEL(all_pc, client);
|
||||
free_proxy_client(client);
|
||||
}
|
||||
}
|
||||
|
||||
50
client.h
50
client.h
@@ -20,8 +20,8 @@
|
||||
\********************************************************************/
|
||||
|
||||
/** @file client.h
|
||||
@brief xfrp client proxy client related
|
||||
@author Copyright (C) 2016 Dengfeng Liu <liudengfeng@kunteng.org>
|
||||
@brief xfrpc proxy client related
|
||||
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
|
||||
*/
|
||||
|
||||
#ifndef _CLIENT_H_
|
||||
@@ -31,6 +31,7 @@
|
||||
|
||||
#include "uthash.h"
|
||||
#include "common.h"
|
||||
#include "tcpmux.h"
|
||||
|
||||
struct event_base;
|
||||
struct base_conf;
|
||||
@@ -40,43 +41,32 @@ struct proxy_service;
|
||||
|
||||
struct proxy_client {
|
||||
struct event_base *base;
|
||||
struct bufferevent *ctl_bev;
|
||||
struct bufferevent *local_proxy_bev;
|
||||
struct event *ev_timeout;
|
||||
|
||||
struct bufferevent *ctl_bev; // xfrpc proxy <---> frps
|
||||
struct bufferevent *local_proxy_bev; // xfrpc proxy <---> local service
|
||||
struct base_conf *bconf;
|
||||
char *name; // pointer to bconf->name
|
||||
char *local_ip;
|
||||
char *type;
|
||||
int local_port;
|
||||
int remote_port;
|
||||
int use_encryption;
|
||||
int use_compression;
|
||||
struct tmux_stream stream;
|
||||
|
||||
char *custom_domains;
|
||||
char *subdomain;
|
||||
char *locations;
|
||||
char *host_header_rewrite;
|
||||
char *http_user;
|
||||
char *http_pwd;
|
||||
|
||||
//provate arguments
|
||||
UT_hash_handle hh;
|
||||
uint32_t stream_id;
|
||||
int connected;
|
||||
int work_started;
|
||||
struct proxy_service *ps;
|
||||
unsigned char *data_tail; // storage untrated data
|
||||
unsigned char *data_tail; // storage untreated data
|
||||
size_t data_tail_size;
|
||||
|
||||
// private arguments
|
||||
UT_hash_handle hh;
|
||||
};
|
||||
|
||||
struct proxy_service {
|
||||
char *proxy_name;
|
||||
char *proxy_type;
|
||||
char *ftp_cfg_proxy_name;
|
||||
int use_encryption;
|
||||
int use_compression;
|
||||
|
||||
char *local_ip;
|
||||
int remote_port;
|
||||
int remote_data_port;
|
||||
int local_port;
|
||||
|
||||
// http and https only
|
||||
@@ -87,7 +77,7 @@ struct proxy_service {
|
||||
char *http_user;
|
||||
char *http_pwd;
|
||||
|
||||
//provate arguments
|
||||
// private arguments
|
||||
UT_hash_handle hh;
|
||||
};
|
||||
|
||||
@@ -96,14 +86,20 @@ struct proxy_service {
|
||||
// when xfrp client receive that request, it will start
|
||||
// frp tunnel
|
||||
// if client has data-tail(not NULL), client value will be changed
|
||||
void start_frp_tunnel(struct proxy_client *client);
|
||||
void start_xfrp_tunnel(struct proxy_client *client);
|
||||
|
||||
void del_proxy_client(struct proxy_client *client);
|
||||
|
||||
void free_proxy_client(struct proxy_client *client);
|
||||
void del_proxy_client_by_stream_id(uint32_t sid);
|
||||
|
||||
struct proxy_service *get_proxy_service(const char *proxy_name);
|
||||
struct proxy_client *get_proxy_client(uint32_t sid);
|
||||
|
||||
int send_client_data_tail(struct proxy_client *client);
|
||||
|
||||
int is_ftp_proxy(const struct proxy_service *ps);
|
||||
|
||||
struct proxy_client *new_proxy_client();
|
||||
|
||||
void clear_all_proxy_client();
|
||||
|
||||
#endif //_CLIENT_H_
|
||||
|
||||
161
cmake/Modules/CMakeParseArguments.cmake
Normal file
161
cmake/Modules/CMakeParseArguments.cmake
Normal file
@@ -0,0 +1,161 @@
|
||||
#.rst:
|
||||
# CMakeParseArguments
|
||||
# -------------------
|
||||
#
|
||||
#
|
||||
#
|
||||
# CMAKE_PARSE_ARGUMENTS(<prefix> <options> <one_value_keywords>
|
||||
# <multi_value_keywords> args...)
|
||||
#
|
||||
# CMAKE_PARSE_ARGUMENTS() is intended to be used in macros or functions
|
||||
# for parsing the arguments given to that macro or function. It
|
||||
# processes the arguments and defines a set of variables which hold the
|
||||
# values of the respective options.
|
||||
#
|
||||
# The <options> argument contains all options for the respective macro,
|
||||
# i.e. keywords which can be used when calling the macro without any
|
||||
# value following, like e.g. the OPTIONAL keyword of the install()
|
||||
# command.
|
||||
#
|
||||
# The <one_value_keywords> argument contains all keywords for this macro
|
||||
# which are followed by one value, like e.g. DESTINATION keyword of the
|
||||
# install() command.
|
||||
#
|
||||
# The <multi_value_keywords> argument contains all keywords for this
|
||||
# macro which can be followed by more than one value, like e.g. the
|
||||
# TARGETS or FILES keywords of the install() command.
|
||||
#
|
||||
# When done, CMAKE_PARSE_ARGUMENTS() will have defined for each of the
|
||||
# keywords listed in <options>, <one_value_keywords> and
|
||||
# <multi_value_keywords> a variable composed of the given <prefix>
|
||||
# followed by "_" and the name of the respective keyword. These
|
||||
# variables will then hold the respective value from the argument list.
|
||||
# For the <options> keywords this will be TRUE or FALSE.
|
||||
#
|
||||
# All remaining arguments are collected in a variable
|
||||
# <prefix>_UNPARSED_ARGUMENTS, this can be checked afterwards to see
|
||||
# whether your macro was called with unrecognized parameters.
|
||||
#
|
||||
# As an example here a my_install() macro, which takes similar arguments
|
||||
# as the real install() command:
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# function(MY_INSTALL)
|
||||
# set(options OPTIONAL FAST)
|
||||
# set(oneValueArgs DESTINATION RENAME)
|
||||
# set(multiValueArgs TARGETS CONFIGURATIONS)
|
||||
# cmake_parse_arguments(MY_INSTALL "${options}" "${oneValueArgs}"
|
||||
# "${multiValueArgs}" ${ARGN} )
|
||||
# ...
|
||||
#
|
||||
#
|
||||
#
|
||||
# Assume my_install() has been called like this:
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# my_install(TARGETS foo bar DESTINATION bin OPTIONAL blub)
|
||||
#
|
||||
#
|
||||
#
|
||||
# After the cmake_parse_arguments() call the macro will have set the
|
||||
# following variables:
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# MY_INSTALL_OPTIONAL = TRUE
|
||||
# MY_INSTALL_FAST = FALSE (this option was not used when calling my_install()
|
||||
# MY_INSTALL_DESTINATION = "bin"
|
||||
# MY_INSTALL_RENAME = "" (was not used)
|
||||
# MY_INSTALL_TARGETS = "foo;bar"
|
||||
# MY_INSTALL_CONFIGURATIONS = "" (was not used)
|
||||
# MY_INSTALL_UNPARSED_ARGUMENTS = "blub" (no value expected after "OPTIONAL"
|
||||
#
|
||||
#
|
||||
#
|
||||
# You can then continue and process these variables.
|
||||
#
|
||||
# Keywords terminate lists of values, e.g. if directly after a
|
||||
# one_value_keyword another recognized keyword follows, this is
|
||||
# interpreted as the beginning of the new option. E.g.
|
||||
# my_install(TARGETS foo DESTINATION OPTIONAL) would result in
|
||||
# MY_INSTALL_DESTINATION set to "OPTIONAL", but MY_INSTALL_DESTINATION
|
||||
# would be empty and MY_INSTALL_OPTIONAL would be set to TRUE therefor.
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2010 Alexander Neundorf <neundorf@kde.org>
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
# see accompanying file Copyright.txt for details.
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
# (To distribute this file outside of CMake, substitute the full
|
||||
# License text for the above reference.)
|
||||
|
||||
|
||||
if(__CMAKE_PARSE_ARGUMENTS_INCLUDED)
|
||||
return()
|
||||
endif()
|
||||
set(__CMAKE_PARSE_ARGUMENTS_INCLUDED TRUE)
|
||||
|
||||
|
||||
function(CMAKE_PARSE_ARGUMENTS prefix _optionNames _singleArgNames _multiArgNames)
|
||||
# first set all result variables to empty/FALSE
|
||||
foreach(arg_name ${_singleArgNames} ${_multiArgNames})
|
||||
set(${prefix}_${arg_name})
|
||||
endforeach()
|
||||
|
||||
foreach(option ${_optionNames})
|
||||
set(${prefix}_${option} FALSE)
|
||||
endforeach()
|
||||
|
||||
set(${prefix}_UNPARSED_ARGUMENTS)
|
||||
|
||||
set(insideValues FALSE)
|
||||
set(currentArgName)
|
||||
|
||||
# now iterate over all arguments and fill the result variables
|
||||
foreach(currentArg ${ARGN})
|
||||
list(FIND _optionNames "${currentArg}" optionIndex) # ... then this marks the end of the arguments belonging to this keyword
|
||||
list(FIND _singleArgNames "${currentArg}" singleArgIndex) # ... then this marks the end of the arguments belonging to this keyword
|
||||
list(FIND _multiArgNames "${currentArg}" multiArgIndex) # ... then this marks the end of the arguments belonging to this keyword
|
||||
|
||||
if(${optionIndex} EQUAL -1 AND ${singleArgIndex} EQUAL -1 AND ${multiArgIndex} EQUAL -1)
|
||||
if(insideValues)
|
||||
if("${insideValues}" STREQUAL "SINGLE")
|
||||
set(${prefix}_${currentArgName} ${currentArg})
|
||||
set(insideValues FALSE)
|
||||
elseif("${insideValues}" STREQUAL "MULTI")
|
||||
list(APPEND ${prefix}_${currentArgName} ${currentArg})
|
||||
endif()
|
||||
else()
|
||||
list(APPEND ${prefix}_UNPARSED_ARGUMENTS ${currentArg})
|
||||
endif()
|
||||
else()
|
||||
if(NOT ${optionIndex} EQUAL -1)
|
||||
set(${prefix}_${currentArg} TRUE)
|
||||
set(insideValues FALSE)
|
||||
elseif(NOT ${singleArgIndex} EQUAL -1)
|
||||
set(currentArgName ${currentArg})
|
||||
set(${prefix}_${currentArgName})
|
||||
set(insideValues "SINGLE")
|
||||
elseif(NOT ${multiArgIndex} EQUAL -1)
|
||||
set(currentArgName ${currentArg})
|
||||
set(${prefix}_${currentArgName})
|
||||
set(insideValues "MULTI")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
endforeach()
|
||||
|
||||
# propagate the result variables to the caller:
|
||||
foreach(arg_name ${_singleArgNames} ${_multiArgNames} ${_optionNames})
|
||||
set(${prefix}_${arg_name} ${${prefix}_${arg_name}} PARENT_SCOPE)
|
||||
endforeach()
|
||||
set(${prefix}_UNPARSED_ARGUMENTS ${${prefix}_UNPARSED_ARGUMENTS} PARENT_SCOPE)
|
||||
|
||||
endfunction()
|
||||
21
cmake/Modules/FindJSON-C.cmake
Normal file
21
cmake/Modules/FindJSON-C.cmake
Normal file
@@ -0,0 +1,21 @@
|
||||
# JSON-C_FOUND - true if library and headers were found
|
||||
# JSON-C_INCLUDE_DIRS - include directories
|
||||
# JSON-C_LIBRARIES - library directories
|
||||
|
||||
find_package(PkgConfig)
|
||||
pkg_check_modules(PC_JSON-C QUIET json-c)
|
||||
|
||||
find_path(JSON-C_INCLUDE_DIR json.h
|
||||
HINTS ${PC_JSON-C_INCLUDEDIR} ${PC_JSON-C_INCLUDE_DIRS} PATH_SUFFIXES json-c json)
|
||||
|
||||
find_library(JSON-C_LIBRARY NAMES json-c libjson-c
|
||||
HINTS ${PC_JSON-C_LIBDIR} ${PC_JSON-C_LIBRARY_DIRS})
|
||||
|
||||
set(JSON-C_LIBRARIES ${JSON-C_LIBRARY})
|
||||
set(JSON-C_INCLUDE_DIRS ${JSON-C_INCLUDE_DIR})
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
find_package_handle_standard_args(JSON-C DEFAULT_MSG JSON-C_LIBRARY JSON-C_INCLUDE_DIR)
|
||||
|
||||
mark_as_advanced(JSON-C_INCLUDE_DIR JSON-C_LIBRARY)
|
||||
39
cmake/Modules/FindLibEvent.cmake
Normal file
39
cmake/Modules/FindLibEvent.cmake
Normal file
@@ -0,0 +1,39 @@
|
||||
# - Find LibEvent (a cross event library)
|
||||
# This module defines
|
||||
# LIBEVENT_INCLUDE_DIR, where to find LibEvent headers
|
||||
# LIBEVENT_LIB, LibEvent libraries
|
||||
# LibEvent_FOUND, If false, do not try to use libevent
|
||||
|
||||
set(LibEvent_EXTRA_PREFIXES /usr/local /opt/local "$ENV{HOME}")
|
||||
foreach(prefix ${LibEvent_EXTRA_PREFIXES})
|
||||
list(APPEND LibEvent_INCLUDE_PATHS "${prefix}/include")
|
||||
list(APPEND LibEvent_LIB_PATHS "${prefix}/lib")
|
||||
endforeach()
|
||||
|
||||
FIND_PATH(LIBEVENT_INCLUDE_DIR event.h PATHS ${LibEvent_INCLUDE_PATHS})
|
||||
|
||||
FIND_LIBRARY(LIBEVENT_LIB NAMES event PATHS ${LibEvent_LIB_PATHS})
|
||||
FIND_LIBRARY(LIBEVENT_CORE_LIB NAMES event_core PATHS ${LibEvent_LIB_PATHS})
|
||||
FIND_LIBRARY(LIBEVENT_PTHREADS_LIB NAMES event_pthreads PATHS ${LibEvent_LIB_PATHS})
|
||||
FIND_LIBRARY(LIBEVENT_EXTRA_LIB NAMES event_extra PATHS ${LibEvent_LIB_PATHS})
|
||||
FIND_LIBRARY(LIBEVENT_OPENSSL_LIB NAMES event_openssl PATHS ${LibEvent_LIB_PATHS})
|
||||
|
||||
if (LIBEVENT_LIB AND LIBEVENT_INCLUDE_DIR)
|
||||
set(LibEvent_FOUND TRUE)
|
||||
set(LIBEVENT_LIB ${LIBEVENT_LIB})
|
||||
else ()
|
||||
set(LibEvent_FOUND FALSE)
|
||||
endif ()
|
||||
|
||||
if (LibEvent_FOUND)
|
||||
if (NOT LibEvent_FIND_QUIETLY)
|
||||
message(STATUS "Found libevent: ${LIBEVENT_LIB}")
|
||||
endif ()
|
||||
else ()
|
||||
if (LibEvent_FIND_REQUIRED)
|
||||
message(FATAL_ERROR "Could NOT find libevent.")
|
||||
endif ()
|
||||
message(STATUS "libevent NOT found.")
|
||||
endif ()
|
||||
|
||||
MARK_AS_ADVANCED(LIBEVENT_INCLUDE_DIR LIBEVENT_LIB LIBEVENT_PTHREADS_LIB LIBEVENT_OPENSSL_LIB LIBEVENT_CORE_LIB LIBEVENT_EXTRA_LIB)
|
||||
359
cmake/Modules/FindOpenSSL.cmake
Normal file
359
cmake/Modules/FindOpenSSL.cmake
Normal file
@@ -0,0 +1,359 @@
|
||||
#.rst:
|
||||
# FindOpenSSL
|
||||
# -----------
|
||||
#
|
||||
# Try to find the OpenSSL encryption library
|
||||
#
|
||||
# Once done this will define
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# OPENSSL_ROOT_DIR - Set this variable to the root installation of OpenSSL
|
||||
#
|
||||
#
|
||||
#
|
||||
# Read-Only variables:
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# OPENSSL_FOUND - System has the OpenSSL library
|
||||
# OPENSSL_INCLUDE_DIR - The OpenSSL include directory
|
||||
# OPENSSL_CRYPTO_LIBRARY - The OpenSSL crypto library
|
||||
# OPENSSL_SSL_LIBRARY - The OpenSSL SSL library
|
||||
# OPENSSL_LIBRARIES - All OpenSSL libraries
|
||||
# OPENSSL_VERSION - This is set to $major.$minor.$revision$patch (eg. 0.9.8s)
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2006-2009 Kitware, Inc.
|
||||
# Copyright 2006 Alexander Neundorf <neundorf@kde.org>
|
||||
# Copyright 2009-2011 Mathieu Malaterre <mathieu.malaterre@gmail.com>
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
# see accompanying file Copyright.txt for details.
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
# (To distribute this file outside of CMake, substitute the full
|
||||
# License text for the above reference.)
|
||||
|
||||
if (UNIX)
|
||||
find_package(PkgConfig QUIET)
|
||||
pkg_check_modules(_OPENSSL QUIET openssl)
|
||||
endif ()
|
||||
|
||||
if (WIN32)
|
||||
# http://www.slproweb.com/products/Win32OpenSSL.html
|
||||
set(_OPENSSL_ROOT_HINTS
|
||||
${OPENSSL_ROOT_DIR}
|
||||
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\OpenSSL (32-bit)_is1;Inno Setup: App Path]"
|
||||
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\OpenSSL (64-bit)_is1;Inno Setup: App Path]"
|
||||
ENV OPENSSL_ROOT_DIR
|
||||
)
|
||||
file(TO_CMAKE_PATH "$ENV{PROGRAMFILES}" _programfiles)
|
||||
set(_OPENSSL_ROOT_PATHS
|
||||
"${_programfiles}/OpenSSL"
|
||||
"${_programfiles}/OpenSSL-Win32"
|
||||
"${_programfiles}/OpenSSL-Win64"
|
||||
"C:/OpenSSL/"
|
||||
"C:/OpenSSL-Win32/"
|
||||
"C:/OpenSSL-Win64/"
|
||||
)
|
||||
unset(_programfiles)
|
||||
else ()
|
||||
set(_OPENSSL_ROOT_HINTS
|
||||
${OPENSSL_ROOT_DIR}
|
||||
ENV OPENSSL_ROOT_DIR
|
||||
)
|
||||
endif ()
|
||||
|
||||
set(_OPENSSL_ROOT_HINTS_AND_PATHS
|
||||
HINTS ${_OPENSSL_ROOT_HINTS}
|
||||
PATHS ${_OPENSSL_ROOT_PATHS}
|
||||
)
|
||||
|
||||
find_path(OPENSSL_INCLUDE_DIR
|
||||
NAMES
|
||||
openssl/ssl.h
|
||||
${_OPENSSL_ROOT_HINTS_AND_PATHS}
|
||||
HINTS
|
||||
${_OPENSSL_INCLUDEDIR}
|
||||
PATH_SUFFIXES
|
||||
include
|
||||
)
|
||||
|
||||
if(WIN32 AND NOT CYGWIN)
|
||||
if(MSVC)
|
||||
# /MD and /MDd are the standard values - if someone wants to use
|
||||
# others, the libnames have to change here too
|
||||
# use also ssl and ssleay32 in debug as fallback for openssl < 0.9.8b
|
||||
# TODO: handle /MT and static lib
|
||||
# In Visual C++ naming convention each of these four kinds of Windows libraries has it's standard suffix:
|
||||
# * MD for dynamic-release
|
||||
# * MDd for dynamic-debug
|
||||
# * MT for static-release
|
||||
# * MTd for static-debug
|
||||
|
||||
# Implementation details:
|
||||
# We are using the libraries located in the VC subdir instead of the parent directory eventhough :
|
||||
# libeay32MD.lib is identical to ../libeay32.lib, and
|
||||
# ssleay32MD.lib is identical to ../ssleay32.lib
|
||||
find_library(LIB_EAY_DEBUG
|
||||
NAMES
|
||||
libeay32MDd
|
||||
libeay32d
|
||||
${_OPENSSL_ROOT_HINTS_AND_PATHS}
|
||||
PATH_SUFFIXES
|
||||
"lib"
|
||||
"VC"
|
||||
"lib/VC"
|
||||
)
|
||||
|
||||
find_library(LIB_EAY_RELEASE
|
||||
NAMES
|
||||
libeay32MD
|
||||
libeay32
|
||||
${_OPENSSL_ROOT_HINTS_AND_PATHS}
|
||||
PATH_SUFFIXES
|
||||
"lib"
|
||||
"VC"
|
||||
"lib/VC"
|
||||
)
|
||||
|
||||
find_library(SSL_EAY_DEBUG
|
||||
NAMES
|
||||
ssleay32MDd
|
||||
ssleay32d
|
||||
${_OPENSSL_ROOT_HINTS_AND_PATHS}
|
||||
PATH_SUFFIXES
|
||||
"lib"
|
||||
"VC"
|
||||
"lib/VC"
|
||||
)
|
||||
|
||||
find_library(SSL_EAY_RELEASE
|
||||
NAMES
|
||||
ssleay32MD
|
||||
ssleay32
|
||||
ssl
|
||||
${_OPENSSL_ROOT_HINTS_AND_PATHS}
|
||||
PATH_SUFFIXES
|
||||
"lib"
|
||||
"VC"
|
||||
"lib/VC"
|
||||
)
|
||||
|
||||
set(LIB_EAY_LIBRARY_DEBUG "${LIB_EAY_DEBUG}")
|
||||
set(LIB_EAY_LIBRARY_RELEASE "${LIB_EAY_RELEASE}")
|
||||
set(SSL_EAY_LIBRARY_DEBUG "${SSL_EAY_DEBUG}")
|
||||
set(SSL_EAY_LIBRARY_RELEASE "${SSL_EAY_RELEASE}")
|
||||
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake)
|
||||
select_library_configurations(LIB_EAY)
|
||||
select_library_configurations(SSL_EAY)
|
||||
|
||||
mark_as_advanced(LIB_EAY_LIBRARY_DEBUG LIB_EAY_LIBRARY_RELEASE
|
||||
SSL_EAY_LIBRARY_DEBUG SSL_EAY_LIBRARY_RELEASE)
|
||||
set( OPENSSL_SSL_LIBRARY ${SSL_EAY_LIBRARY} )
|
||||
set( OPENSSL_CRYPTO_LIBRARY ${LIB_EAY_LIBRARY} )
|
||||
set( OPENSSL_LIBRARIES ${SSL_EAY_LIBRARY} ${LIB_EAY_LIBRARY} )
|
||||
elseif(MINGW)
|
||||
# same player, for MinGW
|
||||
set(LIB_EAY_NAMES libeay32)
|
||||
set(SSL_EAY_NAMES ssleay32)
|
||||
if(CMAKE_CROSSCOMPILING)
|
||||
list(APPEND LIB_EAY_NAMES crypto)
|
||||
list(APPEND SSL_EAY_NAMES ssl)
|
||||
endif()
|
||||
find_library(LIB_EAY
|
||||
NAMES
|
||||
${LIB_EAY_NAMES}
|
||||
${_OPENSSL_ROOT_HINTS_AND_PATHS}
|
||||
PATH_SUFFIXES
|
||||
"lib"
|
||||
"lib/MinGW"
|
||||
)
|
||||
|
||||
find_library(SSL_EAY
|
||||
NAMES
|
||||
${SSL_EAY_NAMES}
|
||||
${_OPENSSL_ROOT_HINTS_AND_PATHS}
|
||||
PATH_SUFFIXES
|
||||
"lib"
|
||||
"lib/MinGW"
|
||||
)
|
||||
|
||||
mark_as_advanced(SSL_EAY LIB_EAY)
|
||||
set( OPENSSL_SSL_LIBRARY ${SSL_EAY} )
|
||||
set( OPENSSL_CRYPTO_LIBRARY ${LIB_EAY} )
|
||||
set( OPENSSL_LIBRARIES ${SSL_EAY} ${LIB_EAY} )
|
||||
unset(LIB_EAY_NAMES)
|
||||
unset(SSL_EAY_NAMES)
|
||||
else()
|
||||
# Not sure what to pick for -say- intel, let's use the toplevel ones and hope someone report issues:
|
||||
find_library(LIB_EAY
|
||||
NAMES
|
||||
libeay32
|
||||
${_OPENSSL_ROOT_HINTS_AND_PATHS}
|
||||
HINTS
|
||||
${_OPENSSL_LIBDIR}
|
||||
PATH_SUFFIXES
|
||||
lib
|
||||
)
|
||||
|
||||
find_library(SSL_EAY
|
||||
NAMES
|
||||
ssleay32
|
||||
${_OPENSSL_ROOT_HINTS_AND_PATHS}
|
||||
HINTS
|
||||
${_OPENSSL_LIBDIR}
|
||||
PATH_SUFFIXES
|
||||
lib
|
||||
)
|
||||
|
||||
mark_as_advanced(SSL_EAY LIB_EAY)
|
||||
set( OPENSSL_SSL_LIBRARY ${SSL_EAY} )
|
||||
set( OPENSSL_CRYPTO_LIBRARY ${LIB_EAY} )
|
||||
set( OPENSSL_LIBRARIES ${SSL_EAY} ${LIB_EAY} )
|
||||
endif()
|
||||
else()
|
||||
|
||||
find_library(OPENSSL_SSL_LIBRARY
|
||||
NAMES
|
||||
ssl
|
||||
ssleay32
|
||||
ssleay32MD
|
||||
${_OPENSSL_ROOT_HINTS_AND_PATHS}
|
||||
HINTS
|
||||
${_OPENSSL_LIBDIR}
|
||||
PATH_SUFFIXES
|
||||
lib
|
||||
)
|
||||
|
||||
find_library(OPENSSL_CRYPTO_LIBRARY
|
||||
NAMES
|
||||
crypto
|
||||
${_OPENSSL_ROOT_HINTS_AND_PATHS}
|
||||
HINTS
|
||||
${_OPENSSL_LIBDIR}
|
||||
PATH_SUFFIXES
|
||||
lib
|
||||
)
|
||||
|
||||
mark_as_advanced(OPENSSL_CRYPTO_LIBRARY OPENSSL_SSL_LIBRARY)
|
||||
|
||||
# compat defines
|
||||
set(OPENSSL_SSL_LIBRARIES ${OPENSSL_SSL_LIBRARY})
|
||||
set(OPENSSL_CRYPTO_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})
|
||||
|
||||
set(OPENSSL_LIBRARIES ${OPENSSL_SSL_LIBRARY} ${OPENSSL_CRYPTO_LIBRARY})
|
||||
|
||||
endif()
|
||||
|
||||
function(from_hex HEX DEC)
|
||||
string(TOUPPER "${HEX}" HEX)
|
||||
set(_res 0)
|
||||
string(LENGTH "${HEX}" _strlen)
|
||||
|
||||
while (_strlen GREATER 0)
|
||||
math(EXPR _res "${_res} * 16")
|
||||
string(SUBSTRING "${HEX}" 0 1 NIBBLE)
|
||||
string(SUBSTRING "${HEX}" 1 -1 HEX)
|
||||
if (NIBBLE STREQUAL "A")
|
||||
math(EXPR _res "${_res} + 10")
|
||||
elseif (NIBBLE STREQUAL "B")
|
||||
math(EXPR _res "${_res} + 11")
|
||||
elseif (NIBBLE STREQUAL "C")
|
||||
math(EXPR _res "${_res} + 12")
|
||||
elseif (NIBBLE STREQUAL "D")
|
||||
math(EXPR _res "${_res} + 13")
|
||||
elseif (NIBBLE STREQUAL "E")
|
||||
math(EXPR _res "${_res} + 14")
|
||||
elseif (NIBBLE STREQUAL "F")
|
||||
math(EXPR _res "${_res} + 15")
|
||||
else()
|
||||
math(EXPR _res "${_res} + ${NIBBLE}")
|
||||
endif()
|
||||
|
||||
string(LENGTH "${HEX}" _strlen)
|
||||
endwhile()
|
||||
|
||||
set(${DEC} ${_res} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
if(OPENSSL_INCLUDE_DIR AND EXISTS "${OPENSSL_INCLUDE_DIR}/openssl/opensslv.h")
|
||||
file(STRINGS "${OPENSSL_INCLUDE_DIR}/openssl/opensslv.h" openssl_version_str
|
||||
REGEX "^#[\t ]*define[\t ]+OPENSSL_VERSION_NUMBER[\t ]+0x([0-9a-fA-F])+.*")
|
||||
|
||||
if(openssl_version_str)
|
||||
# The version number is encoded as 0xMNNFFPPS: major minor fix patch status
|
||||
# The status gives if this is a developer or prerelease and is ignored here.
|
||||
# Major, minor, and fix directly translate into the version numbers shown in
|
||||
# the string. The patch field translates to the single character suffix that
|
||||
# indicates the bug fix state, which 00 -> nothing, 01 -> a, 02 -> b and so
|
||||
# on.
|
||||
|
||||
string(REGEX REPLACE "^.*OPENSSL_VERSION_NUMBER[\t ]+0x([0-9a-fA-F])([0-9a-fA-F][0-9a-fA-F])([0-9a-fA-F][0-9a-fA-F])([0-9a-fA-F][0-9a-fA-F])([0-9a-fA-F]).*$"
|
||||
"\\1;\\2;\\3;\\4;\\5" OPENSSL_VERSION_LIST "${openssl_version_str}")
|
||||
list(GET OPENSSL_VERSION_LIST 0 OPENSSL_VERSION_MAJOR)
|
||||
list(GET OPENSSL_VERSION_LIST 1 OPENSSL_VERSION_MINOR)
|
||||
from_hex("${OPENSSL_VERSION_MINOR}" OPENSSL_VERSION_MINOR)
|
||||
list(GET OPENSSL_VERSION_LIST 2 OPENSSL_VERSION_FIX)
|
||||
from_hex("${OPENSSL_VERSION_FIX}" OPENSSL_VERSION_FIX)
|
||||
list(GET OPENSSL_VERSION_LIST 3 OPENSSL_VERSION_PATCH)
|
||||
|
||||
if (NOT OPENSSL_VERSION_PATCH STREQUAL "00")
|
||||
from_hex("${OPENSSL_VERSION_PATCH}" _tmp)
|
||||
# 96 is the ASCII code of 'a' minus 1
|
||||
math(EXPR OPENSSL_VERSION_PATCH_ASCII "${_tmp} + 96")
|
||||
unset(_tmp)
|
||||
# Once anyone knows how OpenSSL would call the patch versions beyond 'z'
|
||||
# this should be updated to handle that, too. This has not happened yet
|
||||
# so it is simply ignored here for now.
|
||||
string(ASCII "${OPENSSL_VERSION_PATCH_ASCII}" OPENSSL_VERSION_PATCH_STRING)
|
||||
endif ()
|
||||
|
||||
set(OPENSSL_VERSION "${OPENSSL_VERSION_MAJOR}.${OPENSSL_VERSION_MINOR}.${OPENSSL_VERSION_FIX}${OPENSSL_VERSION_PATCH_STRING}")
|
||||
else ()
|
||||
# Since OpenSSL 3.0.0, the new version format is MAJOR.MINOR.PATCH and
|
||||
# a new OPENSSL_VERSION_STR macro contains exactly that
|
||||
file(STRINGS "${OPENSSL_INCLUDE_DIR}/openssl/opensslv.h" OPENSSL_VERSION_STR
|
||||
REGEX "^#[\t ]*define[\t ]+OPENSSL_VERSION_STR[\t ]+\"([0-9])+\\.([0-9])+\\.([0-9])+\".*")
|
||||
string(REGEX REPLACE "^.*OPENSSL_VERSION_STR[\t ]+\"([0-9]+\\.[0-9]+\\.[0-9]+)\".*$"
|
||||
"\\1" OPENSSL_VERSION_STR "${OPENSSL_VERSION_STR}")
|
||||
|
||||
set(OPENSSL_VERSION "${OPENSSL_VERSION_STR}")
|
||||
|
||||
# Setting OPENSSL_VERSION_MAJOR OPENSSL_VERSION_MINOR and OPENSSL_VERSION_FIX
|
||||
string(REGEX MATCHALL "([0-9])+" OPENSSL_VERSION_NUMBER "${OPENSSL_VERSION}")
|
||||
list(POP_FRONT OPENSSL_VERSION_NUMBER
|
||||
OPENSSL_VERSION_MAJOR
|
||||
OPENSSL_VERSION_MINOR
|
||||
OPENSSL_VERSION_FIX)
|
||||
|
||||
unset(OPENSSL_VERSION_NUMBER)
|
||||
unset(OPENSSL_VERSION_STR)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
|
||||
|
||||
if (OPENSSL_VERSION)
|
||||
find_package_handle_standard_args(OpenSSL
|
||||
REQUIRED_VARS
|
||||
OPENSSL_LIBRARIES
|
||||
OPENSSL_INCLUDE_DIR
|
||||
VERSION_VAR
|
||||
OPENSSL_VERSION
|
||||
FAIL_MESSAGE
|
||||
"Could NOT find OpenSSL, try to set the path to OpenSSL root folder in the system variable OPENSSL_ROOT_DIR"
|
||||
)
|
||||
else ()
|
||||
find_package_handle_standard_args(OpenSSL "Could NOT find OpenSSL, try to set the path to OpenSSL root folder in the system variable OPENSSL_ROOT_DIR"
|
||||
OPENSSL_LIBRARIES
|
||||
OPENSSL_INCLUDE_DIR
|
||||
)
|
||||
endif ()
|
||||
|
||||
mark_as_advanced(OPENSSL_INCLUDE_DIR OPENSSL_LIBRARIES)
|
||||
382
cmake/Modules/FindPackageHandleStandardArgs.cmake
Normal file
382
cmake/Modules/FindPackageHandleStandardArgs.cmake
Normal file
@@ -0,0 +1,382 @@
|
||||
#.rst:
|
||||
# FindPackageHandleStandardArgs
|
||||
# -----------------------------
|
||||
#
|
||||
#
|
||||
#
|
||||
# FIND_PACKAGE_HANDLE_STANDARD_ARGS(<name> ... )
|
||||
#
|
||||
# This function is intended to be used in FindXXX.cmake modules files.
|
||||
# It handles the REQUIRED, QUIET and version-related arguments to
|
||||
# find_package(). It also sets the <packagename>_FOUND variable. The
|
||||
# package is considered found if all variables <var1>... listed contain
|
||||
# valid results, e.g. valid filepaths.
|
||||
#
|
||||
# There are two modes of this function. The first argument in both
|
||||
# modes is the name of the Find-module where it is called (in original
|
||||
# casing).
|
||||
#
|
||||
# The first simple mode looks like this:
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# FIND_PACKAGE_HANDLE_STANDARD_ARGS(<name>
|
||||
# (DEFAULT_MSG|"Custom failure message") <var1>...<varN> )
|
||||
#
|
||||
# If the variables <var1> to <varN> are all valid, then
|
||||
# <UPPERCASED_NAME>_FOUND will be set to TRUE. If DEFAULT_MSG is given
|
||||
# as second argument, then the function will generate itself useful
|
||||
# success and error messages. You can also supply a custom error
|
||||
# message for the failure case. This is not recommended.
|
||||
#
|
||||
# The second mode is more powerful and also supports version checking:
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# FIND_PACKAGE_HANDLE_STANDARD_ARGS(<NAME>
|
||||
# [FOUND_VAR <resultVar>]
|
||||
# [REQUIRED_VARS <var1>...<varN>]
|
||||
# [VERSION_VAR <versionvar>]
|
||||
# [HANDLE_COMPONENTS]
|
||||
# [CONFIG_MODE]
|
||||
# [FAIL_MESSAGE "Custom failure message"] )
|
||||
#
|
||||
# In this mode, the name of the result-variable can be set either to
|
||||
# either <UPPERCASED_NAME>_FOUND or <OriginalCase_Name>_FOUND using the
|
||||
# FOUND_VAR option. Other names for the result-variable are not
|
||||
# allowed. So for a Find-module named FindFooBar.cmake, the two
|
||||
# possible names are FooBar_FOUND and FOOBAR_FOUND. It is recommended
|
||||
# to use the original case version. If the FOUND_VAR option is not
|
||||
# used, the default is <UPPERCASED_NAME>_FOUND.
|
||||
#
|
||||
# As in the simple mode, if <var1> through <varN> are all valid,
|
||||
# <packagename>_FOUND will be set to TRUE. After REQUIRED_VARS the
|
||||
# variables which are required for this package are listed. Following
|
||||
# VERSION_VAR the name of the variable can be specified which holds the
|
||||
# version of the package which has been found. If this is done, this
|
||||
# version will be checked against the (potentially) specified required
|
||||
# version used in the find_package() call. The EXACT keyword is also
|
||||
# handled. The default messages include information about the required
|
||||
# version and the version which has been actually found, both if the
|
||||
# version is ok or not. If the package supports components, use the
|
||||
# HANDLE_COMPONENTS option to enable handling them. In this case,
|
||||
# find_package_handle_standard_args() will report which components have
|
||||
# been found and which are missing, and the <packagename>_FOUND variable
|
||||
# will be set to FALSE if any of the required components (i.e. not the
|
||||
# ones listed after OPTIONAL_COMPONENTS) are missing. Use the option
|
||||
# CONFIG_MODE if your FindXXX.cmake module is a wrapper for a
|
||||
# find_package(... NO_MODULE) call. In this case VERSION_VAR will be
|
||||
# set to <NAME>_VERSION and the macro will automatically check whether
|
||||
# the Config module was found. Via FAIL_MESSAGE a custom failure
|
||||
# message can be specified, if this is not used, the default message
|
||||
# will be displayed.
|
||||
#
|
||||
# Example for mode 1:
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# find_package_handle_standard_args(LibXml2 DEFAULT_MSG
|
||||
# LIBXML2_LIBRARY LIBXML2_INCLUDE_DIR)
|
||||
#
|
||||
#
|
||||
#
|
||||
# LibXml2 is considered to be found, if both LIBXML2_LIBRARY and
|
||||
# LIBXML2_INCLUDE_DIR are valid. Then also LIBXML2_FOUND is set to
|
||||
# TRUE. If it is not found and REQUIRED was used, it fails with
|
||||
# FATAL_ERROR, independent whether QUIET was used or not. If it is
|
||||
# found, success will be reported, including the content of <var1>. On
|
||||
# repeated Cmake runs, the same message won't be printed again.
|
||||
#
|
||||
# Example for mode 2:
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# find_package_handle_standard_args(LibXslt
|
||||
# FOUND_VAR LibXslt_FOUND
|
||||
# REQUIRED_VARS LibXslt_LIBRARIES LibXslt_INCLUDE_DIRS
|
||||
# VERSION_VAR LibXslt_VERSION_STRING)
|
||||
#
|
||||
# In this case, LibXslt is considered to be found if the variable(s)
|
||||
# listed after REQUIRED_VAR are all valid, i.e. LibXslt_LIBRARIES and
|
||||
# LibXslt_INCLUDE_DIRS in this case. The result will then be stored in
|
||||
# LibXslt_FOUND . Also the version of LibXslt will be checked by using
|
||||
# the version contained in LibXslt_VERSION_STRING. Since no
|
||||
# FAIL_MESSAGE is given, the default messages will be printed.
|
||||
#
|
||||
# Another example for mode 2:
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# find_package(Automoc4 QUIET NO_MODULE HINTS /opt/automoc4)
|
||||
# find_package_handle_standard_args(Automoc4 CONFIG_MODE)
|
||||
#
|
||||
# In this case, FindAutmoc4.cmake wraps a call to find_package(Automoc4
|
||||
# NO_MODULE) and adds an additional search directory for automoc4. Here
|
||||
# the result will be stored in AUTOMOC4_FOUND. The following
|
||||
# FIND_PACKAGE_HANDLE_STANDARD_ARGS() call produces a proper
|
||||
# success/error message.
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2007-2009 Kitware, Inc.
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
# see accompanying file Copyright.txt for details.
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
# (To distribute this file outside of CMake, substitute the full
|
||||
# License text for the above reference.)
|
||||
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/FindPackageMessage.cmake)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/CMakeParseArguments.cmake)
|
||||
|
||||
# internal helper macro
|
||||
macro(_FPHSA_FAILURE_MESSAGE _msg)
|
||||
if (${_NAME}_FIND_REQUIRED)
|
||||
message(FATAL_ERROR "${_msg}")
|
||||
else ()
|
||||
if (NOT ${_NAME}_FIND_QUIETLY)
|
||||
message(STATUS "${_msg}")
|
||||
endif ()
|
||||
endif ()
|
||||
endmacro()
|
||||
|
||||
|
||||
# internal helper macro to generate the failure message when used in CONFIG_MODE:
|
||||
macro(_FPHSA_HANDLE_FAILURE_CONFIG_MODE)
|
||||
# <name>_CONFIG is set, but FOUND is false, this means that some other of the REQUIRED_VARS was not found:
|
||||
if(${_NAME}_CONFIG)
|
||||
_FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: missing: ${MISSING_VARS} (found ${${_NAME}_CONFIG} ${VERSION_MSG})")
|
||||
else()
|
||||
# If _CONSIDERED_CONFIGS is set, the config-file has been found, but no suitable version.
|
||||
# List them all in the error message:
|
||||
if(${_NAME}_CONSIDERED_CONFIGS)
|
||||
set(configsText "")
|
||||
list(LENGTH ${_NAME}_CONSIDERED_CONFIGS configsCount)
|
||||
math(EXPR configsCount "${configsCount} - 1")
|
||||
foreach(currentConfigIndex RANGE ${configsCount})
|
||||
list(GET ${_NAME}_CONSIDERED_CONFIGS ${currentConfigIndex} filename)
|
||||
list(GET ${_NAME}_CONSIDERED_VERSIONS ${currentConfigIndex} version)
|
||||
set(configsText "${configsText} ${filename} (version ${version})\n")
|
||||
endforeach()
|
||||
if (${_NAME}_NOT_FOUND_MESSAGE)
|
||||
set(configsText "${configsText} Reason given by package: ${${_NAME}_NOT_FOUND_MESSAGE}\n")
|
||||
endif()
|
||||
_FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} ${VERSION_MSG}, checked the following files:\n${configsText}")
|
||||
|
||||
else()
|
||||
# Simple case: No Config-file was found at all:
|
||||
_FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: found neither ${_NAME}Config.cmake nor ${_NAME_LOWER}-config.cmake ${VERSION_MSG}")
|
||||
endif()
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
|
||||
function(FIND_PACKAGE_HANDLE_STANDARD_ARGS _NAME _FIRST_ARG)
|
||||
|
||||
# set up the arguments for CMAKE_PARSE_ARGUMENTS and check whether we are in
|
||||
# new extended or in the "old" mode:
|
||||
set(options CONFIG_MODE HANDLE_COMPONENTS)
|
||||
set(oneValueArgs FAIL_MESSAGE VERSION_VAR FOUND_VAR)
|
||||
set(multiValueArgs REQUIRED_VARS)
|
||||
set(_KEYWORDS_FOR_EXTENDED_MODE ${options} ${oneValueArgs} ${multiValueArgs} )
|
||||
list(FIND _KEYWORDS_FOR_EXTENDED_MODE "${_FIRST_ARG}" INDEX)
|
||||
|
||||
if(${INDEX} EQUAL -1)
|
||||
set(FPHSA_FAIL_MESSAGE ${_FIRST_ARG})
|
||||
set(FPHSA_REQUIRED_VARS ${ARGN})
|
||||
set(FPHSA_VERSION_VAR)
|
||||
else()
|
||||
|
||||
CMAKE_PARSE_ARGUMENTS(FPHSA "${options}" "${oneValueArgs}" "${multiValueArgs}" ${_FIRST_ARG} ${ARGN})
|
||||
|
||||
if(FPHSA_UNPARSED_ARGUMENTS)
|
||||
message(FATAL_ERROR "Unknown keywords given to FIND_PACKAGE_HANDLE_STANDARD_ARGS(): \"${FPHSA_UNPARSED_ARGUMENTS}\"")
|
||||
endif()
|
||||
|
||||
if(NOT FPHSA_FAIL_MESSAGE)
|
||||
set(FPHSA_FAIL_MESSAGE "DEFAULT_MSG")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# now that we collected all arguments, process them
|
||||
|
||||
if("x${FPHSA_FAIL_MESSAGE}" STREQUAL "xDEFAULT_MSG")
|
||||
set(FPHSA_FAIL_MESSAGE "Could NOT find ${_NAME}")
|
||||
endif()
|
||||
|
||||
# In config-mode, we rely on the variable <package>_CONFIG, which is set by find_package()
|
||||
# when it successfully found the config-file, including version checking:
|
||||
if(FPHSA_CONFIG_MODE)
|
||||
list(INSERT FPHSA_REQUIRED_VARS 0 ${_NAME}_CONFIG)
|
||||
list(REMOVE_DUPLICATES FPHSA_REQUIRED_VARS)
|
||||
set(FPHSA_VERSION_VAR ${_NAME}_VERSION)
|
||||
endif()
|
||||
|
||||
if(NOT FPHSA_REQUIRED_VARS)
|
||||
message(FATAL_ERROR "No REQUIRED_VARS specified for FIND_PACKAGE_HANDLE_STANDARD_ARGS()")
|
||||
endif()
|
||||
|
||||
list(GET FPHSA_REQUIRED_VARS 0 _FIRST_REQUIRED_VAR)
|
||||
|
||||
string(TOUPPER ${_NAME} _NAME_UPPER)
|
||||
string(TOLOWER ${_NAME} _NAME_LOWER)
|
||||
|
||||
if(FPHSA_FOUND_VAR)
|
||||
if(FPHSA_FOUND_VAR MATCHES "^${_NAME}_FOUND$" OR FPHSA_FOUND_VAR MATCHES "^${_NAME_UPPER}_FOUND$")
|
||||
set(_FOUND_VAR ${FPHSA_FOUND_VAR})
|
||||
else()
|
||||
message(FATAL_ERROR "The argument for FOUND_VAR is \"${FPHSA_FOUND_VAR}\", but only \"${_NAME}_FOUND\" and \"${_NAME_UPPER}_FOUND\" are valid names.")
|
||||
endif()
|
||||
else()
|
||||
set(_FOUND_VAR ${_NAME_UPPER}_FOUND)
|
||||
endif()
|
||||
|
||||
# collect all variables which were not found, so they can be printed, so the
|
||||
# user knows better what went wrong (#6375)
|
||||
set(MISSING_VARS "")
|
||||
set(DETAILS "")
|
||||
# check if all passed variables are valid
|
||||
unset(${_FOUND_VAR})
|
||||
foreach(_CURRENT_VAR ${FPHSA_REQUIRED_VARS})
|
||||
if(NOT ${_CURRENT_VAR})
|
||||
set(${_FOUND_VAR} FALSE)
|
||||
set(MISSING_VARS "${MISSING_VARS} ${_CURRENT_VAR}")
|
||||
else()
|
||||
set(DETAILS "${DETAILS}[${${_CURRENT_VAR}}]")
|
||||
endif()
|
||||
endforeach()
|
||||
if(NOT "${${_FOUND_VAR}}" STREQUAL "FALSE")
|
||||
set(${_FOUND_VAR} TRUE)
|
||||
endif()
|
||||
|
||||
# component handling
|
||||
unset(FOUND_COMPONENTS_MSG)
|
||||
unset(MISSING_COMPONENTS_MSG)
|
||||
|
||||
if(FPHSA_HANDLE_COMPONENTS)
|
||||
foreach(comp ${${_NAME}_FIND_COMPONENTS})
|
||||
if(${_NAME}_${comp}_FOUND)
|
||||
|
||||
if(NOT DEFINED FOUND_COMPONENTS_MSG)
|
||||
set(FOUND_COMPONENTS_MSG "found components: ")
|
||||
endif()
|
||||
set(FOUND_COMPONENTS_MSG "${FOUND_COMPONENTS_MSG} ${comp}")
|
||||
|
||||
else()
|
||||
|
||||
if(NOT DEFINED MISSING_COMPONENTS_MSG)
|
||||
set(MISSING_COMPONENTS_MSG "missing components: ")
|
||||
endif()
|
||||
set(MISSING_COMPONENTS_MSG "${MISSING_COMPONENTS_MSG} ${comp}")
|
||||
|
||||
if(${_NAME}_FIND_REQUIRED_${comp})
|
||||
set(${_FOUND_VAR} FALSE)
|
||||
set(MISSING_VARS "${MISSING_VARS} ${comp}")
|
||||
endif()
|
||||
|
||||
endif()
|
||||
endforeach()
|
||||
set(COMPONENT_MSG "${FOUND_COMPONENTS_MSG} ${MISSING_COMPONENTS_MSG}")
|
||||
set(DETAILS "${DETAILS}[c${COMPONENT_MSG}]")
|
||||
endif()
|
||||
|
||||
# version handling:
|
||||
set(VERSION_MSG "")
|
||||
set(VERSION_OK TRUE)
|
||||
set(VERSION ${${FPHSA_VERSION_VAR}})
|
||||
|
||||
# check with DEFINED here as the requested or found version may be "0"
|
||||
if (DEFINED ${_NAME}_FIND_VERSION)
|
||||
if(DEFINED ${FPHSA_VERSION_VAR})
|
||||
|
||||
if(${_NAME}_FIND_VERSION_EXACT) # exact version required
|
||||
# count the dots in the version string
|
||||
string(REGEX REPLACE "[^.]" "" _VERSION_DOTS "${VERSION}")
|
||||
# add one dot because there is one dot more than there are components
|
||||
string(LENGTH "${_VERSION_DOTS}." _VERSION_DOTS)
|
||||
if (_VERSION_DOTS GREATER ${_NAME}_FIND_VERSION_COUNT)
|
||||
# Because of the C++ implementation of find_package() ${_NAME}_FIND_VERSION_COUNT
|
||||
# is at most 4 here. Therefore a simple lookup table is used.
|
||||
if (${_NAME}_FIND_VERSION_COUNT EQUAL 1)
|
||||
set(_VERSION_REGEX "[^.]*")
|
||||
elseif (${_NAME}_FIND_VERSION_COUNT EQUAL 2)
|
||||
set(_VERSION_REGEX "[^.]*\\.[^.]*")
|
||||
elseif (${_NAME}_FIND_VERSION_COUNT EQUAL 3)
|
||||
set(_VERSION_REGEX "[^.]*\\.[^.]*\\.[^.]*")
|
||||
else ()
|
||||
set(_VERSION_REGEX "[^.]*\\.[^.]*\\.[^.]*\\.[^.]*")
|
||||
endif ()
|
||||
string(REGEX REPLACE "^(${_VERSION_REGEX})\\..*" "\\1" _VERSION_HEAD "${VERSION}")
|
||||
unset(_VERSION_REGEX)
|
||||
if (NOT ${_NAME}_FIND_VERSION VERSION_EQUAL _VERSION_HEAD)
|
||||
set(VERSION_MSG "Found unsuitable version \"${VERSION}\", but required is exact version \"${${_NAME}_FIND_VERSION}\"")
|
||||
set(VERSION_OK FALSE)
|
||||
else ()
|
||||
set(VERSION_MSG "(found suitable exact version \"${VERSION}\")")
|
||||
endif ()
|
||||
unset(_VERSION_HEAD)
|
||||
else ()
|
||||
if (NOT ${_NAME}_FIND_VERSION VERSION_EQUAL VERSION)
|
||||
set(VERSION_MSG "Found unsuitable version \"${VERSION}\", but required is exact version \"${${_NAME}_FIND_VERSION}\"")
|
||||
set(VERSION_OK FALSE)
|
||||
else ()
|
||||
set(VERSION_MSG "(found suitable exact version \"${VERSION}\")")
|
||||
endif ()
|
||||
endif ()
|
||||
unset(_VERSION_DOTS)
|
||||
|
||||
else() # minimum version specified:
|
||||
if (${_NAME}_FIND_VERSION VERSION_GREATER VERSION)
|
||||
set(VERSION_MSG "Found unsuitable version \"${VERSION}\", but required is at least \"${${_NAME}_FIND_VERSION}\"")
|
||||
set(VERSION_OK FALSE)
|
||||
else ()
|
||||
set(VERSION_MSG "(found suitable version \"${VERSION}\", minimum required is \"${${_NAME}_FIND_VERSION}\")")
|
||||
endif ()
|
||||
endif()
|
||||
|
||||
else()
|
||||
|
||||
# if the package was not found, but a version was given, add that to the output:
|
||||
if(${_NAME}_FIND_VERSION_EXACT)
|
||||
set(VERSION_MSG "(Required is exact version \"${${_NAME}_FIND_VERSION}\")")
|
||||
else()
|
||||
set(VERSION_MSG "(Required is at least version \"${${_NAME}_FIND_VERSION}\")")
|
||||
endif()
|
||||
|
||||
endif()
|
||||
else ()
|
||||
if(VERSION)
|
||||
set(VERSION_MSG "(found version \"${VERSION}\")")
|
||||
endif()
|
||||
endif ()
|
||||
|
||||
if(VERSION_OK)
|
||||
set(DETAILS "${DETAILS}[v${VERSION}(${${_NAME}_FIND_VERSION})]")
|
||||
else()
|
||||
set(${_FOUND_VAR} FALSE)
|
||||
endif()
|
||||
|
||||
|
||||
# print the result:
|
||||
if (${_FOUND_VAR})
|
||||
FIND_PACKAGE_MESSAGE(${_NAME} "Found ${_NAME}: ${${_FIRST_REQUIRED_VAR}} ${VERSION_MSG} ${COMPONENT_MSG}" "${DETAILS}")
|
||||
else ()
|
||||
|
||||
if(FPHSA_CONFIG_MODE)
|
||||
_FPHSA_HANDLE_FAILURE_CONFIG_MODE()
|
||||
else()
|
||||
if(NOT VERSION_OK)
|
||||
_FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: ${VERSION_MSG} (found ${${_FIRST_REQUIRED_VAR}})")
|
||||
else()
|
||||
_FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} (missing: ${MISSING_VARS}) ${VERSION_MSG}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
endif ()
|
||||
|
||||
set(${_FOUND_VAR} ${${_FOUND_VAR}} PARENT_SCOPE)
|
||||
|
||||
endfunction()
|
||||
57
cmake/Modules/FindPackageMessage.cmake
Normal file
57
cmake/Modules/FindPackageMessage.cmake
Normal file
@@ -0,0 +1,57 @@
|
||||
#.rst:
|
||||
# FindPackageMessage
|
||||
# ------------------
|
||||
#
|
||||
#
|
||||
#
|
||||
# FIND_PACKAGE_MESSAGE(<name> "message for user" "find result details")
|
||||
#
|
||||
# This macro is intended to be used in FindXXX.cmake modules files. It
|
||||
# will print a message once for each unique find result. This is useful
|
||||
# for telling the user where a package was found. The first argument
|
||||
# specifies the name (XXX) of the package. The second argument
|
||||
# specifies the message to display. The third argument lists details
|
||||
# about the find result so that if they change the message will be
|
||||
# displayed again. The macro also obeys the QUIET argument to the
|
||||
# find_package command.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# if(X11_FOUND)
|
||||
# FIND_PACKAGE_MESSAGE(X11 "Found X11: ${X11_X11_LIB}"
|
||||
# "[${X11_X11_LIB}][${X11_INCLUDE_DIR}]")
|
||||
# else()
|
||||
# ...
|
||||
# endif()
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2008-2009 Kitware, Inc.
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
# see accompanying file Copyright.txt for details.
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
# (To distribute this file outside of CMake, substitute the full
|
||||
# License text for the above reference.)
|
||||
|
||||
function(FIND_PACKAGE_MESSAGE pkg msg details)
|
||||
# Avoid printing a message repeatedly for the same find result.
|
||||
if(NOT ${pkg}_FIND_QUIETLY)
|
||||
string(REPLACE "\n" "" details "${details}")
|
||||
set(DETAILS_VAR FIND_PACKAGE_MESSAGE_DETAILS_${pkg})
|
||||
if(NOT "${details}" STREQUAL "${${DETAILS_VAR}}")
|
||||
# The message has not yet been printed.
|
||||
message(STATUS "${msg}")
|
||||
|
||||
# Save the find details in the cache to avoid printing the same
|
||||
# message again.
|
||||
set("${DETAILS_VAR}" "${details}"
|
||||
CACHE INTERNAL "Details about finding ${pkg}")
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <syslog.h>
|
||||
#include <assert.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
@@ -38,6 +39,7 @@
|
||||
#include "commandline.h"
|
||||
#include "debug.h"
|
||||
#include "version.h"
|
||||
#include "utils.h"
|
||||
|
||||
typedef void signal_func (int);
|
||||
|
||||
@@ -108,7 +110,7 @@ get_daemon_status()
|
||||
/** @internal
|
||||
* @brief Print usage
|
||||
*
|
||||
* Prints usage, called when wifidog is run with -h or with an unknown option
|
||||
* Prints usage, called when xfrpc is run with -h or with an unknown option
|
||||
*/
|
||||
static void
|
||||
usage(const char *appname)
|
||||
@@ -121,6 +123,7 @@ usage(const char *appname)
|
||||
fprintf(stdout, " -d <level> Debug level\n");
|
||||
fprintf(stdout, " -h Print usage\n");
|
||||
fprintf(stdout, " -v Print version information\n");
|
||||
fprintf(stdout, " -r Print run id of client\n");
|
||||
fprintf(stdout, "\n");
|
||||
}
|
||||
|
||||
@@ -133,7 +136,7 @@ parse_commandline(int argc, char **argv)
|
||||
int c;
|
||||
int flag = 0;
|
||||
|
||||
while (-1 != (c = getopt(argc, argv, "c:hfd:sw:vx:i:a:"))) {
|
||||
while (-1 != (c = getopt(argc, argv, "c:hfd:sw:vrx:i:a:"))) {
|
||||
|
||||
|
||||
switch (c) {
|
||||
@@ -146,9 +149,7 @@ parse_commandline(int argc, char **argv)
|
||||
case 'c':
|
||||
if (optarg) {
|
||||
confile = strdup(optarg); //never free it
|
||||
if (! confile)
|
||||
exit(0);
|
||||
|
||||
assert(confile);
|
||||
flag = 1;
|
||||
}
|
||||
break;
|
||||
@@ -165,10 +166,28 @@ parse_commandline(int argc, char **argv)
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
fprintf(stdout, "This is %s version " VERSION "\n", argv[0]);
|
||||
fprintf(stdout, "version: " VERSION "\n");
|
||||
exit(1);
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
{
|
||||
char ifname[16] = {0};
|
||||
if(get_net_ifname(ifname, 16)){
|
||||
debug(LOG_ERR, "error: get device sign ifname failed!");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
char if_mac[64] = {0};
|
||||
if(get_net_mac(ifname, if_mac, sizeof(if_mac))) {
|
||||
debug(LOG_ERR, "error: Hard ware MAC address of [%s] get failed!", ifname);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
fprintf(stdout, "run ID:%s\n", if_mac);
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
usage(argv[0]);
|
||||
exit(1);
|
||||
|
||||
26
common.c
26
common.c
@@ -1,3 +1,29 @@
|
||||
/* vim: set et ts=4 sts=4 sw=4 : */
|
||||
/********************************************************************\
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License as *
|
||||
* published by the Free Software Foundation; either version 2 of *
|
||||
* the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License*
|
||||
* along with this program; if not, contact: *
|
||||
* *
|
||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02111-1307, USA gnu@gnu.org *
|
||||
* *
|
||||
\********************************************************************/
|
||||
|
||||
/** @file common.c
|
||||
@brief xfrp common function implemented
|
||||
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
|
||||
*/
|
||||
|
||||
#include "uthash.h"
|
||||
#include "common.h"
|
||||
|
||||
|
||||
42
common.h
42
common.h
@@ -1,3 +1,29 @@
|
||||
/* vim: set et ts=4 sts=4 sw=4 : */
|
||||
/********************************************************************\
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License as *
|
||||
* published by the Free Software Foundation; either version 2 of *
|
||||
* the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License*
|
||||
* along with this program; if not, contact: *
|
||||
* *
|
||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02111-1307, USA gnu@gnu.org *
|
||||
* *
|
||||
\********************************************************************/
|
||||
|
||||
/** @file common.h
|
||||
@brief xfrp common header
|
||||
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
|
||||
*/
|
||||
|
||||
#ifndef _COMMON_H_
|
||||
#define _COMMON_H_
|
||||
|
||||
@@ -6,10 +32,20 @@
|
||||
#include <string.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <event2/bufferevent.h>
|
||||
#include <event2/buffer.h>
|
||||
#include <event2/listener.h>
|
||||
#include <event2/util.h>
|
||||
#include <event2/event.h>
|
||||
#include <event2/dns.h>
|
||||
#include <event2/event_struct.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "uthash.h"
|
||||
|
||||
// #define BIGENDIAN_64BIT 0
|
||||
#define BIGENDIAN_32BIT 1
|
||||
#define BIGENDIAN_64BIT 1
|
||||
//#define BIGENDIAN_32BIT 1
|
||||
|
||||
#define SAFE_FREE(m) \
|
||||
if (m) free(m)
|
||||
@@ -37,4 +73,4 @@ uint64_t hton64(const uint64_t input);
|
||||
|
||||
typedef unsigned short ushort;
|
||||
|
||||
#endif //_COMMON_H_
|
||||
#endif //_COMMON_H_
|
||||
|
||||
205
config.c
205
config.c
@@ -20,8 +20,8 @@
|
||||
\********************************************************************/
|
||||
|
||||
/** @file config.c
|
||||
@brief xfrp client config related
|
||||
@author Copyright (C) 2016 Dengfeng Liu <liudengfeng@kunteng.org>
|
||||
@brief xfrpc client config related
|
||||
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -38,12 +38,13 @@
|
||||
#include "client.h"
|
||||
#include "debug.h"
|
||||
#include "msg.h"
|
||||
#include "utils.h"
|
||||
#include "version.h"
|
||||
|
||||
static struct common_conf *c_conf;
|
||||
static struct proxy_client *p_clients;
|
||||
static struct proxy_service *p_services;
|
||||
static struct proxy_service *all_ps;
|
||||
|
||||
static void new_ftp_data_proxy_service(struct proxy_service *ftp_ps);
|
||||
|
||||
struct common_conf *get_common_config()
|
||||
{
|
||||
@@ -55,36 +56,9 @@ void free_common_config()
|
||||
struct common_conf *c_conf = get_common_config();
|
||||
|
||||
if (c_conf->server_addr) free(c_conf->server_addr);
|
||||
if (c_conf->http_proxy) free(c_conf->http_proxy);
|
||||
if (c_conf->log_file) free(c_conf->log_file);
|
||||
if (c_conf->log_way) free(c_conf->log_way);
|
||||
if (c_conf->log_level) free(c_conf->log_level);
|
||||
if (c_conf->auth_token) free(c_conf->auth_token);
|
||||
if (c_conf->privilege_token) free(c_conf->privilege_token);
|
||||
};
|
||||
|
||||
void free_base_config(struct base_conf *bconf)
|
||||
{
|
||||
if (bconf->name) free(bconf->name);
|
||||
if (bconf->auth_token) free(bconf->auth_token);
|
||||
if (bconf->type) free(bconf->type);
|
||||
if (bconf->privilege_token) free(bconf->privilege_token);
|
||||
if (bconf->host_header_rewrite) free(bconf->host_header_rewrite);
|
||||
if (bconf->http_username) free(bconf->http_username);
|
||||
if (bconf->http_password) free(bconf->http_password);
|
||||
if (bconf->subdomain) free(bconf->subdomain);
|
||||
}
|
||||
|
||||
struct proxy_client *get_all_pc()
|
||||
{
|
||||
return p_clients;
|
||||
}
|
||||
|
||||
struct proxy_service *get_all_proxy_services()
|
||||
{
|
||||
return p_services;
|
||||
}
|
||||
|
||||
static int is_true(const char *val)
|
||||
{
|
||||
if (val && (strcmp(val, "true") == 0 || strcmp(val, "1") == 0))
|
||||
@@ -101,8 +75,7 @@ static const char *get_valid_type(const char *val)
|
||||
#define MATCH_VALUE(s) strcmp(val, s) == 0
|
||||
if (MATCH_VALUE("tcp") ||
|
||||
MATCH_VALUE("http") ||
|
||||
MATCH_VALUE("https") ||
|
||||
MATCH_VALUE("udp")) { // will add ftp support in here
|
||||
MATCH_VALUE("https")) {
|
||||
|
||||
return val;
|
||||
}
|
||||
@@ -112,13 +85,14 @@ static const char *get_valid_type(const char *val)
|
||||
|
||||
static void dump_common_conf()
|
||||
{
|
||||
if(!c_conf) {
|
||||
if(! c_conf) {
|
||||
debug(LOG_ERR, "Error: c_conf is NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
debug(LOG_DEBUG, "Section[common]: {server_addr:%s, server_port:%d, auth_token:%s, privilege_token:%s, interval:%d, timeout:%d}",
|
||||
c_conf->server_addr, c_conf->server_port, c_conf->auth_token, c_conf->privilege_token, c_conf->heartbeat_interval, c_conf->heartbeat_timeout);
|
||||
debug(LOG_DEBUG, "Section[common]: {server_addr:%s, server_port:%d, auth_token:%s, interval:%d, timeout:%d}",
|
||||
c_conf->server_addr, c_conf->server_port, c_conf->auth_token,
|
||||
c_conf->heartbeat_interval, c_conf->heartbeat_timeout);
|
||||
}
|
||||
|
||||
static void dump_proxy_service(const int index, struct proxy_service *ps)
|
||||
@@ -133,6 +107,9 @@ static void dump_proxy_service(const int index, struct proxy_service *ps)
|
||||
|
||||
if (NULL == ps->proxy_type) {
|
||||
ps->proxy_type = strdup("tcp");
|
||||
assert(ps->proxy_type);
|
||||
} else if (strcmp(ps->proxy_type, "ftp") == 0) {
|
||||
new_ftp_data_proxy_service(ps);
|
||||
}
|
||||
|
||||
debug(LOG_DEBUG,
|
||||
@@ -148,7 +125,7 @@ static void dump_all_ps()
|
||||
struct proxy_service *ps = NULL, *tmp = NULL;
|
||||
|
||||
int index = 0;
|
||||
HASH_ITER(hh, p_services, ps, tmp) {
|
||||
HASH_ITER(hh, all_ps, ps, tmp) {
|
||||
dump_proxy_service(index++, ps);
|
||||
}
|
||||
}
|
||||
@@ -157,17 +134,20 @@ static struct proxy_service *new_proxy_service(const char *name)
|
||||
{
|
||||
if (! name)
|
||||
return NULL;
|
||||
struct proxy_service *ps = calloc(sizeof(struct proxy_service), 1);
|
||||
|
||||
struct proxy_service *ps = (struct proxy_service *)calloc(sizeof(struct proxy_service), 1);
|
||||
assert(ps);
|
||||
assert(c_conf);
|
||||
|
||||
ps->proxy_name = strdup(name);
|
||||
ps->ftp_cfg_proxy_name = NULL;
|
||||
assert(ps->proxy_name);
|
||||
|
||||
ps->proxy_type = NULL;
|
||||
ps->use_encryption = 0;
|
||||
ps->local_port = -1;
|
||||
ps->remote_port = -1;
|
||||
ps->remote_data_port = -1;
|
||||
ps->use_compression = 0;
|
||||
ps->use_encryption = 0;
|
||||
|
||||
@@ -181,30 +161,58 @@ static struct proxy_service *new_proxy_service(const char *name)
|
||||
return ps;
|
||||
}
|
||||
|
||||
// create a new proxy service with suffix "_ftp_data_proxy"
|
||||
static void new_ftp_data_proxy_service(struct proxy_service *ftp_ps)
|
||||
{
|
||||
struct proxy_service *ps = NULL;
|
||||
char *ftp_data_proxy_name = get_ftp_data_proxy_name((const char *)ftp_ps->proxy_name);
|
||||
|
||||
HASH_FIND_STR(all_ps, ftp_data_proxy_name, ps);
|
||||
if (!ps) {
|
||||
ps = new_proxy_service(ftp_data_proxy_name);
|
||||
if (! ps) {
|
||||
debug(LOG_ERR,
|
||||
"cannot create ftp data proxy service, it should not happenned!");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
ps->ftp_cfg_proxy_name = strdup(ftp_ps->proxy_name);
|
||||
assert(ps->ftp_cfg_proxy_name);
|
||||
|
||||
ps->proxy_type = strdup("tcp");
|
||||
ps->remote_port = ftp_ps->remote_data_port;
|
||||
ps->local_ip = ftp_ps->local_ip;
|
||||
ps->local_port = 0; //will be init in working tunnel connectting
|
||||
|
||||
HASH_ADD_KEYPTR(hh, all_ps, ps->proxy_name, strlen(ps->proxy_name), ps);
|
||||
}
|
||||
|
||||
free(ftp_data_proxy_name);
|
||||
}
|
||||
|
||||
static int
|
||||
proxy_service_handler(void *user, const char *sect, const char *nm, const char *value)
|
||||
{
|
||||
struct proxy_service *ps = NULL;
|
||||
|
||||
char *section = NULL;
|
||||
section = strdup(sect);
|
||||
assert(section);
|
||||
|
||||
if (strlen(sect) == 25) {//fix proxy name length = 25 bug, not find the reason
|
||||
section = calloc(1, 26);
|
||||
memset(section, '_', 26);
|
||||
memcpy(section, sect, 25);
|
||||
} else {
|
||||
section = strdup(sect);
|
||||
if (strcmp(section, "common") == 0) {
|
||||
SAFE_FREE(section);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strcmp(section, "common") == 0)
|
||||
return 0;
|
||||
|
||||
HASH_FIND_STR(p_services, section, ps);
|
||||
HASH_FIND_STR(all_ps, section, ps);
|
||||
if (!ps) {
|
||||
ps = new_proxy_service(section);
|
||||
assert(ps);
|
||||
if (! ps) {
|
||||
debug(LOG_ERR, "cannot create proxy service, it should not happenned!");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
HASH_ADD_KEYPTR(hh, p_services, ps->proxy_name, strlen(ps->proxy_name), ps);
|
||||
HASH_ADD_KEYPTR(hh, all_ps, ps->proxy_name, strlen(ps->proxy_name), ps);
|
||||
}
|
||||
|
||||
#define MATCH_NAME(s) strcmp(nm, s) == 0
|
||||
@@ -213,36 +221,42 @@ proxy_service_handler(void *user, const char *sect, const char *nm, const char *
|
||||
if (MATCH_NAME("type")) {
|
||||
if (! get_valid_type(value)) {
|
||||
debug(LOG_ERR, "proxy service type %s is not supportted", value);
|
||||
SAFE_FREE(section);
|
||||
exit(0);
|
||||
}
|
||||
ps->proxy_type = strdup(value);
|
||||
assert(ps->proxy_type);
|
||||
} else if (MATCH_NAME("local_ip")) {
|
||||
ps->local_ip = strdup(value);
|
||||
assert(ps->local_ip);
|
||||
} else if (MATCH_NAME("local_port")) {
|
||||
ps->local_port = atoi(value);
|
||||
} else if (MATCH_NAME("use_encryption")) {
|
||||
ps->use_encryption = is_true(value);
|
||||
} else if (MATCH_NAME("remote_port")) {
|
||||
ps->remote_port = atoi(value);
|
||||
} else if (MATCH_NAME("remote_data_port")) {
|
||||
ps->remote_data_port = atoi(value);
|
||||
} else if (MATCH_NAME("http_user")) {
|
||||
ps->http_user = strdup(value);
|
||||
} else if (MATCH_NAME("http_pwd")) {
|
||||
ps->http_pwd = strdup(value);
|
||||
} else if (MATCH_NAME("subdomain")) {
|
||||
ps->subdomain= strdup(value);
|
||||
ps->subdomain = strdup(value);
|
||||
} else if (MATCH_NAME("custom_domains")) {
|
||||
ps->custom_domains= strdup(value);
|
||||
ps->custom_domains = strdup(value);
|
||||
assert(ps->custom_domains);
|
||||
} else if (MATCH_NAME("locations")) {
|
||||
ps->locations= strdup(value);
|
||||
ps->locations = strdup(value);
|
||||
} else if (MATCH_NAME("host_header_rewrite")) {
|
||||
ps->host_header_rewrite= strdup(value);
|
||||
ps->host_header_rewrite = strdup(value);
|
||||
} else if (MATCH_NAME("use_encryption")) {
|
||||
ps->use_encryption = TO_BOOL(value);
|
||||
} else if (MATCH_NAME("use_compression")) {
|
||||
ps->use_compression = TO_BOOL(value);
|
||||
}
|
||||
|
||||
free(section);
|
||||
|
||||
SAFE_FREE(section);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -254,37 +268,20 @@ static int common_handler(void *user, const char *section, const char *name, con
|
||||
if (MATCH("common", "server_addr")) {
|
||||
SAFE_FREE(config->server_addr);
|
||||
config->server_addr = strdup(value);
|
||||
assert(config->server_addr);
|
||||
} else if (MATCH("common", "server_port")) {
|
||||
config->server_port = atoi(value);
|
||||
} else if (MATCH("common", "http_proxy")) {
|
||||
SAFE_FREE(config->http_proxy);
|
||||
config->http_proxy = strdup(value);
|
||||
} else if (MATCH("common", "log_file")) {
|
||||
SAFE_FREE(config->log_file);
|
||||
config->log_file = strdup(value);
|
||||
} else if (MATCH("common", "log_way")) {
|
||||
SAFE_FREE(config->log_way);
|
||||
config->log_way = strdup(value);
|
||||
} else if (MATCH("common", "log_level")) {
|
||||
SAFE_FREE(config->log_level);
|
||||
config->log_level = strdup(value);
|
||||
} else if (MATCH("common", "log_max_days")) {
|
||||
config->log_max_days = atoi(value);
|
||||
} else if (MATCH("common", "privilege_token")) {
|
||||
SAFE_FREE(config->privilege_token);
|
||||
config->privilege_token = strdup(value);
|
||||
} else if (MATCH("common", "heartbeat_interval")) {
|
||||
config->heartbeat_interval = atoi(value);
|
||||
} else if (MATCH("common", "heartbeat_timeout")) {
|
||||
config->heartbeat_timeout = atoi(value);
|
||||
} else if (MATCH("common", "auth_token")) {
|
||||
} else if (MATCH("common", "token")) {
|
||||
SAFE_FREE(config->auth_token);
|
||||
config->auth_token = strdup(value);
|
||||
} else if (MATCH("common", "user")) {
|
||||
SAFE_FREE(config->user);
|
||||
config->user = strdup(value);
|
||||
assert(config->auth_token);
|
||||
} else if (MATCH("common", "tcp_mux")) {
|
||||
config->tcp_mux = 0; // set tcp_mux to default: false
|
||||
config->tcp_mux = atoi(value);
|
||||
config->tcp_mux = !!config->tcp_mux;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@@ -295,20 +292,35 @@ static void init_common_conf(struct common_conf *config)
|
||||
return;
|
||||
|
||||
config->server_addr = strdup("0.0.0.0");
|
||||
assert(config->server_addr);
|
||||
config->server_port = 7000;
|
||||
config->log_file = strdup("console");
|
||||
config->log_way = strdup("console");
|
||||
config->log_level = strdup("info");
|
||||
config->log_max_days = 3;
|
||||
config->heartbeat_interval = 10;
|
||||
config->heartbeat_timeout = 30;
|
||||
config->tcp_mux = 0;
|
||||
config->user = NULL;
|
||||
config->heartbeat_interval = 30;
|
||||
config->heartbeat_timeout = 90;
|
||||
config->tcp_mux = 1;
|
||||
config->is_router = 0;
|
||||
}
|
||||
|
||||
// it should be free after using
|
||||
// because of assert it will never return NULL
|
||||
char *get_ftp_data_proxy_name(const char *ftp_proxy_name)
|
||||
{
|
||||
char *ftp_tail_data_name = FTP_RMT_CTL_PROXY_SUFFIX;
|
||||
char *ftp_data_proxy_name = (char *)calloc(1,
|
||||
strlen(ftp_proxy_name)+strlen(ftp_tail_data_name)+1);
|
||||
assert(ftp_data_proxy_name);
|
||||
|
||||
snprintf(ftp_data_proxy_name,
|
||||
strlen(ftp_proxy_name) + strlen(ftp_tail_data_name) + 1,
|
||||
"%s%s",
|
||||
ftp_proxy_name,
|
||||
ftp_tail_data_name);
|
||||
|
||||
return ftp_data_proxy_name;
|
||||
}
|
||||
|
||||
void load_config(const char *confile)
|
||||
{
|
||||
c_conf = calloc(sizeof(struct common_conf), 1);
|
||||
c_conf = (struct common_conf *)calloc(sizeof(struct common_conf), 1);
|
||||
assert(c_conf);
|
||||
|
||||
init_common_conf(c_conf);
|
||||
@@ -336,3 +348,22 @@ void load_config(const char *confile)
|
||||
|
||||
dump_all_ps();
|
||||
}
|
||||
|
||||
int is_running_in_router()
|
||||
{
|
||||
return c_conf->is_router;
|
||||
}
|
||||
|
||||
struct proxy_service *
|
||||
get_proxy_service(const char *proxy_name)
|
||||
{
|
||||
struct proxy_service *ps = NULL;
|
||||
HASH_FIND_STR(all_ps, proxy_name, ps);
|
||||
return ps;
|
||||
}
|
||||
|
||||
struct proxy_service *
|
||||
get_all_proxy_services()
|
||||
{
|
||||
return all_ps;
|
||||
}
|
||||
|
||||
50
config.h
50
config.h
@@ -20,8 +20,8 @@
|
||||
\********************************************************************/
|
||||
|
||||
/** @file config.h
|
||||
@brief xfrp client config related
|
||||
@author Copyright (C) 2016 Dengfeng Liu <liudengfeng@kunteng.org>
|
||||
@brief xfrpc client config related
|
||||
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
|
||||
*/
|
||||
#ifndef _CONFIG_H_
|
||||
#define _CONFIG_H_
|
||||
@@ -29,47 +29,33 @@
|
||||
#include "client.h"
|
||||
#include "common.h"
|
||||
|
||||
struct base_conf{
|
||||
char *name;
|
||||
char *auth_token;
|
||||
char *type;
|
||||
int use_encryption;
|
||||
int use_gzip;
|
||||
int privilege_mode;
|
||||
char *privilege_token;
|
||||
int pool_count;
|
||||
char *host_header_rewrite;
|
||||
char *http_username;
|
||||
char *http_password;
|
||||
char *subdomain;
|
||||
};
|
||||
#define FTP_RMT_CTL_PROXY_SUFFIX "_ftp_remote_ctl_proxy"
|
||||
|
||||
// common config
|
||||
//client common config
|
||||
struct common_conf {
|
||||
char *server_addr; /* default 0.0.0.0 */
|
||||
int server_port; /* default 7000 */
|
||||
char *http_proxy;
|
||||
char *log_file; /* default consol */
|
||||
char *log_way; /* default console */
|
||||
char *log_level; /* default info */
|
||||
int log_max_days; /* default 3 */
|
||||
char *privilege_token;
|
||||
char *server_addr; /* default 0.0.0.0 */
|
||||
int server_port; /* default 7000 */
|
||||
char *auth_token;
|
||||
int heartbeat_interval; /* default 10 */
|
||||
int heartbeat_timeout; /* default 30 */
|
||||
int tcp_mux; /* default 0 */
|
||||
char *user;
|
||||
int tcp_mux; /* default 0 */
|
||||
|
||||
/* private fields */
|
||||
int is_router; // to sign router (Openwrt/LEDE) or not
|
||||
};
|
||||
|
||||
struct common_conf *get_common_config();
|
||||
struct proxy_service *get_all_proxy_services();
|
||||
|
||||
void free_common_config();
|
||||
|
||||
void free_base_config(struct base_conf *bconf);
|
||||
|
||||
struct proxy_client *get_all_pc();
|
||||
|
||||
void load_config(const char *confile);
|
||||
|
||||
char *get_ftp_data_proxy_name(const char *ftp_proxy_name);
|
||||
|
||||
int is_running_in_router();
|
||||
|
||||
struct proxy_service *get_proxy_service(const char *proxy_name);
|
||||
|
||||
struct proxy_service *get_all_proxy_services();
|
||||
|
||||
#endif //_CONFIG_H_
|
||||
|
||||
14
const.h
14
const.h
@@ -20,8 +20,8 @@
|
||||
\********************************************************************/
|
||||
|
||||
/** @file const.h
|
||||
@brief xfrp constant parameter define
|
||||
@author Copyright (C) 2016 Dengfeng Liu <liudengfeng@kunteng.org>
|
||||
@brief xfrpc constant parameter define
|
||||
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
|
||||
*/
|
||||
|
||||
#ifndef _CONST_H_
|
||||
@@ -34,15 +34,5 @@ enum server_status {
|
||||
Closed
|
||||
};
|
||||
|
||||
// msg type
|
||||
// enum msg_type {
|
||||
// NewCtlConn = 0,
|
||||
// NewWorkConn,
|
||||
// NoticeUserConn,
|
||||
// NewCtlConnRes,
|
||||
// HeartbeatReq,
|
||||
// HeartbeatRes,
|
||||
// NewWorkConnUdp
|
||||
// };
|
||||
|
||||
#endif
|
||||
|
||||
41
control.h
41
control.h
@@ -21,7 +21,7 @@
|
||||
|
||||
/** @file control.h
|
||||
@brief control related
|
||||
@author Copyright (C) 2016 Dengfeng Liu <liudengfeng@kunteng.org>
|
||||
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
|
||||
*/
|
||||
|
||||
#ifndef _CONTROL_H_
|
||||
@@ -40,36 +40,45 @@ struct control {
|
||||
struct event_base *connect_base; //main netevent
|
||||
struct evdns_base *dnsbase;
|
||||
struct bufferevent *connect_bev; //main io evet buf
|
||||
char session_id;
|
||||
struct event *ticker_ping; //heartbeat timer
|
||||
|
||||
struct event *tcp_mux_ping_event;
|
||||
uint32_t tcp_mux_ping_id;
|
||||
struct tmux_stream stream;
|
||||
};
|
||||
|
||||
void connect_eventcb(struct bufferevent *bev, short events, void *ptr);
|
||||
void sync_iv(unsigned char *iv);
|
||||
void start_base_connect();
|
||||
void sync_session_id(uint32_t sid);
|
||||
|
||||
void init_main_control();
|
||||
|
||||
void run_control();
|
||||
|
||||
struct control *get_main_control();
|
||||
|
||||
void close_main_control();
|
||||
|
||||
void start_login_frp_server(struct event_base *base);
|
||||
|
||||
void send_login_frp_server(struct bufferevent *bev);
|
||||
|
||||
void login();
|
||||
void free_control();
|
||||
void sync_session_id(uint32_t sid);
|
||||
|
||||
void send_msg_frp_server(struct bufferevent *bev,
|
||||
const enum msg_type type,
|
||||
const char *msg,
|
||||
const size_t msg_len,
|
||||
uint32_t sid);
|
||||
const enum msg_type type,
|
||||
const char *msg,
|
||||
const size_t msg_len,
|
||||
struct tmux_stream *stream);
|
||||
|
||||
void send_enc_msg_frp_server(struct bufferevent *bev,
|
||||
const enum msg_type type,
|
||||
const char *msg,
|
||||
const size_t msg_len,
|
||||
struct tmux_stream *stream);
|
||||
|
||||
void control_process(struct proxy_client *client);
|
||||
|
||||
void send_new_proxy(struct proxy_service *ps);
|
||||
|
||||
struct bufferevent
|
||||
*connect_server(struct event_base *base, const char *name, const int port);
|
||||
struct bufferevent *connect_server(struct event_base *base, const char *name, const int port);
|
||||
|
||||
void control_request_free(struct control_request *req);
|
||||
|
||||
#endif //_CONTROL_H_
|
||||
#endif //_CONTROL_H_
|
||||
|
||||
305
crypto.c
305
crypto.c
@@ -1,3 +1,30 @@
|
||||
/* vim: set et ts=4 sts=4 sw=4 : */
|
||||
/********************************************************************\
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License as *
|
||||
* published by the Free Software Foundation; either version 2 of *
|
||||
* the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License*
|
||||
* along with this program; if not, contact: *
|
||||
* *
|
||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02111-1307, USA gnu@gnu.org *
|
||||
* *
|
||||
\********************************************************************/
|
||||
|
||||
/** @file crypto.c
|
||||
@brief xfrpc crypto implement
|
||||
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
|
||||
*/
|
||||
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -12,122 +39,160 @@
|
||||
#include "common.h"
|
||||
#include "debug.h"
|
||||
|
||||
// #define ENC_DEBUG 1
|
||||
|
||||
static const char *default_salt = "frp";
|
||||
static const size_t block_size = 16;
|
||||
static struct frp_coder *main_encoder = NULL;
|
||||
static struct frp_coder *main_decoder = NULL;
|
||||
static EVP_CIPHER_CTX *enc_ctx = NULL;
|
||||
static EVP_CIPHER_CTX *dec_ctx = NULL;
|
||||
|
||||
size_t get_block_size()
|
||||
static void
|
||||
free_frp_coder(struct frp_coder *coder)
|
||||
{
|
||||
free(coder->salt);
|
||||
free(coder->token);
|
||||
free(coder);
|
||||
}
|
||||
|
||||
static void
|
||||
free_all_frp_coder()
|
||||
{
|
||||
if (main_encoder) {
|
||||
free_frp_coder(main_encoder);
|
||||
main_encoder = NULL;
|
||||
}
|
||||
|
||||
if (main_decoder) {
|
||||
free_frp_coder(main_decoder);
|
||||
main_decoder = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
free_evp_cipher_ctx()
|
||||
{
|
||||
free_all_frp_coder();
|
||||
|
||||
if (enc_ctx) {
|
||||
EVP_CIPHER_CTX_free(enc_ctx);
|
||||
enc_ctx = NULL;
|
||||
}
|
||||
|
||||
if (dec_ctx) {
|
||||
EVP_CIPHER_CTX_free(dec_ctx);
|
||||
dec_ctx = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
size_t
|
||||
get_block_size()
|
||||
{
|
||||
return block_size;
|
||||
}
|
||||
|
||||
// TODO: NEED free
|
||||
struct frp_coder *new_coder(const char *privilege_token, const char *salt)
|
||||
struct frp_coder *
|
||||
new_coder(const char *token, const char *salt)
|
||||
{
|
||||
struct frp_coder *enc = calloc(sizeof(struct frp_coder), 1);
|
||||
assert(enc);
|
||||
|
||||
enc->privilege_token = privilege_token ? strdup(privilege_token):"\0";
|
||||
enc->key_len = block_size;
|
||||
enc->token = token ? strdup(token):strdup("\0");
|
||||
enc->salt = strdup(salt);
|
||||
enc->key = encrypt_key(enc->privilege_token, strlen(enc->privilege_token), enc->salt);
|
||||
enc->iv = calloc(block_size, 1);
|
||||
encrypt_key(enc->token, strlen(enc->token), enc->salt, enc->key, block_size);
|
||||
encrypt_iv(enc->iv, block_size);
|
||||
return enc;
|
||||
}
|
||||
|
||||
size_t get_encrypt_block_size()
|
||||
struct frp_coder *
|
||||
clone_coder(const struct frp_coder *coder)
|
||||
{
|
||||
assert(coder);
|
||||
struct frp_coder *enc = calloc(sizeof(struct frp_coder), 1);
|
||||
memcpy(enc, coder, sizeof(*coder));
|
||||
enc->token = strdup(coder->token);
|
||||
enc->salt = strdup(coder->salt);
|
||||
|
||||
return enc;
|
||||
}
|
||||
|
||||
size_t
|
||||
get_encrypt_block_size()
|
||||
{
|
||||
return block_size;
|
||||
}
|
||||
|
||||
struct frp_coder *init_main_encoder()
|
||||
struct frp_coder *
|
||||
init_main_encoder()
|
||||
{
|
||||
struct common_conf *c_conf = get_common_config();
|
||||
main_encoder = new_coder(c_conf->privilege_token, default_salt);
|
||||
assert(main_encoder);
|
||||
assert(main_encoder->key);
|
||||
|
||||
if (main_decoder) {
|
||||
main_encoder = clone_coder(main_decoder);
|
||||
} else {
|
||||
struct common_conf *c_conf = get_common_config();
|
||||
main_encoder = new_coder(c_conf->auth_token, default_salt);
|
||||
}
|
||||
return main_encoder;
|
||||
}
|
||||
|
||||
struct frp_coder *init_main_decoder(unsigned char *iv)
|
||||
struct frp_coder *
|
||||
init_main_decoder(const uint8_t *iv)
|
||||
{
|
||||
struct common_conf *c_conf = get_common_config();
|
||||
main_decoder = new_coder(c_conf->privilege_token, default_salt);
|
||||
assert(main_encoder);
|
||||
assert(main_encoder->key);
|
||||
main_decoder = new_coder(c_conf->auth_token, default_salt);
|
||||
memcpy(main_decoder->iv, iv, block_size);
|
||||
|
||||
return main_decoder;
|
||||
}
|
||||
|
||||
struct frp_coder *get_main_encoder()
|
||||
struct frp_coder *
|
||||
get_main_encoder()
|
||||
{
|
||||
return main_encoder;
|
||||
}
|
||||
|
||||
struct frp_coder *get_main_decoder()
|
||||
struct frp_coder *
|
||||
get_main_decoder()
|
||||
{
|
||||
return main_decoder;
|
||||
}
|
||||
|
||||
int is_encoder_inited()
|
||||
int
|
||||
is_encoder_inited()
|
||||
{
|
||||
struct frp_coder *e = get_main_encoder();
|
||||
return e != NULL;
|
||||
}
|
||||
|
||||
int is_decoder_inited()
|
||||
int
|
||||
is_decoder_inited()
|
||||
{
|
||||
struct frp_coder *d = get_main_decoder();
|
||||
return d != NULL;
|
||||
}
|
||||
|
||||
// 29 201 136 254 206 150 233 65 13 82 120 149 203 228 122 128
|
||||
// key_ret buffer len must be 16
|
||||
// the result should be free after using
|
||||
unsigned char *encrypt_key(const char *token, size_t token_len, const char *salt)
|
||||
unsigned char *
|
||||
encrypt_key(const char *token, size_t token_len, const char *salt, uint8_t *key, size_t block_size)
|
||||
{
|
||||
unsigned char *key_ret = calloc(block_size, 1);
|
||||
unsigned char *key_ret = key;
|
||||
fastpbkdf2_hmac_sha1((void *)token,
|
||||
token_len, (void *)salt,
|
||||
strlen(salt),
|
||||
64,
|
||||
(void *)key_ret,
|
||||
block_size);
|
||||
|
||||
/* debug */
|
||||
#ifdef ENC_DEBUG
|
||||
printf("encrypt_key = ");
|
||||
int i = 0;
|
||||
for(i=0; i<block_size; i++ ) {
|
||||
printf("%u ", *(key_ret + i));
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
/* debug end */
|
||||
#endif //ENC_DEBUG
|
||||
|
||||
if (! key_ret)
|
||||
fprintf(stderr, "key result buffer not applied!\n");
|
||||
|
||||
return key_ret;
|
||||
}
|
||||
|
||||
// the result should be free after using
|
||||
unsigned char *encrypt_iv(unsigned char *iv_buf, size_t iv_len)
|
||||
unsigned char *
|
||||
encrypt_iv(unsigned char *iv_buf, size_t iv_len)
|
||||
{
|
||||
if (iv_len < block_size || iv_buf == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
srand((unsigned int) time(NULL));
|
||||
size_t i;
|
||||
for(i=0; i<iv_len; i++) {
|
||||
for(size_t i=0; i<iv_len; i++) {
|
||||
iv_buf[i] = (rand() % 254 ) + 1;
|
||||
}
|
||||
|
||||
@@ -135,145 +200,81 @@ unsigned char *encrypt_iv(unsigned char *iv_buf, size_t iv_len)
|
||||
}
|
||||
|
||||
// using aes-128-cfb and nopadding
|
||||
size_t encrypt_data(const unsigned char *src_data, size_t srclen, struct frp_coder *encoder, unsigned char **ret)
|
||||
size_t
|
||||
encrypt_data(const uint8_t *src_data, size_t srclen, struct frp_coder *encoder, unsigned char **ret)
|
||||
{
|
||||
unsigned char *intext = calloc(srclen, 1); // free in func
|
||||
uint8_t *intext = (uint8_t *)src_data;
|
||||
assert(intext);
|
||||
memcpy(intext, src_data, srclen);
|
||||
assert(encoder);
|
||||
struct frp_coder *c = encoder;
|
||||
int outlen = 0, tmplen = 0;
|
||||
uint8_t *outbuf = NULL;
|
||||
assert(c);
|
||||
|
||||
unsigned char *outbuf = calloc(srclen, 1);
|
||||
outbuf = calloc(srclen, 1);
|
||||
assert(outbuf);
|
||||
*ret = outbuf;
|
||||
|
||||
int outlen = 0, tmplen = 0;
|
||||
struct frp_coder *c = encoder;
|
||||
EVP_CIPHER_CTX ctx;
|
||||
EVP_CIPHER_CTX_init(&ctx);
|
||||
EVP_EncryptInit_ex(&ctx, EVP_aes_128_cfb(), NULL, c->key, c->iv);
|
||||
if(!EVP_EncryptUpdate(&ctx, outbuf, &outlen, intext, (int)srclen)) {
|
||||
if (!enc_ctx) {
|
||||
enc_ctx = EVP_CIPHER_CTX_new();
|
||||
EVP_EncryptInit_ex(enc_ctx, EVP_aes_128_cfb(), NULL, c->key, c->iv);
|
||||
}
|
||||
EVP_CIPHER_CTX *ctx = enc_ctx;
|
||||
|
||||
if(!EVP_EncryptUpdate(ctx, outbuf, &tmplen, intext, (int)srclen)) {
|
||||
debug(LOG_ERR, "EVP_EncryptUpdate error!");
|
||||
goto E_END;
|
||||
}
|
||||
|
||||
if(!EVP_EncryptFinal_ex(&ctx, outbuf+outlen, &tmplen)) {
|
||||
outlen += tmplen;
|
||||
if(!EVP_EncryptFinal_ex(ctx, outbuf+tmplen, &tmplen)) {
|
||||
debug(LOG_ERR, "EVP_EncryptFinal_ex error!");
|
||||
goto E_END;
|
||||
}
|
||||
|
||||
outlen += tmplen;
|
||||
EVP_CIPHER_CTX_cleanup(&ctx);
|
||||
|
||||
#ifdef ENC_DEBUG
|
||||
int j = 0;
|
||||
debug(LOG_DEBUG, "encoder iv=");
|
||||
for (j=0; j<16; j++){
|
||||
printf("%u ", (unsigned char)c->iv[j]) ;
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
debug(LOG_DEBUG, "encoder KEY=");
|
||||
for (j=0; j<16; j++){
|
||||
printf("%u ", (unsigned char)c->key[j]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
debug(LOG_DEBUG, "encoder result 10 =");
|
||||
for (j = 0; j<outlen; j++) {
|
||||
printf("%d ", (unsigned char)outbuf[j]);
|
||||
}
|
||||
printf("\n");
|
||||
#endif //ENC_DEBUG
|
||||
|
||||
E_END:
|
||||
free(intext);
|
||||
return outlen;
|
||||
}
|
||||
|
||||
size_t decrypt_data(const unsigned char *enc_data, size_t enc_len, struct frp_coder *decoder, unsigned char **ret)
|
||||
size_t
|
||||
decrypt_data(const uint8_t *enc_data, size_t enclen, struct frp_coder *decoder, uint8_t **ret)
|
||||
{
|
||||
unsigned char *inbuf = malloc(enc_len);
|
||||
uint8_t *inbuf = (uint8_t *)enc_data;
|
||||
uint8_t *outbuf = calloc(enclen+1, 1);
|
||||
struct frp_coder *c = decoder;
|
||||
assert(inbuf);
|
||||
memcpy(inbuf, enc_data, enc_len);
|
||||
|
||||
unsigned char *outbuf = malloc(enc_len);
|
||||
assert(outbuf);
|
||||
*ret = outbuf;
|
||||
|
||||
assert(decoder);
|
||||
|
||||
int outlen = 0, tmplen = 0;
|
||||
struct frp_coder *c = decoder;
|
||||
EVP_CIPHER_CTX ctx;
|
||||
EVP_CIPHER_CTX_init(&ctx);
|
||||
EVP_DecryptInit_ex(&ctx, EVP_aes_128_cfb(), NULL, c->key, c->iv);
|
||||
EVP_CIPHER_CTX_set_padding(&ctx, 0);
|
||||
|
||||
int loop_times = enc_len / 10;
|
||||
int latest_len = enc_len % 10;
|
||||
int i = 0;
|
||||
int totol_len = 0;
|
||||
int enc_per_len;
|
||||
for(i=0; i<=loop_times; i++) {
|
||||
if (i == loop_times) {
|
||||
enc_per_len = latest_len;
|
||||
} else {
|
||||
enc_per_len = 10;
|
||||
}
|
||||
|
||||
if(!EVP_DecryptUpdate(&ctx, outbuf + (i*10), &outlen, inbuf + (i*10), enc_per_len)) {
|
||||
debug(LOG_ERR, "EVP_DecryptUpdate error!");
|
||||
goto D_END;
|
||||
}
|
||||
totol_len += outlen;
|
||||
if (!dec_ctx) {
|
||||
dec_ctx= EVP_CIPHER_CTX_new();
|
||||
EVP_DecryptInit_ex(dec_ctx, EVP_aes_128_cfb(), NULL, c->key, c->iv);
|
||||
}
|
||||
|
||||
EVP_CIPHER_CTX *ctx = dec_ctx;
|
||||
if(!EVP_DecryptUpdate(ctx, outbuf, &tmplen, inbuf, enclen)) {
|
||||
debug(LOG_ERR, "EVP_DecryptUpdate error!");
|
||||
goto D_END;
|
||||
}
|
||||
outlen += tmplen;
|
||||
|
||||
if(!EVP_DecryptFinal_ex(&ctx, outbuf+totol_len, &tmplen)) {
|
||||
if(!EVP_DecryptFinal_ex(ctx, outbuf+outlen, &tmplen)) {
|
||||
debug(LOG_ERR, "EVP_DecryptFinal_ex error");
|
||||
goto D_END;
|
||||
}
|
||||
|
||||
totol_len += tmplen;
|
||||
EVP_CIPHER_CTX_cleanup(&ctx);
|
||||
|
||||
#ifdef ENC_DEBUG
|
||||
debug(LOG_DEBUG, "DEC_LEN:%lu", enc_len);
|
||||
int j = 0;
|
||||
debug(LOG_DEBUG, "decoder IV=");
|
||||
for (j=0; j<16; j++){
|
||||
printf("%u ", (unsigned char)c->iv[j] );
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
debug(LOG_DEBUG, "decoder KEY=");
|
||||
for (j=0; j<16; j++){
|
||||
printf("%u ", (unsigned char)c->key[j] );
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
debug(LOG_DEBUG, "decoder source=");
|
||||
for (j=0; j<enc_len; j++){
|
||||
printf("%u ", (unsigned char)inbuf[j]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
debug(LOG_DEBUG, "decoder result=");
|
||||
for (j = 0; j<totol_len; j++) {
|
||||
printf("%u ", (unsigned char)(*ret)[j]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
debug(LOG_DEBUG, "decode string=%s", outbuf);
|
||||
#endif //ENC_DEBUG
|
||||
outlen += tmplen;
|
||||
|
||||
D_END:
|
||||
return totol_len;
|
||||
return outlen;
|
||||
}
|
||||
|
||||
void free_encoder(struct frp_coder *encoder) {
|
||||
void
|
||||
free_encoder(struct frp_coder *encoder) {
|
||||
if (encoder) {
|
||||
SAFE_FREE(encoder->privilege_token);
|
||||
SAFE_FREE(encoder->token);
|
||||
SAFE_FREE(encoder->salt);
|
||||
SAFE_FREE(encoder->key);
|
||||
SAFE_FREE(encoder->iv);
|
||||
SAFE_FREE(encoder);
|
||||
free(encoder);
|
||||
}
|
||||
}
|
||||
|
||||
51
crypto.h
51
crypto.h
@@ -1,3 +1,30 @@
|
||||
/* vim: set et ts=4 sts=4 sw=4 : */
|
||||
/********************************************************************\
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License as *
|
||||
* published by the Free Software Foundation; either version 2 of *
|
||||
* the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License*
|
||||
* along with this program; if not, contact: *
|
||||
* *
|
||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02111-1307, USA gnu@gnu.org *
|
||||
* *
|
||||
\********************************************************************/
|
||||
|
||||
/** @file crypto.h
|
||||
@brief xfrpc crypto header
|
||||
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _CRYPTO_H_
|
||||
#define _CRYPTO_H_
|
||||
|
||||
@@ -8,26 +35,26 @@
|
||||
#include "common.h"
|
||||
|
||||
struct frp_coder {
|
||||
unsigned char *key;
|
||||
ushort key_len;
|
||||
char *salt;
|
||||
unsigned char *iv;
|
||||
char *privilege_token;
|
||||
uint8_t key[16];
|
||||
char *salt;
|
||||
uint8_t iv[16];
|
||||
char *token;
|
||||
};
|
||||
|
||||
size_t get_encrypt_block_size();
|
||||
size_t decrypt_data(const unsigned char *enc_data, size_t enc_len, struct frp_coder *decoder, unsigned char **ret);
|
||||
size_t decrypt_data(const uint8_t *enc_data, size_t enc_len, struct frp_coder *decoder, uint8_t **ret);
|
||||
int is_encoder_inited();
|
||||
int is_decoder_inited();
|
||||
struct frp_coder *init_main_encoder();
|
||||
struct frp_coder *init_main_decoder(unsigned char *iv);
|
||||
struct frp_coder *new_coder(const char *privilege_token, const char *salt);
|
||||
unsigned char *encrypt_key(const char *token, size_t token_len, const char *salt);
|
||||
unsigned char *encrypt_iv(unsigned char *iv_buf, size_t iv_len);
|
||||
size_t encrypt_data(const unsigned char *src_data, size_t srclen, struct frp_coder *encoder, unsigned char **ret);
|
||||
struct frp_coder *init_main_decoder(const uint8_t *iv);
|
||||
struct frp_coder *new_coder(const char *token, const char *salt);
|
||||
uint8_t *encrypt_key(const char *token, size_t token_len, const char *salt, uint8_t *key, size_t key_len);
|
||||
uint8_t *encrypt_iv(uint8_t *iv_buf, size_t iv_len);
|
||||
size_t encrypt_data(const uint8_t *src_data, size_t srclen, struct frp_coder *encoder, uint8_t **ret);
|
||||
struct frp_coder *get_main_encoder();
|
||||
struct frp_coder *get_main_decoder();
|
||||
size_t get_block_size();
|
||||
void free_encoder(struct frp_coder *encoder);
|
||||
void free_evp_cipher_ctx();
|
||||
|
||||
#endif // _CRYPTO_H_
|
||||
#endif // _CRYPTO_H_
|
||||
|
||||
6
debug.c
6
debug.c
@@ -34,6 +34,8 @@
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#define PROGNAME "xfrpc"
|
||||
|
||||
debugconf_t debugconf = {
|
||||
.debuglevel = LOG_INFO,
|
||||
.log_stderr = 1,
|
||||
@@ -46,7 +48,7 @@ Do not use directly, use the debug macro */
|
||||
void
|
||||
_debug(const char *filename, int line, int level, const char *format, ...)
|
||||
{
|
||||
char buf[28];
|
||||
char buf[32] = {0};
|
||||
va_list vlist;
|
||||
time_t ts;
|
||||
sigset_t block_chld;
|
||||
@@ -75,7 +77,7 @@ _debug(const char *filename, int line, int level, const char *format, ...)
|
||||
}
|
||||
|
||||
if (debugconf.log_syslog) {
|
||||
openlog("wifidog", LOG_PID, debugconf.syslog_facility);
|
||||
openlog(PROGNAME, LOG_PID, debugconf.syslog_facility);
|
||||
va_start(vlist, format);
|
||||
vsyslog(level, format, vlist);
|
||||
va_end(vlist);
|
||||
|
||||
1
debug.h
1
debug.h
@@ -28,6 +28,7 @@
|
||||
#define _WIFIDOG_DEBUG_H_
|
||||
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
|
||||
|
||||
|
||||
69
frame.c
69
frame.c
@@ -1,69 +0,0 @@
|
||||
#include "frame.h"
|
||||
#include "session.h"
|
||||
#include "version.h"
|
||||
#include "common.h"
|
||||
|
||||
const static int size_of_ver = 1;
|
||||
const static int size_of_cmd = 1;
|
||||
const static int size_of_length = 2;
|
||||
const static int size_of_sid = 4;
|
||||
const static char version = 1;
|
||||
|
||||
int get_header_size() {
|
||||
return size_of_ver + size_of_cmd + size_of_length + size_of_sid;
|
||||
}
|
||||
|
||||
struct frame *new_frame(char cmd, uint32_t sid) {
|
||||
struct frame *f = calloc(sizeof(struct frame), 1);
|
||||
if (f != NULL) {
|
||||
f->ver = version;
|
||||
f->cmd = cmd;
|
||||
f->sid = sid;
|
||||
f->len = 0;
|
||||
}
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
// f->len is rawed in this func
|
||||
struct frame *raw_frame(unsigned char *buf, const size_t buf_len)
|
||||
{
|
||||
int header_size = get_header_size();
|
||||
if (buf_len < header_size) {
|
||||
return NULL;
|
||||
}
|
||||
char ver = buf[VERI];
|
||||
char cmd = buf[CMDI];
|
||||
uint32_t sid = *(uint32_t *)(buf + SIDI);
|
||||
|
||||
struct frame *f = new_frame(cmd, sid);
|
||||
f->ver = ver;
|
||||
f->len = *(ushort *)(buf + LENI);
|
||||
f->data = buf_len > header_size ? (unsigned char *)(buf + header_size) : NULL;
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
struct frame *raw_frame_only_msg(unsigned char *buf, const size_t buf_len)
|
||||
{
|
||||
struct frame *f = new_frame(0, 0);
|
||||
f->ver = CLIENT_V;
|
||||
f->len = (ushort)buf_len;
|
||||
f->data = buf;
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
void set_frame_cmd(struct frame *f, char cmd)
|
||||
{
|
||||
f->cmd = cmd;
|
||||
}
|
||||
|
||||
void set_frame_len(struct frame *f, ushort data_len)
|
||||
{
|
||||
f->len = data_len;
|
||||
}
|
||||
|
||||
void free_frame(struct frame *f) {
|
||||
SAFE_FREE(f);
|
||||
}
|
||||
40
frame.h
40
frame.h
@@ -1,40 +0,0 @@
|
||||
#ifndef _FRAME_H_
|
||||
#define _FRAME_H_
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "uthash.h"
|
||||
#include "common.h"
|
||||
|
||||
#define VERI 0
|
||||
#define CMDI 1
|
||||
#define LENI 2
|
||||
#define SIDI 4
|
||||
#define DATAI 8
|
||||
|
||||
// cmds
|
||||
enum cmd_type {
|
||||
cmdSYN = 0, // stream open
|
||||
cmdFIN, // stream close, a.k.a EOF mark
|
||||
cmdPSH, // data push
|
||||
cmdNOP, // no operation
|
||||
};
|
||||
|
||||
struct frame {
|
||||
char ver;
|
||||
char cmd;
|
||||
ushort len;
|
||||
uint32_t sid;
|
||||
unsigned char *data;
|
||||
};
|
||||
|
||||
struct frame *new_frame(char cmd, uint32_t sid);
|
||||
int get_header_size();
|
||||
struct frame *raw_frame(unsigned char *buf, const size_t buf_len);
|
||||
struct frame *raw_frame_only_msg(unsigned char *buf, const size_t buf_len);
|
||||
void set_frame_cmd(struct frame *f, char cmd);
|
||||
void set_frame_len(struct frame *f, ushort data_len);
|
||||
void free_frame(struct frame *f);
|
||||
|
||||
#endif //_FRAME_H_
|
||||
@@ -1,2 +0,0 @@
|
||||
/usr/bin/xfrp_client
|
||||
/usr/bin/xfrp_test_server
|
||||
69
login.c
69
login.c
@@ -1,3 +1,29 @@
|
||||
/* vim: set et ts=4 sts=4 sw=4 : */
|
||||
/********************************************************************\
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License as *
|
||||
* published by the Free Software Foundation; either version 2 of *
|
||||
* the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License*
|
||||
* along with this program; if not, contact: *
|
||||
* *
|
||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02111-1307, USA gnu@gnu.org *
|
||||
* *
|
||||
\********************************************************************/
|
||||
|
||||
/** @file login.c
|
||||
@brief xfrpc login protocol implemented
|
||||
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -15,6 +41,7 @@
|
||||
#include "msg.h"
|
||||
#include "version.h"
|
||||
#include "login.h"
|
||||
#include "utils.h"
|
||||
|
||||
static struct login *c_login;
|
||||
|
||||
@@ -37,38 +64,58 @@ void init_login()
|
||||
{
|
||||
if (! c_login)
|
||||
c_login = calloc(sizeof(struct login), 1);
|
||||
|
||||
assert(c_login);
|
||||
|
||||
struct common_conf *c_conf = get_common_config();
|
||||
assert(c_conf);
|
||||
|
||||
|
||||
struct utsname uname_buf;
|
||||
if (uname(&uname_buf)) {
|
||||
return;
|
||||
}
|
||||
|
||||
c_login->version = strdup(PROTOCOL_VERESION);
|
||||
assert(c_login->version);
|
||||
c_login->hostname = NULL;
|
||||
c_login->os = strdup(uname_buf.sysname);
|
||||
c_login->os = strdup(uname_buf.sysname);
|
||||
assert(c_login->os);
|
||||
c_login->arch = strdup(uname_buf.machine);
|
||||
assert(c_login->arch);
|
||||
c_login->user = NULL;
|
||||
|
||||
c_login->timestamp = 0;
|
||||
c_login->run_id = NULL;
|
||||
c_login->metas = NULL;
|
||||
c_login->pool_count = 1;
|
||||
c_login->privilege_key = NULL;
|
||||
c_login->user = c_conf->user;
|
||||
|
||||
c_login->logged = 0;
|
||||
|
||||
/* start to init login->run_id */
|
||||
char ifname[16] = {0};
|
||||
if(get_net_ifname(ifname, 16)){
|
||||
debug(LOG_ERR, "error: get device sign ifname failed!");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (strcmp(ifname, "br-lan") == 0) {
|
||||
c_conf->is_router = 1;
|
||||
debug(LOG_DEBUG, "working in router");
|
||||
}
|
||||
|
||||
char if_mac[64] = {0};
|
||||
if(get_net_mac(ifname, if_mac, sizeof(if_mac))) {
|
||||
debug(LOG_ERR, "error: Hard ware MAC address of [%s] get failed!", ifname);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
c_login->run_id = strdup(if_mac);
|
||||
assert(c_login->run_id);
|
||||
}
|
||||
|
||||
int login_resp_check(struct login_resp *lr)
|
||||
{
|
||||
debug(LOG_DEBUG, "xfrp login response: run_id: [%s], version: [%s], error: [%s]",
|
||||
lr->run_id,
|
||||
lr->version,
|
||||
lr->error);
|
||||
|
||||
if (lr->run_id == NULL || strlen(lr->run_id) <= 1) {
|
||||
if (lr->error && strlen(lr->error) > 0) {
|
||||
debug(LOG_ERR, "login response error: %s", lr->error);
|
||||
@@ -77,10 +124,14 @@ int login_resp_check(struct login_resp *lr)
|
||||
c_login->logged = 0;
|
||||
} else {
|
||||
c_login->logged = 1;
|
||||
debug(LOG_DEBUG, "xfrp login response: run_id: [%s], version: [%s]",
|
||||
lr->run_id,
|
||||
lr->version);
|
||||
SAFE_FREE(c_login->run_id);
|
||||
|
||||
c_login->run_id = strdup(lr->run_id);
|
||||
assert(c_login->run_id);
|
||||
}
|
||||
|
||||
return c_login->logged;
|
||||
}
|
||||
}
|
||||
|
||||
29
login.h
29
login.h
@@ -1,3 +1,29 @@
|
||||
/* vim: set et ts=4 sts=4 sw=4 : */
|
||||
/********************************************************************\
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License as *
|
||||
* published by the Free Software Foundation; either version 2 of *
|
||||
* the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License*
|
||||
* along with this program; if not, contact: *
|
||||
* *
|
||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02111-1307, USA gnu@gnu.org *
|
||||
* *
|
||||
\********************************************************************/
|
||||
|
||||
/** @file login.h
|
||||
@brief xfrp login header
|
||||
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
|
||||
*/
|
||||
|
||||
#ifndef _LOGIN_H_
|
||||
#define _LOGIN_H_
|
||||
|
||||
@@ -17,6 +43,7 @@ struct login {
|
||||
char *privilege_key;
|
||||
long int timestamp;
|
||||
char *run_id;
|
||||
char *metas;
|
||||
int pool_count;
|
||||
|
||||
/* fields not need json marshal */
|
||||
@@ -35,4 +62,4 @@ struct login *get_common_login_config();
|
||||
int is_logged();
|
||||
int login_resp_check(struct login_resp *lr);
|
||||
|
||||
#endif //_LOGIN_H_
|
||||
#endif //_LOGIN_H_
|
||||
|
||||
6
main.c
6
main.c
@@ -21,10 +21,10 @@
|
||||
|
||||
/** @file main.c
|
||||
@brief xfrp client main
|
||||
@author Copyright (C) 2016 Dengfeng Liu <liudengfeng@kunteng.org>
|
||||
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
|
||||
*/
|
||||
|
||||
#include "xfrp_client.h"
|
||||
#include "xfrpc.h"
|
||||
#include "commandline.h"
|
||||
#include "login.h"
|
||||
|
||||
@@ -32,5 +32,5 @@ int main(int argc, char **argv)
|
||||
{
|
||||
parse_commandline(argc, argv);
|
||||
init_login();
|
||||
xfrp_client_loop();
|
||||
xfrpc_loop();
|
||||
}
|
||||
|
||||
229
msg.c
229
msg.c
@@ -20,14 +20,13 @@
|
||||
\********************************************************************/
|
||||
|
||||
/** @file msg.c
|
||||
@brief xfrp client msg related
|
||||
@author Copyright (C) 2016 Dengfeng Liu <liudengfeng@kunteng.org>
|
||||
@brief xfrpc client msg related
|
||||
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <json-c/json.h>
|
||||
#include <json-c/bits.h>
|
||||
#include <openssl/md5.h>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
@@ -37,10 +36,11 @@
|
||||
#include "msg.h"
|
||||
#include "const.h"
|
||||
#include "config.h"
|
||||
#include "frame.h"
|
||||
#include "debug.h"
|
||||
#include "common.h"
|
||||
#include "login.h"
|
||||
#include "client.h"
|
||||
#include "utils.h"
|
||||
|
||||
#define JSON_MARSHAL_TYPE(jobj,key,jtype,item) \
|
||||
json_object_object_add(jobj, key, json_object_new_##jtype((item)));
|
||||
@@ -48,10 +48,19 @@ json_object_object_add(jobj, key, json_object_new_##jtype((item)));
|
||||
#define SAFE_JSON_STRING(str_target) \
|
||||
str_target?str_target:"\0"
|
||||
|
||||
const char msg_typs[] = {TypeLogin, TypeLoginResp, TypeNewProxy, TypeNewProxyResp,
|
||||
TypeNewWorkConn, TypeReqWorkConn, TypeStartWorkConn, TypePing, TypePong, TypeUdpPacket};
|
||||
const char msg_types[] = {TypeLogin,
|
||||
TypeLoginResp,
|
||||
TypeNewProxy,
|
||||
TypeNewProxyResp,
|
||||
TypeNewWorkConn,
|
||||
TypeReqWorkConn,
|
||||
TypeStartWorkConn,
|
||||
TypePing,
|
||||
TypePong,
|
||||
TypeUDPPacket};
|
||||
|
||||
char *calc_md5(const char *data, int datalen)
|
||||
char *
|
||||
calc_md5(const char *data, int datalen)
|
||||
{
|
||||
unsigned char digest[16] = {0};
|
||||
char *out = (char*)malloc(33);
|
||||
@@ -70,15 +79,24 @@ char *calc_md5(const char *data, int datalen)
|
||||
return out;
|
||||
}
|
||||
|
||||
static void fill_custom_domains(struct json_object *j_ctl_req, const char *custom_domains)
|
||||
static void
|
||||
fill_custom_domains(struct json_object *j_ctl_req, const char *custom_domains)
|
||||
{
|
||||
struct json_object *jarray_cdomains = json_object_new_array();
|
||||
assert(jarray_cdomains);
|
||||
char *tmp = strdup(custom_domains);
|
||||
assert(tmp);
|
||||
char *tok = tmp, *end = tmp;
|
||||
while (tok != NULL) {
|
||||
strsep(&end, ",");
|
||||
json_object_array_add(jarray_cdomains, json_object_new_string(tok));
|
||||
|
||||
int dname_len = strlen(tok) + 1;
|
||||
char *dname_buf = (char *)calloc(1, dname_len);
|
||||
assert(dname_buf);
|
||||
dns_unified(tok, dname_buf, dname_len);
|
||||
json_object_array_add(jarray_cdomains, json_object_new_string(dname_buf));
|
||||
|
||||
free(dname_buf);
|
||||
tok = end;
|
||||
}
|
||||
SAFE_FREE(tmp);
|
||||
@@ -86,27 +104,18 @@ static void fill_custom_domains(struct json_object *j_ctl_req, const char *custo
|
||||
json_object_object_add(j_ctl_req, "custom_domains", jarray_cdomains);
|
||||
}
|
||||
|
||||
// NEED FREE
|
||||
struct message *new_message() {
|
||||
struct message *msg = calloc(1, sizeof(struct message)); //TODO: FREE
|
||||
if (msg)
|
||||
{
|
||||
msg->data_p = NULL;
|
||||
msg->data_len = 0;
|
||||
}
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
struct work_conn *new_work_conn() {
|
||||
struct work_conn *
|
||||
new_work_conn() {
|
||||
struct work_conn *work_c = calloc(1, sizeof(struct work_conn));
|
||||
assert(work_c);
|
||||
if (work_c)
|
||||
work_c->run_id = NULL;
|
||||
|
||||
return work_c;
|
||||
}
|
||||
|
||||
char *get_auth_key(const char *token, long int *timestamp)
|
||||
char *
|
||||
get_auth_key(const char *token, long int *timestamp)
|
||||
{
|
||||
char seed[128] = {0};
|
||||
*timestamp = time(NULL);
|
||||
@@ -118,11 +127,12 @@ char *get_auth_key(const char *token, long int *timestamp)
|
||||
return calc_md5(seed, strlen(seed));
|
||||
}
|
||||
|
||||
size_t login_request_marshal(char **msg)
|
||||
size_t
|
||||
login_request_marshal(char **msg)
|
||||
{
|
||||
size_t nret = 0;
|
||||
struct json_object *j_login_req = json_object_new_object();
|
||||
if (is_error(j_login_req))
|
||||
if (j_login_req == NULL)
|
||||
return 0;
|
||||
|
||||
struct login *lg = get_common_login_config();
|
||||
@@ -131,8 +141,9 @@ size_t login_request_marshal(char **msg)
|
||||
|
||||
SAFE_FREE(lg->privilege_key);
|
||||
struct common_conf *cf = get_common_config();
|
||||
char *auth_key = get_auth_key(cf->privilege_token, &lg->timestamp);
|
||||
char *auth_key = get_auth_key(cf->auth_token, &lg->timestamp);
|
||||
lg->privilege_key = strdup(auth_key);
|
||||
assert(lg->privilege_key);
|
||||
|
||||
JSON_MARSHAL_TYPE(j_login_req, "version", string, lg->version);
|
||||
JSON_MARSHAL_TYPE(j_login_req, "hostname", string, SAFE_JSON_STRING(lg->hostname));
|
||||
@@ -144,19 +155,22 @@ size_t login_request_marshal(char **msg)
|
||||
JSON_MARSHAL_TYPE(j_login_req, "timestamp", int64, lg->timestamp);
|
||||
JSON_MARSHAL_TYPE(j_login_req, "run_id", string, SAFE_JSON_STRING(lg->run_id));
|
||||
JSON_MARSHAL_TYPE(j_login_req, "pool_count", int, lg->pool_count);
|
||||
|
||||
json_object_object_add(j_login_req, "metas", NULL);
|
||||
|
||||
const char *tmp = NULL;
|
||||
tmp = json_object_to_json_string(j_login_req);
|
||||
if (tmp && strlen(tmp) > 0) {
|
||||
nret = strlen(tmp);
|
||||
*msg = strdup(tmp);
|
||||
assert(*msg);
|
||||
}
|
||||
json_object_put(j_login_req);
|
||||
SAFE_FREE(auth_key);
|
||||
return nret;
|
||||
}
|
||||
|
||||
int new_proxy_service_marshal(const struct proxy_service *np_req, char **msg)
|
||||
int
|
||||
new_proxy_service_marshal(const struct proxy_service *np_req, char **msg)
|
||||
{
|
||||
const char *tmp = NULL;
|
||||
int nret = 0;
|
||||
@@ -168,12 +182,21 @@ int new_proxy_service_marshal(const struct proxy_service *np_req, char **msg)
|
||||
JSON_MARSHAL_TYPE(j_np_req, "proxy_type", string, np_req->proxy_type);
|
||||
JSON_MARSHAL_TYPE(j_np_req, "use_encryption", boolean, np_req->use_encryption);
|
||||
JSON_MARSHAL_TYPE(j_np_req, "use_compression", boolean, np_req->use_compression);
|
||||
JSON_MARSHAL_TYPE(j_np_req, "remote_port", int, np_req->remote_port);
|
||||
|
||||
if (is_ftp_proxy(np_req)) {
|
||||
JSON_MARSHAL_TYPE(j_np_req, "remote_data_port", int, np_req->remote_data_port);
|
||||
}
|
||||
|
||||
if (np_req->custom_domains) {
|
||||
fill_custom_domains(j_np_req, np_req->custom_domains);
|
||||
json_object_object_add(j_np_req, "remote_port", NULL);
|
||||
} else {
|
||||
json_object_object_add(j_np_req, "custom_domains", NULL);
|
||||
if (np_req->remote_port != -1) {
|
||||
JSON_MARSHAL_TYPE(j_np_req, "remote_port", int, np_req->remote_port);
|
||||
} else {
|
||||
json_object_object_add(j_np_req, "remote_port", NULL);
|
||||
}
|
||||
}
|
||||
|
||||
JSON_MARSHAL_TYPE(j_np_req, "subdomain", string, SAFE_JSON_STRING(np_req->subdomain));
|
||||
@@ -193,13 +216,15 @@ int new_proxy_service_marshal(const struct proxy_service *np_req, char **msg)
|
||||
if (tmp && strlen(tmp) > 0) {
|
||||
nret = strlen(tmp);
|
||||
*msg = strdup(tmp);
|
||||
assert(*msg);
|
||||
}
|
||||
json_object_put(j_np_req);
|
||||
|
||||
return nret;
|
||||
}
|
||||
|
||||
int new_work_conn_marshal(const struct work_conn *work_c, char **msg)
|
||||
int
|
||||
new_work_conn_marshal(const struct work_conn *work_c, char **msg)
|
||||
{
|
||||
const char *tmp = NULL;
|
||||
int nret = 0;
|
||||
@@ -212,6 +237,7 @@ int new_work_conn_marshal(const struct work_conn *work_c, char **msg)
|
||||
if (tmp && strlen(tmp) > 0) {
|
||||
nret = strlen(tmp);
|
||||
*msg = strdup(tmp);
|
||||
assert(*msg);
|
||||
}
|
||||
|
||||
json_object_put(j_new_work_conn);
|
||||
@@ -219,68 +245,112 @@ int new_work_conn_marshal(const struct work_conn *work_c, char **msg)
|
||||
return nret;
|
||||
}
|
||||
|
||||
// result returned of this func need be free
|
||||
struct new_proxy_response *
|
||||
new_proxy_resp_unmarshal(const char *jres)
|
||||
{
|
||||
struct json_object *j_np_res = json_tokener_parse(jres);
|
||||
if (j_np_res == NULL)
|
||||
return NULL;
|
||||
|
||||
struct new_proxy_response *npr = calloc(1, sizeof(struct new_proxy_response));
|
||||
assert(npr);
|
||||
|
||||
struct json_object *npr_run_id = NULL;
|
||||
if (json_object_object_get_ex(j_np_res, "run_id", &npr_run_id))
|
||||
npr->run_id = strdup(json_object_get_string(npr_run_id));
|
||||
|
||||
struct json_object *npr_proxy_remote_addr = NULL;
|
||||
if (! json_object_object_get_ex(j_np_res, "remote_addr", &npr_proxy_remote_addr))
|
||||
goto END_ERROR;
|
||||
const char *remote_addr = json_object_get_string(npr_proxy_remote_addr);
|
||||
char *port = strrchr(remote_addr, ':');
|
||||
if (port) {
|
||||
port++;
|
||||
npr->remote_port = atoi(port);
|
||||
}
|
||||
|
||||
struct json_object *npr_proxy_name = NULL;
|
||||
if (! json_object_object_get_ex(j_np_res, "proxy_name", &npr_proxy_name))
|
||||
goto END_ERROR;
|
||||
npr->proxy_name = strdup(json_object_get_string(npr_proxy_name));
|
||||
assert(npr->proxy_name);
|
||||
|
||||
struct json_object *npr_error = NULL;
|
||||
if(! json_object_object_get_ex(j_np_res, "error", &npr_error))
|
||||
goto END_ERROR;
|
||||
npr->error = strdup(json_object_get_string(npr_error));
|
||||
assert(npr->error);
|
||||
|
||||
END_ERROR:
|
||||
json_object_put(j_np_res);
|
||||
return npr;
|
||||
}
|
||||
|
||||
// login_resp_unmarshal NEED FREE
|
||||
struct login_resp *login_resp_unmarshal(const char *jres)
|
||||
struct login_resp *
|
||||
login_resp_unmarshal(const char *jres)
|
||||
{
|
||||
struct json_object *j_lg_res = json_tokener_parse(jres);
|
||||
if (is_error(j_lg_res))
|
||||
if (j_lg_res == NULL)
|
||||
return NULL;
|
||||
|
||||
struct login_resp *lr = calloc(1, sizeof(struct login_resp));
|
||||
if (lr == NULL) {
|
||||
goto END_ERROR;
|
||||
}
|
||||
assert(lr);
|
||||
|
||||
struct json_object *l_version = NULL;
|
||||
if (! json_object_object_get_ex(j_lg_res, "version", &l_version))
|
||||
goto END_ERROR;
|
||||
lr->version = strdup(json_object_get_string(l_version));
|
||||
assert(lr->version);
|
||||
|
||||
struct json_object *l_run_id = NULL;
|
||||
if (! json_object_object_get_ex(j_lg_res, "run_id", &l_run_id))
|
||||
goto END_ERROR;
|
||||
lr->run_id = strdup(json_object_get_string(l_run_id));
|
||||
|
||||
assert(lr->run_id);
|
||||
|
||||
struct json_object *l_error = NULL;
|
||||
if(! json_object_object_get_ex(j_lg_res, "error", &l_error))
|
||||
goto END_ERROR;
|
||||
lr->error = strdup(json_object_get_string(l_error));
|
||||
assert(lr->error);
|
||||
|
||||
END_ERROR:
|
||||
json_object_put(j_lg_res);
|
||||
return lr;
|
||||
}
|
||||
|
||||
struct start_work_conn_resp *start_work_conn_resp_unmarshal(const char *resp_msg)
|
||||
struct start_work_conn_resp *
|
||||
start_work_conn_resp_unmarshal(const char *resp_msg)
|
||||
{
|
||||
struct json_object *j_start_w_res = json_tokener_parse(resp_msg);
|
||||
if (is_error(j_start_w_res))
|
||||
if (j_start_w_res == NULL)
|
||||
return NULL;
|
||||
|
||||
struct start_work_conn_resp *sr = calloc(1, sizeof(struct start_work_conn_resp));
|
||||
if (! sr)
|
||||
goto START_W_C_R_END;
|
||||
assert(sr);
|
||||
|
||||
struct json_object *pn = NULL;
|
||||
if(! json_object_object_get_ex(j_start_w_res, "proxy_name", &pn))
|
||||
goto START_W_C_R_END;
|
||||
|
||||
sr->proxy_name = strdup(json_object_get_string(pn));
|
||||
assert(sr->proxy_name);
|
||||
|
||||
START_W_C_R_END:
|
||||
json_object_put(j_start_w_res);
|
||||
return sr;
|
||||
}
|
||||
|
||||
struct control_response *control_response_unmarshal(const char *jres)
|
||||
struct control_response *
|
||||
control_response_unmarshal(const char *jres)
|
||||
{
|
||||
struct json_object *j_ctl_res = json_tokener_parse(jres);
|
||||
if (is_error(j_ctl_res))
|
||||
if (j_ctl_res == NULL)
|
||||
return NULL;
|
||||
struct control_response *ctl_res = calloc(sizeof(struct control_response), 1);
|
||||
if (ctl_res == NULL) {
|
||||
goto END_ERROR;
|
||||
}
|
||||
assert(ctl_res);
|
||||
|
||||
struct json_object *jtype = NULL;
|
||||
if(! json_object_object_get_ex(j_ctl_res, "type", &jtype))
|
||||
@@ -293,15 +363,18 @@ struct control_response *control_response_unmarshal(const char *jres)
|
||||
ctl_res->code = json_object_get_int(jcode);
|
||||
|
||||
struct json_object *jmsg = NULL;
|
||||
if(json_object_object_get_ex(j_ctl_res, "msg", &jmsg))
|
||||
if(json_object_object_get_ex(j_ctl_res, "msg", &jmsg)) {
|
||||
ctl_res->msg = strdup(json_object_get_string(jmsg));
|
||||
|
||||
assert(ctl_res->msg);
|
||||
}
|
||||
|
||||
END_ERROR:
|
||||
json_object_put(j_ctl_res);
|
||||
return ctl_res;
|
||||
}
|
||||
|
||||
void control_response_free(struct control_response *res)
|
||||
void
|
||||
control_response_free(struct control_response *res)
|
||||
{
|
||||
if (!res)
|
||||
return;
|
||||
@@ -310,67 +383,21 @@ void control_response_free(struct control_response *res)
|
||||
SAFE_FREE(res);
|
||||
}
|
||||
|
||||
int msg_type_valid_check(char msg_type)
|
||||
int
|
||||
msg_type_valid_check(char msg_type)
|
||||
{
|
||||
int i = 0;
|
||||
for(i = 0; i<(sizeof(msg_typs) / sizeof(*msg_typs)); i++) {
|
||||
if (msg_typs[i] == msg_type)
|
||||
for(i = 0; i<(sizeof(msg_types) / sizeof(*msg_types)); i++) {
|
||||
if (msg_types[i] == msg_type)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// only handle recved message with right message type
|
||||
struct message *unpack(unsigned char *recv_msg, const ushort len)
|
||||
char *
|
||||
get_msg_type(uint8_t type)
|
||||
{
|
||||
struct message *msg = new_message();
|
||||
msg->type = *(recv_msg + MSG_TYPE_I);
|
||||
|
||||
if (! msg_type_valid_check(msg->type) ) {
|
||||
debug(LOG_ERR, "message recved type is invalid!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
msg_size_t data_len_bigend;
|
||||
data_len_bigend = *(msg_size_t *)(recv_msg + MSG_LEN_I);
|
||||
msg->data_len = msg_ntoh(data_len_bigend);
|
||||
|
||||
if (msg->data_len > 0) {
|
||||
msg->data_p = calloc(msg->data_len + 1, 1);
|
||||
assert(msg->data_p);
|
||||
|
||||
memcpy(msg->data_p, recv_msg + MSG_DATA_I, msg->data_len);
|
||||
}
|
||||
|
||||
return msg;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t pack(struct message *req_msg, unsigned char **ret_buf)
|
||||
{
|
||||
int endian_check = 1;
|
||||
// little endian if true
|
||||
|
||||
msg_size_t data_len_bigend;
|
||||
if(*(char *)&endian_check == 1)
|
||||
data_len_bigend = msg_hton(req_msg->data_len);
|
||||
else
|
||||
data_len_bigend = req_msg->data_len;
|
||||
|
||||
|
||||
size_t buf_len = TYPE_LEN + sizeof(data_len_bigend) + req_msg->data_len;
|
||||
*ret_buf = calloc(buf_len, 1);
|
||||
|
||||
if (*ret_buf == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
*(*ret_buf + MSG_TYPE_I) = req_msg->type;
|
||||
*(msg_size_t *)(*ret_buf + MSG_LEN_I) = data_len_bigend;
|
||||
snprintf((char *)*ret_buf + TYPE_LEN + sizeof(data_len_bigend),
|
||||
req_msg->data_len + 1,
|
||||
"%s",
|
||||
req_msg->data_p);
|
||||
|
||||
return buf_len;
|
||||
}
|
||||
87
msg.h
87
msg.h
@@ -20,8 +20,8 @@
|
||||
\********************************************************************/
|
||||
|
||||
/** @file msg.h
|
||||
@brief xfrp msg struct
|
||||
@author Copyright (C) 2016 Dengfeng Liu <liudengfeng@kunteng.org>
|
||||
@brief xfrpc msg struct
|
||||
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
|
||||
*/
|
||||
|
||||
#ifndef _MSG_H_
|
||||
@@ -40,64 +40,56 @@
|
||||
|
||||
#define MSG_TYPE_I 0
|
||||
#define MSG_LEN_I 1
|
||||
#define MSG_DATA_I 5
|
||||
#define MSG_DATA_I 9
|
||||
|
||||
// msg_type match frp v0.10.0
|
||||
enum msg_type {
|
||||
TypeLogin = 'o',
|
||||
TypeLoginResp = '1',
|
||||
TypeNewProxy = 'p',
|
||||
TypeNewProxyResp = '2',
|
||||
TypeNewWorkConn = 'w',
|
||||
TypeReqWorkConn = 'r',
|
||||
TypeStartWorkConn = 's',
|
||||
TypePing = 'h',
|
||||
TypePong = '4',
|
||||
TypeUdpPacket = 'u',
|
||||
TypeLogin = 'o',
|
||||
TypeLoginResp = '1',
|
||||
TypeNewProxy = 'p',
|
||||
TypeNewProxyResp = '2',
|
||||
TypeCloseProxy = 'c',
|
||||
TypeNewWorkConn = 'w',
|
||||
TypeReqWorkConn = 'r',
|
||||
TypeStartWorkConn = 's',
|
||||
TypeNewVisitorConn = 'v',
|
||||
TypeNewVisitorConnResp = '3',
|
||||
TypePing = 'h',
|
||||
TypePong = '4',
|
||||
TypeUDPPacket = 'u',
|
||||
TypeNatHoleVisitor = 'i',
|
||||
TypeNatHoleClient = 'n',
|
||||
TypeNatHoleResp = 'm',
|
||||
TypeNatHoleClientDetectOK = 'd',
|
||||
TypeNatHoleSid = '5',
|
||||
};
|
||||
|
||||
struct general_response {
|
||||
int code;
|
||||
int code;
|
||||
char *msg;
|
||||
};
|
||||
|
||||
// messages between control connections of frpc and frps
|
||||
struct control_request {
|
||||
int type;
|
||||
char *proxy_name;
|
||||
char *auth_key;
|
||||
int use_encryption;
|
||||
int use_gzip;
|
||||
int pool_count;
|
||||
|
||||
int privilege_mode;
|
||||
char *privilege_key;
|
||||
char *proxy_type;
|
||||
int remote_port;
|
||||
char *custom_domains;
|
||||
char *locations;
|
||||
char *host_header_rewrite;
|
||||
char *http_username;
|
||||
char *http_password;
|
||||
char *subdomain;
|
||||
long timestamp;
|
||||
};
|
||||
|
||||
|
||||
struct control_response {
|
||||
int type;
|
||||
int code;
|
||||
int type;
|
||||
int code;
|
||||
char *msg;
|
||||
};
|
||||
|
||||
struct new_proxy_response {
|
||||
char *run_id;
|
||||
char *proxy_name;
|
||||
char *error;
|
||||
int remote_port;
|
||||
};
|
||||
|
||||
struct work_conn {
|
||||
char *run_id;
|
||||
};
|
||||
|
||||
struct message {
|
||||
char type;
|
||||
char *data_p;
|
||||
size_t data_len;
|
||||
struct __attribute__((__packed__)) msg_hdr {
|
||||
char type;
|
||||
uint64_t length;
|
||||
uint8_t data[];
|
||||
};
|
||||
|
||||
struct start_work_conn_resp {
|
||||
@@ -106,15 +98,12 @@ struct start_work_conn_resp {
|
||||
|
||||
int new_proxy_service_marshal(const struct proxy_service *np_req, char **msg);
|
||||
int msg_type_valid_check(char msg_type);
|
||||
struct message *new_message();
|
||||
char *calc_md5(const char *data, int datalen);
|
||||
char *get_auth_key(const char *token, long int *timestamp);
|
||||
size_t login_request_marshal(char **msg);
|
||||
size_t pack(struct message *req_msg, unsigned char **ret_buf);
|
||||
struct message *unpack(unsigned char *recv_msg, const ushort len);
|
||||
|
||||
// tranlate control request to json string
|
||||
int control_request_marshal(const struct control_request *req, char **msg);
|
||||
struct new_proxy_response *new_proxy_resp_unmarshal(const char *jres);
|
||||
struct login_resp *login_resp_unmarshal(const char *jres);
|
||||
struct start_work_conn_resp *start_work_conn_resp_unmarshal(const char *resp_msg);
|
||||
|
||||
@@ -125,4 +114,6 @@ int new_work_conn_marshal(const struct work_conn *work_c, char **msg);
|
||||
|
||||
void control_response_free(struct control_response *res);
|
||||
|
||||
#endif //_MSG_H_
|
||||
char *get_msg_type(uint8_t type);
|
||||
|
||||
#endif //_MSG_H_
|
||||
|
||||
@@ -19,14 +19,42 @@
|
||||
* *
|
||||
\********************************************************************/
|
||||
|
||||
/** @file xfrp_client.h
|
||||
@brief xfrp client header file
|
||||
@author Copyright (C) 2016 Dengfeng Liu <liudengfeng@kunteng.org>
|
||||
/** @file proxy.c
|
||||
@brief xfrp proxy implemented
|
||||
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
|
||||
*/
|
||||
|
||||
#ifndef _XFRP_CLIENT_H_
|
||||
#define _XFRP_CLIENT_H_
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
void xfrp_client_loop();
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <errno.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#endif //_XFRP_CLIENT_H_
|
||||
|
||||
#include "debug.h"
|
||||
#include "uthash.h"
|
||||
#include "common.h"
|
||||
#include "proxy.h"
|
||||
#include "config.h"
|
||||
|
||||
struct proxy *
|
||||
new_proxy_obj(struct bufferevent *bev)
|
||||
{
|
||||
struct proxy *p = (struct proxy *)calloc(1, sizeof(struct proxy));
|
||||
assert(p);
|
||||
p->bev = bev;
|
||||
p->remote_data_port = -1;
|
||||
p->proxy_name = NULL;
|
||||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
free_proxy_obj(struct proxy *p)
|
||||
{
|
||||
SAFE_FREE(p->proxy_name);
|
||||
SAFE_FREE(p);
|
||||
}
|
||||
63
proxy.h
Normal file
63
proxy.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/* vim: set et ts=4 sts=4 sw=4 : */
|
||||
/********************************************************************\
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License as *
|
||||
* published by the Free Software Foundation; either version 2 of *
|
||||
* the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License*
|
||||
* along with this program; if not, contact: *
|
||||
* *
|
||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02111-1307, USA gnu@gnu.org *
|
||||
* *
|
||||
\********************************************************************/
|
||||
|
||||
/** @file proxy.h
|
||||
@brief xfrp proxy header file
|
||||
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
|
||||
*/
|
||||
|
||||
#ifndef _PROXY_H_
|
||||
#define _PROXY_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <event2/bufferevent.h>
|
||||
#include <event2/buffer.h>
|
||||
#include <event2/listener.h>
|
||||
#include <event2/util.h>
|
||||
#include <event2/event.h>
|
||||
|
||||
#include "client.h"
|
||||
#include "common.h"
|
||||
|
||||
#define IP_LEN 16
|
||||
|
||||
struct ftp_pasv {
|
||||
int code;
|
||||
char ftp_server_ip[IP_LEN];
|
||||
int ftp_server_port;
|
||||
};
|
||||
|
||||
struct proxy {
|
||||
struct bufferevent *bev;
|
||||
char *proxy_name;
|
||||
int remote_data_port; //used in ftp proxy
|
||||
};
|
||||
|
||||
void tcp_proxy_c2s_cb(struct bufferevent *bev, void *ctx);
|
||||
void tcp_proxy_s2c_cb(struct bufferevent *bev, void *ctx);
|
||||
void ftp_proxy_c2s_cb(struct bufferevent *bev, void *ctx);
|
||||
void ftp_proxy_s2c_cb(struct bufferevent *bev, void *ctx);
|
||||
struct proxy *new_proxy_obj(struct bufferevent *bev);
|
||||
void free_proxy_obj(struct proxy *p);
|
||||
void set_ftp_data_proxy_tunnel(const char *ftp_proxy_name,
|
||||
struct ftp_pasv *local_fp,
|
||||
struct ftp_pasv *remote_fp);
|
||||
#endif //_PROXY_H_
|
||||
267
proxy_ftp.c
Normal file
267
proxy_ftp.c
Normal file
@@ -0,0 +1,267 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <errno.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#include <event2/bufferevent.h>
|
||||
#include <event2/buffer.h>
|
||||
#include <event2/listener.h>
|
||||
#include <event2/event.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "uthash.h"
|
||||
#include "common.h"
|
||||
#include "proxy.h"
|
||||
#include "config.h"
|
||||
#include "client.h"
|
||||
|
||||
#define FTP_PRO_BUF 256
|
||||
#define FTP_PASV_PORT_BLOCK 256
|
||||
|
||||
static struct ftp_pasv *new_ftp_pasv();
|
||||
static void free_ftp_pasv(struct ftp_pasv *fp);
|
||||
static struct ftp_pasv * pasv_unpack(char *data);
|
||||
static size_t pasv_pack(struct ftp_pasv *fp, char **pack_p);
|
||||
|
||||
void set_ftp_data_proxy_tunnel(const char *ftp_proxy_name,
|
||||
struct ftp_pasv *local_fp,
|
||||
struct ftp_pasv *remote_fp)
|
||||
{
|
||||
struct proxy_service *ps = NULL;
|
||||
char *ftp_data_proxy_name = get_ftp_data_proxy_name(ftp_proxy_name);
|
||||
|
||||
struct proxy_service *p_services = get_all_proxy_services();
|
||||
HASH_FIND_STR(p_services, ftp_data_proxy_name, ps);
|
||||
if (!ps) {
|
||||
debug(LOG_ERR,
|
||||
"error: ftp data proxy not inserted in proxy-service queue, it should not happend!");
|
||||
goto FTP_DATA_PROXY_TUNNEL_END;
|
||||
}
|
||||
|
||||
ps->local_port = local_fp->ftp_server_port;
|
||||
ps->local_ip = strdup(local_fp->ftp_server_ip);
|
||||
assert(ps->local_ip);
|
||||
|
||||
ps->remote_port = remote_fp->ftp_server_port;
|
||||
|
||||
debug(LOG_DEBUG,
|
||||
"set ftp proxy DATA port [local:remote] = [%d:%d]",
|
||||
ps->local_port, ps->remote_port);
|
||||
|
||||
FTP_DATA_PROXY_TUNNEL_END:
|
||||
free(ftp_data_proxy_name);
|
||||
}
|
||||
|
||||
// read from client-working host port
|
||||
void ftp_proxy_c2s_cb(struct bufferevent *bev, void *ctx)
|
||||
{
|
||||
struct proxy *p = (struct proxy *)ctx;
|
||||
assert(p);
|
||||
struct bufferevent *partner = p->bev;
|
||||
|
||||
struct evbuffer *src, *dst;
|
||||
size_t len;
|
||||
src = bufferevent_get_input(bev);
|
||||
len = evbuffer_get_length(src);
|
||||
if (len < 0)
|
||||
return;
|
||||
|
||||
dst = bufferevent_get_output(partner);
|
||||
assert(dst);
|
||||
|
||||
unsigned char *buf = calloc(1, len);
|
||||
assert(buf);
|
||||
size_t read_n = 0;
|
||||
read_n = evbuffer_remove(src, buf, len);
|
||||
|
||||
// #define FTP_P_DEBUG 1
|
||||
#ifdef FTP_P_DEBUG
|
||||
char *dbg_buf = calloc(1, read_n * 7 + 1);
|
||||
assert(dbg_buf);
|
||||
unsigned int i = 0;
|
||||
for(i = 0; i<read_n && ((2 * i) < (read_n * 2 + 1)); i++) {
|
||||
snprintf(dbg_buf + 7*i, 8, "%3u[%c] ",
|
||||
(unsigned char)buf[i],
|
||||
(unsigned char)buf[i]);
|
||||
}
|
||||
debug(LOG_DEBUG, "FTP Client RECV ctl byte:%s", dbg_buf);
|
||||
debug(LOG_DEBUG, "FTP Client RECV ctl stri:%s", buf);
|
||||
SAFE_FREE(dbg_buf);
|
||||
#endif //FTP_P_DEBUG
|
||||
|
||||
struct ftp_pasv *local_fp = pasv_unpack((char *)buf);
|
||||
|
||||
if (local_fp) {
|
||||
struct common_conf *c_conf = get_common_config();
|
||||
struct ftp_pasv *r_fp = new_ftp_pasv();
|
||||
r_fp->code = local_fp->code;
|
||||
|
||||
if (! c_conf->server_addr) {
|
||||
debug(LOG_ERR, "error: FTP proxy without server ip!");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
strncpy(r_fp->ftp_server_ip, c_conf->server_addr, IP_LEN);
|
||||
r_fp->ftp_server_port = p->remote_data_port;
|
||||
|
||||
if (r_fp->ftp_server_port <= 0) {
|
||||
debug(LOG_ERR, "error: remote ftp data port is not init!");
|
||||
goto FTP_C2S_CB_END;
|
||||
}
|
||||
|
||||
char *pasv_msg = NULL;
|
||||
size_t pack_len = pasv_pack(r_fp, &pasv_msg);
|
||||
if ( ! pack_len){
|
||||
debug(LOG_ERR, "error: ftp proxy replace failed!");
|
||||
SAFE_FREE(pasv_msg);
|
||||
goto FTP_C2S_CB_END;
|
||||
}
|
||||
|
||||
#ifdef FTP_P_DEBUG
|
||||
debug(LOG_DEBUG, "ftp pack result:%s", pasv_msg);
|
||||
#endif //FTP_P_DEBUG
|
||||
|
||||
set_ftp_data_proxy_tunnel(p->proxy_name, local_fp, r_fp);
|
||||
evbuffer_add(dst, pasv_msg, pack_len);
|
||||
SAFE_FREE(pasv_msg);
|
||||
} else {
|
||||
evbuffer_add(dst, buf, read_n);
|
||||
}
|
||||
|
||||
FTP_C2S_CB_END:
|
||||
SAFE_FREE(buf);
|
||||
free_ftp_pasv(local_fp);
|
||||
return;
|
||||
}
|
||||
|
||||
void ftp_proxy_s2c_cb(struct bufferevent *bev, void *ctx)
|
||||
{
|
||||
tcp_proxy_s2c_cb(bev, ctx);
|
||||
}
|
||||
|
||||
static struct ftp_pasv *pasv_unpack(char *data)
|
||||
{
|
||||
char cd_buf[4] = {0};
|
||||
snprintf(cd_buf, 4, "%s", data);
|
||||
int code = atoi(cd_buf);
|
||||
if (code != 227 && code != 211 && code != 229)
|
||||
return NULL;
|
||||
|
||||
struct ftp_pasv *fp = new_ftp_pasv();
|
||||
assert(fp);
|
||||
|
||||
fp->code = code;
|
||||
switch(fp->code) {
|
||||
case 227:
|
||||
{
|
||||
int i = 0, ip_i = 0, port_i = 0, ip_start = 0, comma_n = 0;
|
||||
char port[2][4] = { {0}, {0} };
|
||||
for (i=0; i<strlen(data) && ip_i<IP_LEN; i++) {
|
||||
if (data[i] == '(') {
|
||||
ip_start = 1;
|
||||
continue;
|
||||
}
|
||||
if (! ip_start)
|
||||
continue;
|
||||
|
||||
if (data[i] == ')')
|
||||
break;
|
||||
|
||||
if (data[i] == ','){
|
||||
comma_n++;
|
||||
port_i = 0;
|
||||
if (comma_n < 4){
|
||||
fp->ftp_server_ip[ip_i] = '.';
|
||||
ip_i++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (comma_n >= 4 && port_i < 4) {
|
||||
port[comma_n - 4][port_i] = data[i];
|
||||
port_i++;
|
||||
continue;
|
||||
}
|
||||
fp->ftp_server_ip[ip_i] = data[i];
|
||||
ip_i++;
|
||||
}
|
||||
|
||||
fp->ftp_server_port = atoi(port[0]) * FTP_PASV_PORT_BLOCK + atoi(port[1]);
|
||||
debug(LOG_DEBUG, "ftp pasv unpack:[%s:%d]", fp->ftp_server_ip, fp->ftp_server_port);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
free_ftp_pasv(fp);
|
||||
break;
|
||||
}
|
||||
|
||||
return fp;
|
||||
}
|
||||
|
||||
// the value returned need FREE after using
|
||||
static size_t pasv_pack(struct ftp_pasv *fp, char **pack_p)
|
||||
{
|
||||
*pack_p = (char *)calloc(1, FTP_PRO_BUF);
|
||||
assert(*pack_p);
|
||||
size_t pack_len = 0;
|
||||
|
||||
switch (fp->code){
|
||||
case 227:
|
||||
{
|
||||
char ftp_ip[IP_LEN] = {0};
|
||||
int i =0;
|
||||
for (i=0; i<strlen(fp->ftp_server_ip) && i < IP_LEN; i++) {
|
||||
if (fp->ftp_server_ip[i] == '.') {
|
||||
ftp_ip[i] = ',';
|
||||
continue;
|
||||
}
|
||||
|
||||
ftp_ip[i] = fp->ftp_server_ip[i];
|
||||
}
|
||||
snprintf(*pack_p,
|
||||
FTP_PRO_BUF,
|
||||
"227 Entering Passive Mode (%s,%d,%d).\n",
|
||||
ftp_ip,
|
||||
fp->ftp_server_port / FTP_PASV_PORT_BLOCK,
|
||||
fp->ftp_server_port % FTP_PASV_PORT_BLOCK);
|
||||
|
||||
pack_len = strlen(*pack_p);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
debug(LOG_DEBUG, "ftp pasv protocol data not supportted in pasv_pack");
|
||||
free(*pack_p);
|
||||
break;
|
||||
}
|
||||
|
||||
return pack_len;
|
||||
}
|
||||
|
||||
// need be free after using
|
||||
static struct ftp_pasv *new_ftp_pasv()
|
||||
{
|
||||
struct ftp_pasv *fp = (struct ftp_pasv *)calloc(1, sizeof(struct ftp_pasv));
|
||||
if (! fp)
|
||||
return NULL;
|
||||
|
||||
memset(fp->ftp_server_ip, 0, IP_LEN);
|
||||
fp->ftp_server_port = -1;
|
||||
fp->code = -1;
|
||||
|
||||
return fp;
|
||||
}
|
||||
|
||||
// can be used to free NULL pointer also
|
||||
static void free_ftp_pasv(struct ftp_pasv *fp)
|
||||
{
|
||||
if (!fp)
|
||||
return;
|
||||
|
||||
SAFE_FREE(fp);
|
||||
fp = NULL;
|
||||
}
|
||||
95
proxy_tcp.c
Normal file
95
proxy_tcp.c
Normal file
@@ -0,0 +1,95 @@
|
||||
/* vim: set et ts=4 sts=4 sw=4 : */
|
||||
/********************************************************************\
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License as *
|
||||
* published by the Free Software Foundation; either version 2 of *
|
||||
* the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License*
|
||||
* along with this program; if not, contact: *
|
||||
* *
|
||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02111-1307, USA gnu@gnu.org *
|
||||
* *
|
||||
\********************************************************************/
|
||||
|
||||
/** @file proxy_tcp.c
|
||||
@brief xfrp proxy tcp implemented
|
||||
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <errno.h>
|
||||
#include <syslog.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <event2/bufferevent.h>
|
||||
#include <event2/buffer.h>
|
||||
#include <event2/listener.h>
|
||||
#include <event2/event.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "uthash.h"
|
||||
#include "common.h"
|
||||
#include "proxy.h"
|
||||
#include "config.h"
|
||||
#include "tcpmux.h"
|
||||
|
||||
#define BUF_LEN 2*1024
|
||||
|
||||
// read data from local service
|
||||
void tcp_proxy_c2s_cb(struct bufferevent *bev, void *ctx)
|
||||
{
|
||||
struct common_conf *c_conf = get_common_config();
|
||||
struct proxy_client *client = (struct proxy_client *)ctx;
|
||||
assert(client);
|
||||
struct bufferevent *partner = client->ctl_bev;
|
||||
assert(partner);
|
||||
struct evbuffer *src = bufferevent_get_input(bev);
|
||||
size_t len = evbuffer_get_length(src);
|
||||
assert(len > 0);
|
||||
if (!c_conf->tcp_mux) {
|
||||
struct evbuffer *dst = bufferevent_get_output(partner);
|
||||
evbuffer_add_buffer(dst, src);
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t *buf = (uint8_t *)malloc(len);
|
||||
assert(buf != NULL);
|
||||
memset(buf, 0, len);
|
||||
uint32_t nr = bufferevent_read(bev, buf, len);
|
||||
assert(nr == len);
|
||||
nr = tmux_stream_write(partner, buf, len, &client->stream);
|
||||
if (nr < len) {
|
||||
debug(LOG_DEBUG, "stream_id [%d] len is %d tmux_stream_write %d data, disable read", client->stream.id, len, nr);
|
||||
bufferevent_disable(bev, EV_READ);
|
||||
}
|
||||
}
|
||||
|
||||
// read data from frps
|
||||
// when tcp mux enable this function will not be used
|
||||
void tcp_proxy_s2c_cb(struct bufferevent *bev, void *ctx)
|
||||
{
|
||||
struct proxy_client *client = (struct proxy_client *)ctx;
|
||||
assert(client);
|
||||
struct bufferevent *partner = client->local_proxy_bev;
|
||||
assert(partner);
|
||||
struct evbuffer *src, *dst;
|
||||
src = bufferevent_get_input(bev);
|
||||
size_t len = evbuffer_get_length(src);
|
||||
assert(len > 0);
|
||||
dst = bufferevent_get_output(partner);
|
||||
evbuffer_add_buffer(dst, src);
|
||||
}
|
||||
52
session.c
52
session.c
@@ -1,52 +0,0 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#include "uthash.h"
|
||||
#include "session.h"
|
||||
#include "version.h"
|
||||
#include "debug.h"
|
||||
#include "frame.h"
|
||||
|
||||
uint32_t *sid_index = NULL;
|
||||
|
||||
// need free
|
||||
uint32_t *init_sid_index()
|
||||
{
|
||||
if (NULL == sid_index) {
|
||||
sid_index = (uint32_t *)calloc(1, sizeof(uint32_t));
|
||||
if (NULL == sid_index)
|
||||
return sid_index;
|
||||
|
||||
#ifdef CLIENT_V
|
||||
*sid_index = 1;
|
||||
#elif SERVER
|
||||
*sid_index = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
*sid_index += 2; //xfrp client session id start from 3
|
||||
return sid_index;
|
||||
}
|
||||
|
||||
uint32_t get_current_sid_index()
|
||||
{
|
||||
if (NULL == sid_index) {
|
||||
return *init_sid_index();
|
||||
}
|
||||
|
||||
return *sid_index;
|
||||
}
|
||||
|
||||
uint32_t new_sid()
|
||||
{
|
||||
if (NULL == sid_index) {
|
||||
init_sid_index();
|
||||
return get_current_sid_index();
|
||||
}
|
||||
|
||||
*sid_index += 2;
|
||||
return *sid_index;
|
||||
}
|
||||
11
session.h
11
session.h
@@ -1,11 +0,0 @@
|
||||
#ifndef _SESSION_H_
|
||||
#define _SESSION_H_
|
||||
|
||||
#include "uthash.h"
|
||||
#include "common.h"
|
||||
|
||||
uint32_t *init_sid_index();
|
||||
uint32_t get_current_sid_index();
|
||||
uint32_t new_sid();
|
||||
|
||||
#endif //_SESSION_H_
|
||||
16
systemd/xfrpc.service
Normal file
16
systemd/xfrpc.service
Normal file
@@ -0,0 +1,16 @@
|
||||
# 1. put xfrpc and xfrpc.ini under /usr/local/xfrpc/
|
||||
# 2. put this file (xfrpc.service) at /etc/systemd/system
|
||||
# 3. run `sudo systemctl daemon-reload && sudo systemctl enable xfrpc && sudo systemctl start xfrpc`
|
||||
# Then we can manage xfrpc with `sudo service xfrpc {start|stop|restart|status}`
|
||||
|
||||
|
||||
[Unit]
|
||||
Description=frp c language client
|
||||
Wants=network-online.target
|
||||
After=network.target network-online.target
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/local/xfrpc/xfrpc -c /usr/local/xfrpc/xfrpc.ini -f -d 0
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
610
tcpmux.c
Normal file
610
tcpmux.c
Normal file
@@ -0,0 +1,610 @@
|
||||
/* vim: set et ts=4 sts=4 sw=4 : */
|
||||
/********************************************************************\
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License as *
|
||||
* published by the Free Software Foundation; either version 2 of *
|
||||
* the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License*
|
||||
* along with this program; if not, contact: *
|
||||
* *
|
||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02111-1307, USA gnu@gnu.org *
|
||||
* *
|
||||
\********************************************************************/
|
||||
|
||||
/** @file tcpmux.c
|
||||
@brief xfrp tcp mux implemented
|
||||
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "tcpmux.h"
|
||||
#include "client.h"
|
||||
#include "config.h"
|
||||
#include "debug.h"
|
||||
#include "control.h"
|
||||
|
||||
static uint8_t proto_version = 0;
|
||||
static uint8_t remote_go_away;
|
||||
static uint8_t local_go_away;
|
||||
static uint32_t g_session_id = 1;
|
||||
static struct tmux_stream *cur_stream = NULL;
|
||||
static struct tmux_stream *all_stream;
|
||||
|
||||
static uint32_t ring_buffer_read(struct bufferevent *bev, struct ring_buffer *ring, uint32_t len);
|
||||
static uint32_t ring_buffer_write(struct bufferevent *bev, struct ring_buffer *ring, uint32_t len);
|
||||
|
||||
void
|
||||
add_stream(struct tmux_stream *stream)
|
||||
{
|
||||
HASH_ADD_INT(all_stream, id, stream);
|
||||
}
|
||||
|
||||
void
|
||||
del_stream(uint32_t id)
|
||||
{
|
||||
assert(all_stream != NULL);
|
||||
|
||||
struct tmux_stream *stream = get_stream_by_id(id);
|
||||
if (stream)
|
||||
HASH_DEL(all_stream, stream);
|
||||
}
|
||||
|
||||
struct tmux_stream *
|
||||
get_stream_by_id(uint32_t id)
|
||||
{
|
||||
if (!all_stream) return NULL;
|
||||
|
||||
struct tmux_stream *stream = NULL;
|
||||
HASH_FIND_INT(all_stream, &id, stream);
|
||||
return stream;
|
||||
}
|
||||
|
||||
struct tmux_stream *
|
||||
get_cur_stream()
|
||||
{
|
||||
return cur_stream;
|
||||
}
|
||||
|
||||
void
|
||||
set_cur_stream(struct tmux_stream *stream)
|
||||
{
|
||||
cur_stream = stream;
|
||||
}
|
||||
|
||||
void
|
||||
init_tmux_stream(struct tmux_stream *stream, uint32_t id, enum tcp_mux_state state)
|
||||
{
|
||||
stream->id = id;
|
||||
stream->state = state;
|
||||
stream->recv_window = MAX_STREAM_WINDOW_SIZE;
|
||||
stream->send_window = MAX_STREAM_WINDOW_SIZE;
|
||||
|
||||
memset(&stream->tx_ring, 0, sizeof(struct ring_buffer));
|
||||
memset(&stream->rx_ring, 0, sizeof(struct ring_buffer));
|
||||
|
||||
add_stream(stream);
|
||||
};
|
||||
|
||||
int
|
||||
validate_tcp_mux_protocol(struct tcp_mux_header *tmux_hdr)
|
||||
{
|
||||
if (tmux_hdr->version != proto_version) return 0;
|
||||
|
||||
if (tmux_hdr->type > GO_AWAY) return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
tcp_mux_encode(enum tcp_mux_type type, enum tcp_mux_flag flags, uint32_t stream_id, uint32_t length, struct tcp_mux_header *tmux_hdr)
|
||||
{
|
||||
assert(tmux_hdr);
|
||||
tmux_hdr->version = proto_version;
|
||||
tmux_hdr->type = type;
|
||||
tmux_hdr->flags = htons(flags);
|
||||
tmux_hdr->stream_id = htonl(stream_id);
|
||||
tmux_hdr->length = length?htonl(length):0;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
tcp_mux_flag()
|
||||
{
|
||||
struct common_conf *c_conf = get_common_config();
|
||||
return c_conf->tcp_mux;
|
||||
}
|
||||
|
||||
void
|
||||
reset_session_id() {
|
||||
g_session_id = 1;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
get_next_session_id() {
|
||||
uint32_t id = g_session_id;
|
||||
g_session_id += 2;
|
||||
return id;
|
||||
}
|
||||
|
||||
static void
|
||||
tcp_mux_send_win_update(struct bufferevent *bout, enum tcp_mux_flag flags, uint32_t stream_id, uint32_t delta)
|
||||
{
|
||||
struct tcp_mux_header tmux_hdr;
|
||||
memset(&tmux_hdr, 0, sizeof(tmux_hdr));
|
||||
tcp_mux_encode(WINDOW_UPDATE, flags, stream_id, delta, &tmux_hdr);
|
||||
bufferevent_write(bout, (uint8_t *)&tmux_hdr, sizeof(tmux_hdr));
|
||||
}
|
||||
|
||||
void
|
||||
tcp_mux_send_win_update_syn(struct bufferevent *bout, uint32_t stream_id)
|
||||
{
|
||||
if (!tcp_mux_flag()) return;
|
||||
|
||||
tcp_mux_send_win_update(bout, SYN, stream_id, 0);
|
||||
}
|
||||
|
||||
void
|
||||
tcp_mux_send_win_update_ack(struct bufferevent *bout, uint32_t stream_id, uint32_t delta)
|
||||
{
|
||||
if (!tcp_mux_flag()) return;
|
||||
|
||||
tcp_mux_send_win_update(bout, ZERO, stream_id, 0);
|
||||
}
|
||||
|
||||
void
|
||||
tcp_mux_send_win_update_fin(struct bufferevent *bout, uint32_t stream_id)
|
||||
{
|
||||
if (!tcp_mux_flag()) return;
|
||||
|
||||
tcp_mux_send_win_update(bout, FIN, stream_id, 0);
|
||||
}
|
||||
|
||||
void
|
||||
tcp_mux_send_win_update_rst(struct bufferevent *bout, uint32_t stream_id)
|
||||
{
|
||||
if (!tcp_mux_flag()) return;
|
||||
|
||||
tcp_mux_send_win_update(bout, RST, stream_id, 0);
|
||||
}
|
||||
void
|
||||
tcp_mux_send_data(struct bufferevent *bout, uint16_t flags, uint32_t stream_id, uint32_t length)
|
||||
{
|
||||
if (!tcp_mux_flag()) return;
|
||||
|
||||
struct tcp_mux_header tmux_hdr;
|
||||
memset(&tmux_hdr, 0, sizeof(tmux_hdr));
|
||||
tcp_mux_encode(DATA, flags, stream_id, length, &tmux_hdr);
|
||||
//debug(LOG_DEBUG, "tcp mux [%d] send data len : %d", stream_id, length);
|
||||
bufferevent_write(bout, (uint8_t *)&tmux_hdr, sizeof(tmux_hdr));
|
||||
}
|
||||
|
||||
void
|
||||
tcp_mux_send_ping(struct bufferevent *bout, uint32_t ping_id)
|
||||
{
|
||||
if (!tcp_mux_flag()) return;
|
||||
|
||||
struct tcp_mux_header tmux_hdr;
|
||||
memset(&tmux_hdr, 0, sizeof(tmux_hdr));
|
||||
tcp_mux_encode(PING, SYN, 0, ping_id, &tmux_hdr);
|
||||
//debug(LOG_DEBUG, "tcp mux send ping syn : %d", ping_id);
|
||||
bufferevent_write(bout, (uint8_t *)&tmux_hdr, sizeof(tmux_hdr));
|
||||
}
|
||||
|
||||
static void
|
||||
tcp_mux_handle_ping(struct bufferevent *bout, uint32_t ping_id)
|
||||
{
|
||||
if (!tcp_mux_flag()) return;
|
||||
|
||||
struct tcp_mux_header tmux_hdr;
|
||||
memset(&tmux_hdr, 0, sizeof(tmux_hdr));
|
||||
tcp_mux_encode(PING, ACK, 0, ping_id, &tmux_hdr);
|
||||
//debug(LOG_DEBUG, "tcp mux send ping ack : %d", ping_id);
|
||||
bufferevent_write(bout, (uint8_t *)&tmux_hdr, sizeof(tmux_hdr));
|
||||
}
|
||||
|
||||
static void
|
||||
tcp_mux_send_go_away(struct bufferevent *bout, uint32_t reason)
|
||||
{
|
||||
if (!tcp_mux_flag()) return;
|
||||
|
||||
struct tcp_mux_header tmux_hdr;
|
||||
memset(&tmux_hdr, 0, sizeof(tmux_hdr));
|
||||
tcp_mux_encode(GO_AWAY, 0, 0, reason, &tmux_hdr);
|
||||
//debug(LOG_DEBUG, "tcp mux send ping ack : %d", ping_id);
|
||||
bufferevent_write(bout, (uint8_t *)&tmux_hdr, sizeof(tmux_hdr));
|
||||
|
||||
}
|
||||
|
||||
static int
|
||||
process_flags(uint16_t flags, struct tmux_stream *stream)
|
||||
{
|
||||
uint32_t close_stream = 0;
|
||||
if ( (flags&ACK) == ACK ) {
|
||||
if (stream->state == SYN_SEND)
|
||||
stream->state = ESTABLISHED;
|
||||
} else if ( (flags&FIN) == FIN ) {
|
||||
switch(stream->state) {
|
||||
case SYN_SEND:
|
||||
case SYN_RECEIVED:
|
||||
case ESTABLISHED:
|
||||
stream->state = REMOTE_CLOSE;
|
||||
break;
|
||||
case LOCAL_CLOSE:
|
||||
stream->state = CLOSED;
|
||||
close_stream = 1;
|
||||
break;
|
||||
default:
|
||||
debug(LOG_ERR, "unexpected FIN flag in state %d", stream->state);
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
} else if ( (flags&RST) == RST ) {
|
||||
stream->state = RESET;
|
||||
close_stream = 1;
|
||||
}
|
||||
|
||||
if (close_stream) {
|
||||
debug(LOG_DEBUG, "free stream %d", stream->id);
|
||||
del_proxy_client_by_stream_id(stream->id);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static uint16_t
|
||||
get_send_flags(struct tmux_stream *stream)
|
||||
{
|
||||
uint16_t flags = 0;
|
||||
|
||||
switch (stream->state) {
|
||||
case INIT:
|
||||
flags |= SYN;
|
||||
stream->state = SYN_SEND;
|
||||
break;
|
||||
case SYN_RECEIVED:
|
||||
flags |= ACK;
|
||||
stream->state = ESTABLISHED;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
void
|
||||
send_window_update(struct bufferevent *bout, struct tmux_stream *stream, uint32_t length)
|
||||
{
|
||||
uint32_t max = MAX_STREAM_WINDOW_SIZE;
|
||||
uint32_t delta = (max - length) - stream->recv_window;
|
||||
|
||||
uint16_t flags = get_send_flags(stream);
|
||||
|
||||
if (delta < max/2 && flags == 0)
|
||||
return;
|
||||
|
||||
stream->recv_window += delta;
|
||||
tcp_mux_send_win_update(bout, flags, stream->id, delta);
|
||||
//debug(LOG_DEBUG, "send window update: flags %d, stream_id %d delta %d, recv_window %u length %u",
|
||||
// flags, stream->id, delta, stream->recv_window, length);
|
||||
}
|
||||
|
||||
static int
|
||||
ring_buffer_pop(struct ring_buffer *ring, uint8_t *data, uint32_t len)
|
||||
{
|
||||
assert(ring->sz >= len);
|
||||
assert(data != NULL);
|
||||
|
||||
uint32_t i = 0;
|
||||
while(i < len) {
|
||||
data[i] = ring->data[ring->cur++];
|
||||
if (ring->cur == RBUF_SIZE)
|
||||
ring->cur = 0;
|
||||
i++;
|
||||
ring->sz--;
|
||||
}
|
||||
|
||||
assert(i == len);
|
||||
return len;
|
||||
}
|
||||
|
||||
static int
|
||||
process_data(struct tmux_stream *stream, uint32_t length, uint16_t flags,
|
||||
void (*fn)(uint8_t *, int, void *), void *param)
|
||||
{
|
||||
if (!process_flags(flags, stream)) return 0;
|
||||
|
||||
|
||||
if (length > stream->recv_window) {
|
||||
debug(LOG_ERR, "receive window exceed (remain %d, recv %d)", stream->recv_window, length);
|
||||
return 0;
|
||||
}
|
||||
|
||||
stream->recv_window -= length;
|
||||
|
||||
struct proxy_client *pc = (struct proxy_client *)param;
|
||||
if (!pc || (pc && !pc->local_proxy_bev)) {
|
||||
uint8_t *data = (uint8_t *)calloc(length, 1);
|
||||
ring_buffer_pop(&stream->rx_ring, data, length);
|
||||
fn(data, length, pc);
|
||||
free(data);
|
||||
} else {
|
||||
ring_buffer_write(pc->local_proxy_bev, &stream->rx_ring, length);
|
||||
}
|
||||
|
||||
struct bufferevent *bout = get_main_control()->connect_bev;
|
||||
send_window_update(bout, stream, length);
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
static int
|
||||
incr_send_window(struct bufferevent *bev, struct tcp_mux_header *tmux_hdr, uint16_t flags, struct tmux_stream *stream)
|
||||
{
|
||||
if (!process_flags(flags, stream))
|
||||
return 0;
|
||||
|
||||
uint32_t length = ntohl(tmux_hdr->length);
|
||||
if (stream->send_window == 0) bufferevent_enable(bev, EV_READ);
|
||||
stream->send_window += length;
|
||||
//debug(LOG_DEBUG, "incr_send_window : stream_id %d length %d send_window %d",
|
||||
// stream->id, length, stream->send_window);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
incoming_stream(uint32_t stream_id)
|
||||
{
|
||||
if (local_go_away) {
|
||||
struct bufferevent *bout = get_main_control()->connect_bev;
|
||||
tcp_mux_send_win_update_rst(bout, stream_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO
|
||||
// create new stream
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
handle_tcp_mux_ping(struct tcp_mux_header *tmux_hdr)
|
||||
{
|
||||
uint16_t flags = ntohs(tmux_hdr->flags);
|
||||
uint32_t ping_id = ntohl(tmux_hdr->length);
|
||||
|
||||
if ( (flags&SYN) == SYN) {
|
||||
struct bufferevent *bout = get_main_control()->connect_bev;
|
||||
tcp_mux_handle_ping(bout, ping_id);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
handle_tcp_mux_go_away(struct tcp_mux_header *tmux_hdr)
|
||||
{
|
||||
uint32_t code = ntohl(tmux_hdr->length);
|
||||
switch(code) {
|
||||
case NORMAL:
|
||||
remote_go_away = 1;
|
||||
break;
|
||||
case PROTO_ERR:
|
||||
debug(LOG_ERR, "receive protocol error go away");
|
||||
break;
|
||||
case INTERNAL_ERR:
|
||||
debug(LOG_ERR, "receive internal error go away");
|
||||
break;
|
||||
default:
|
||||
debug(LOG_ERR, "receive unexpected go away");
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
tmux_stream_read(struct bufferevent *bev, struct tmux_stream *stream, uint32_t len)
|
||||
{
|
||||
assert(stream != NULL);
|
||||
|
||||
return ring_buffer_read(bev, &stream->rx_ring, len);
|
||||
}
|
||||
|
||||
int
|
||||
handle_tcp_mux_stream(struct tcp_mux_header *tmux_hdr, handle_data_fn_t fn)
|
||||
{
|
||||
uint32_t stream_id = ntohl(tmux_hdr->stream_id);
|
||||
uint16_t flags = ntohs(tmux_hdr->flags);
|
||||
|
||||
//debug(LOG_DEBUG, "handle_tcp_mux_stream stream_id %d type %d flags %d", stream_id, tmux_hdr->type, flags);
|
||||
|
||||
if ( (flags&SYN) == SYN) {
|
||||
debug(LOG_INFO, "!!!! as xfrpc, it should not be here %d", stream_id);
|
||||
if (!incoming_stream(stream_id))
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct tmux_stream *stream = get_stream_by_id(stream_id);
|
||||
struct proxy_client *pc = get_proxy_client(stream_id);
|
||||
assert(stream != NULL);
|
||||
if (tmux_hdr->type == WINDOW_UPDATE) {
|
||||
struct bufferevent *bev = pc?pc->local_proxy_bev: get_main_control()->connect_bev;
|
||||
if (!incr_send_window(bev, tmux_hdr, flags, stream)) {
|
||||
struct bufferevent *bout = get_main_control()->connect_bev;
|
||||
tcp_mux_send_go_away(bout, PROTO_ERR);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int32_t length = ntohl(tmux_hdr->length);
|
||||
if (!process_data(stream, length, flags, fn, (void *)pc)) {
|
||||
struct bufferevent *bout = get_main_control()->connect_bev;
|
||||
tcp_mux_send_go_away(bout, PROTO_ERR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
static int
|
||||
ring_buffer_append(struct ring_buffer *ring, uint8_t *data, uint32_t len)
|
||||
{
|
||||
uint32_t left = RBUF_SIZE - ring->sz;
|
||||
assert(left >= len);
|
||||
int i = 0;
|
||||
for (; i < len; i++) {
|
||||
ring->data[ring->end++] = data[i];
|
||||
if (ring->end == RBUF_SIZE) ring->end = 0;
|
||||
ring->sz++;
|
||||
if (ring->cur == ring->end) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
ring_buffer_read(struct bufferevent *bev, struct ring_buffer *ring, uint32_t len)
|
||||
{
|
||||
if (ring->sz == RBUF_SIZE) {
|
||||
debug(LOG_ERR, "ring buffer is full");
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t cap = RBUF_SIZE - ring->sz;
|
||||
if (len > cap) {
|
||||
debug(LOG_INFO, "prepare read data [%d] out size ring capacity [%d]", len, cap);
|
||||
len = cap;
|
||||
}
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
bufferevent_read(bev, &ring->data[ring->end++], 1);
|
||||
if (ring->end == RBUF_SIZE) ring->end = 0;
|
||||
ring->sz++;
|
||||
if (ring->cur == ring->end) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
ring_buffer_write(struct bufferevent *bev, struct ring_buffer *ring, uint32_t len)
|
||||
{
|
||||
if (ring->sz == 0) {
|
||||
debug(LOG_ERR, "ring buffer is empty");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (len > ring->sz) {
|
||||
debug(LOG_INFO, "prepare write data [%d] out size ring data [%d]", len, ring->sz);
|
||||
len = ring->sz;
|
||||
}
|
||||
|
||||
while(len > 0) {
|
||||
bufferevent_write(bev, &ring->data[ring->cur++], 1);
|
||||
len--;
|
||||
ring->sz--;;
|
||||
if (ring->cur == RBUF_SIZE) ring->cur = 0;
|
||||
if (ring->cur == ring->end) {
|
||||
assert(ring->sz == 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
tmux_stream_write(struct bufferevent *bev, uint8_t *data, uint32_t length, struct tmux_stream *stream)
|
||||
{
|
||||
switch(stream->state) {
|
||||
case LOCAL_CLOSE:
|
||||
case CLOSED:
|
||||
case RESET:
|
||||
debug(LOG_INFO, "stream %d state is closed", stream->id);
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
struct ring_buffer *tx_ring = &stream->tx_ring;
|
||||
uint32_t left = RBUF_SIZE - tx_ring->sz;
|
||||
if (stream->send_window == 0) {
|
||||
debug(LOG_INFO, "stream %d send_window is zero, length %d left %d", stream->id, length, left);
|
||||
ring_buffer_append(tx_ring, data, length);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t flags = get_send_flags(stream);
|
||||
uint32_t max = length;
|
||||
struct bufferevent *bout = get_main_control()->connect_bev;
|
||||
//debug(LOG_DEBUG, "tmux_stream_write stream id %u: send_window %u tx_ring sz %u length %u",
|
||||
// stream->id, stream->send_window, tx_ring->sz, length);
|
||||
if (stream->send_window < tx_ring->sz) {
|
||||
debug(LOG_INFO, " send_window %u less than tx_ring size %u", stream->send_window, tx_ring->sz);
|
||||
max = stream->send_window;
|
||||
tcp_mux_send_data(bout, flags, stream->id, max);
|
||||
ring_buffer_write(bev, tx_ring, max);
|
||||
ring_buffer_append(tx_ring, data, length);
|
||||
} else if (stream->send_window < tx_ring->sz + length) {
|
||||
debug(LOG_INFO, " send_window %u less than %u", stream->send_window, tx_ring->sz+length);
|
||||
max = stream->send_window;
|
||||
tcp_mux_send_data(bout, flags, stream->id, max);
|
||||
if (tx_ring->sz > 0)
|
||||
ring_buffer_write(bev, tx_ring, tx_ring->sz);
|
||||
bufferevent_write(bev, data, max - tx_ring->sz);
|
||||
ring_buffer_append(tx_ring, data + max - tx_ring->sz, length + tx_ring->sz - max);
|
||||
} else {
|
||||
max = tx_ring->sz + length;
|
||||
tcp_mux_send_data(bout, flags, stream->id, max);
|
||||
if (tx_ring->sz > 0)
|
||||
ring_buffer_write(bev, tx_ring, tx_ring->sz);
|
||||
bufferevent_write(bev, data, length);
|
||||
}
|
||||
|
||||
stream->send_window -= max;
|
||||
|
||||
return max;
|
||||
}
|
||||
|
||||
void
|
||||
tmux_stream_close(struct bufferevent *bout, struct tmux_stream *stream)
|
||||
{
|
||||
int closed = 0;
|
||||
switch(stream->state) {
|
||||
case SYN_SEND:
|
||||
case SYN_RECEIVED:
|
||||
case ESTABLISHED:
|
||||
stream->state = LOCAL_CLOSE;
|
||||
break;
|
||||
case LOCAL_CLOSE:
|
||||
case REMOTE_CLOSE:
|
||||
stream->state = CLOSED;
|
||||
closed = 1;
|
||||
case CLOSED:
|
||||
case RESET:
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t flags = get_send_flags(stream);
|
||||
flags |= FIN;
|
||||
tcp_mux_send_win_update(bout, flags, stream->id, 0);
|
||||
if (closed) {
|
||||
debug(LOG_DEBUG, "del proxy client %d", stream->id);
|
||||
del_proxy_client_by_stream_id(stream->id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
153
tcpmux.h
Normal file
153
tcpmux.h
Normal file
@@ -0,0 +1,153 @@
|
||||
/* vim: set et ts=4 sts=4 sw=4 : */
|
||||
/********************************************************************\
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License as *
|
||||
* published by the Free Software Foundation; either version 2 of *
|
||||
* the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License*
|
||||
* along with this program; if not, contact: *
|
||||
* *
|
||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02111-1307, USA gnu@gnu.org *
|
||||
* *
|
||||
\********************************************************************/
|
||||
|
||||
/** @file tcpmux.h
|
||||
@brief xfrp tcp mux header file
|
||||
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
|
||||
*/
|
||||
|
||||
#ifndef __TCP_MUX__
|
||||
#define __TCP_MUX__
|
||||
|
||||
#include "uthash.h"
|
||||
|
||||
#define MAX_STREAM_WINDOW_SIZE 256*1024
|
||||
#define RBUF_SIZE 32*1024
|
||||
|
||||
struct ring_buffer {
|
||||
uint32_t cur;
|
||||
uint32_t end;
|
||||
uint32_t sz;
|
||||
uint8_t data[RBUF_SIZE];
|
||||
};
|
||||
|
||||
enum go_away_type {
|
||||
NORMAL,
|
||||
PROTO_ERR,
|
||||
INTERNAL_ERR,
|
||||
};
|
||||
|
||||
enum tcp_mux_type {
|
||||
DATA,
|
||||
WINDOW_UPDATE,
|
||||
PING,
|
||||
GO_AWAY,
|
||||
};
|
||||
|
||||
struct tcp_mux_type_desc {
|
||||
enum tcp_mux_type type;
|
||||
char *desc;
|
||||
};
|
||||
|
||||
enum tcp_mux_flag {
|
||||
ZERO,
|
||||
SYN,
|
||||
ACK = 1<<1,
|
||||
FIN = 1<<2,
|
||||
RST = 1<<3,
|
||||
};
|
||||
|
||||
struct __attribute__((__packed__)) tcp_mux_header {
|
||||
uint8_t version;
|
||||
uint8_t type;
|
||||
uint16_t flags;
|
||||
uint32_t stream_id;
|
||||
uint32_t length;
|
||||
};
|
||||
|
||||
struct tcp_mux_flag_desc {
|
||||
enum tcp_mux_flag flag;
|
||||
char *desc;
|
||||
};
|
||||
|
||||
enum tcp_mux_state {
|
||||
INIT = 0,
|
||||
SYN_SEND,
|
||||
SYN_RECEIVED,
|
||||
ESTABLISHED,
|
||||
LOCAL_CLOSE,
|
||||
REMOTE_CLOSE,
|
||||
CLOSED,
|
||||
RESET
|
||||
};
|
||||
|
||||
struct tmux_stream {
|
||||
uint32_t id;
|
||||
uint32_t recv_window;
|
||||
uint32_t send_window;
|
||||
enum tcp_mux_state state;
|
||||
struct ring_buffer tx_ring;
|
||||
struct ring_buffer rx_ring;
|
||||
|
||||
// private arguments
|
||||
UT_hash_handle hh;
|
||||
};
|
||||
|
||||
typedef void (*handle_data_fn_t)(uint8_t *, int, void *);
|
||||
|
||||
void init_tmux_stream(struct tmux_stream *stream, uint32_t id, enum tcp_mux_state state);
|
||||
|
||||
int validate_tcp_mux_protocol(struct tcp_mux_header *tmux_hdr);
|
||||
|
||||
void send_window_update(struct bufferevent *bout, struct tmux_stream *stream, uint32_t length);
|
||||
|
||||
void tcp_mux_send_win_update_syn(struct bufferevent *bout, uint32_t stream_id);
|
||||
|
||||
void tcp_mux_send_win_update_ack(struct bufferevent *bout, uint32_t stream_id, uint32_t delta);
|
||||
|
||||
void tcp_mux_send_win_update_fin(struct bufferevent *bout, uint32_t stream_id);
|
||||
|
||||
void tcp_mux_send_win_update_rst(struct bufferevent *bout, uint32_t stream_id);
|
||||
|
||||
void tcp_mux_send_data(struct bufferevent *bout, uint16_t flags, uint32_t stream_id, uint32_t length);
|
||||
|
||||
void tcp_mux_send_ping(struct bufferevent *bout, uint32_t ping_id);
|
||||
|
||||
uint32_t get_next_session_id();
|
||||
|
||||
void tcp_mux_encode(enum tcp_mux_type type, enum tcp_mux_flag flags,
|
||||
uint32_t stream_id, uint32_t length, struct tcp_mux_header *tmux_hdr);
|
||||
|
||||
int handle_tcp_mux_stream(struct tcp_mux_header *tmux_hdr, handle_data_fn_t fn);
|
||||
|
||||
void handle_tcp_mux_ping(struct tcp_mux_header *tmux_hdr);
|
||||
|
||||
void handle_tcp_mux_go_away(struct tcp_mux_header *tmux_hdr);
|
||||
|
||||
uint32_t tmux_stream_write(struct bufferevent *bev, uint8_t *data, uint32_t length, struct tmux_stream *stream);
|
||||
|
||||
uint32_t tmux_stream_read(struct bufferevent *bev, struct tmux_stream *stream, uint32_t len);
|
||||
|
||||
void reset_session_id();
|
||||
|
||||
struct tmux_stream *get_cur_stream();
|
||||
|
||||
void set_cur_stream(struct tmux_stream *stream);
|
||||
|
||||
void add_stream(struct tmux_stream *stream);
|
||||
|
||||
void del_stream(uint32_t stream_id);
|
||||
|
||||
struct tmux_stream* get_stream_by_id(uint32_t id);
|
||||
|
||||
void tmux_stream_close(struct bufferevent *bout, struct tmux_stream *stream);
|
||||
|
||||
#endif
|
||||
188
utils.c
188
utils.c
@@ -7,6 +7,15 @@
|
||||
#include <sys/time.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <linux/if_link.h>
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
@@ -20,3 +29,182 @@ void s_sleep(unsigned int s, unsigned int u)
|
||||
timeout.tv_usec = u;
|
||||
select(0, NULL, NULL, NULL, &timeout);
|
||||
}
|
||||
|
||||
// is_valid_ip_address:
|
||||
// return 0:ipaddress unlegal
|
||||
int is_valid_ip_address(const char *ip_address)
|
||||
{
|
||||
struct sockaddr_in sa;
|
||||
int result = inet_pton(AF_INET, ip_address, &(sa.sin_addr));
|
||||
return result;
|
||||
}
|
||||
|
||||
// net_if_name: name of network interface, e.g. br-lan
|
||||
// return: 1: error 0:get succeed
|
||||
int get_net_mac(char *net_if_name, char *mac, int mac_len) {
|
||||
int ret = 1;
|
||||
int i = 0;
|
||||
int sock = 0;
|
||||
|
||||
if (mac_len < 12 || net_if_name == NULL) {
|
||||
return 1;
|
||||
}
|
||||
struct ifreq ifreq;
|
||||
|
||||
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if( sock < 0 ) {
|
||||
perror("error sock");
|
||||
goto OUT;
|
||||
}
|
||||
|
||||
strncpy(ifreq.ifr_name, net_if_name, IFNAMSIZ);
|
||||
if( ioctl(sock, SIOCGIFHWADDR,&ifreq) < 0 ) {
|
||||
perror("error ioctl");
|
||||
goto OUT;
|
||||
}
|
||||
|
||||
for( i = 0; i < 6; i++ ){
|
||||
snprintf(mac+2*i, mac_len - 2*i, "%02X",
|
||||
(unsigned char)ifreq.ifr_hwaddr.sa_data[i]);
|
||||
}
|
||||
mac[strlen(mac)] = 0;
|
||||
ret = 0;
|
||||
|
||||
OUT:
|
||||
close(sock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// return: -1: network interface check failed; other: ifname numbers
|
||||
int show_net_ifname()
|
||||
{
|
||||
struct ifaddrs *ifaddr, *ifa;
|
||||
int family, s, n;
|
||||
char host[NI_MAXHOST];
|
||||
|
||||
if (getifaddrs(&ifaddr) == -1) {
|
||||
perror("getifaddrs");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Walk through linked list, maintaining head pointer so we
|
||||
can free list later */
|
||||
|
||||
for (ifa = ifaddr, n = 0; ifa != NULL; ifa = ifa->ifa_next, n++) {
|
||||
if (ifa->ifa_addr == NULL) continue;
|
||||
|
||||
family = ifa->ifa_addr->sa_family;
|
||||
|
||||
/* Display interface name and family (including symbolic
|
||||
form of the latter for the common families) */
|
||||
|
||||
printf("%-8s %s (%d)\n",
|
||||
ifa->ifa_name,
|
||||
(family == AF_PACKET) ? "AF_PACKET" :
|
||||
(family == AF_INET) ? "AF_INET" :
|
||||
(family == AF_INET6) ? "AF_INET6" : "???",
|
||||
family);
|
||||
|
||||
/* For an AF_INET* interface address, display the address */
|
||||
|
||||
if (family == AF_INET || family == AF_INET6) {
|
||||
s = getnameinfo(ifa->ifa_addr,
|
||||
(family == AF_INET) ? sizeof(struct sockaddr_in) :
|
||||
sizeof(struct sockaddr_in6),
|
||||
host, NI_MAXHOST,
|
||||
NULL, 0, NI_NUMERICHOST);
|
||||
if (s != 0) {
|
||||
printf("getnameinfo() failed: %s\n", gai_strerror(s));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
printf("\t\taddress: <%s>\n", host);
|
||||
|
||||
} else if (family == AF_PACKET && ifa->ifa_data != NULL) {
|
||||
struct rtnl_link_stats *stats = (struct rtnl_link_stats *)ifa->ifa_data;
|
||||
|
||||
printf("\t\ttx_packets = %10u; rx_packets = %10u\n"
|
||||
"\t\ttx_bytes = %10u; rx_bytes = %10u\n",
|
||||
stats->tx_packets, stats->rx_packets,
|
||||
stats->tx_bytes, stats->rx_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
freeifaddrs(ifaddr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// return: 0: network interface get succeed
|
||||
int get_net_ifname(char *if_buf, int blen)
|
||||
{
|
||||
if (NULL == if_buf || blen < 8) return -1;
|
||||
|
||||
struct ifaddrs *ifaddr, *ifa;
|
||||
int family, n;
|
||||
int ret = 1;
|
||||
if (getifaddrs(&ifaddr) == -1) {
|
||||
perror("getifaddrs");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int found = 0;
|
||||
char tmp_if_buf[16];
|
||||
memset(tmp_if_buf, 0, sizeof(tmp_if_buf));
|
||||
/* Walk through linked list, maintaining head pointer so we
|
||||
can free list later */
|
||||
for (ifa = ifaddr, n = 0; ifa != NULL; ifa = ifa->ifa_next, n++) {
|
||||
if (ifa->ifa_addr == NULL) continue;
|
||||
|
||||
family = ifa->ifa_addr->sa_family;
|
||||
|
||||
if (family == AF_INET) {
|
||||
// for LEDE/OpenWRT embedded router os
|
||||
if (strcmp(ifa->ifa_name, "br-lan") == 0) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
} else if (family == AF_PACKET &&
|
||||
ifa->ifa_data != NULL &&
|
||||
strcmp(ifa->ifa_name, "lo") != 0) { // skip local loop interface
|
||||
|
||||
strncpy(tmp_if_buf, ifa->ifa_name, 16);
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
strncpy(if_buf, ifa->ifa_name, blen);
|
||||
ret = 0;
|
||||
} else if (tmp_if_buf[0] != 0) {
|
||||
strncpy(if_buf, tmp_if_buf, blen);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
freeifaddrs(ifaddr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// e.g. wWw.Baidu.com/China will be trans into www.baidu.com/China
|
||||
// return: 0:check and trant succeed, 1:failed or domain name is invalid
|
||||
int dns_unified(const char *dname, char *udname_buf, int udname_buf_len)
|
||||
{
|
||||
if (! dname || ! udname_buf || udname_buf_len < strlen(dname)+1)
|
||||
return 1;
|
||||
|
||||
int has_dot = 0;
|
||||
int dlen = strlen(dname);
|
||||
int i = 0;
|
||||
for(i=0; i<dlen; i++) {
|
||||
if(dname[i] == '/')
|
||||
break;
|
||||
|
||||
if (dname[i] == '.' && i != dlen-1)
|
||||
has_dot = 1;
|
||||
|
||||
udname_buf[i] = tolower(dname[i]);
|
||||
}
|
||||
|
||||
if (! has_dot) //domain name should have 1 dot leastly
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
13
utils.h
13
utils.h
@@ -1,6 +1,19 @@
|
||||
#ifndef _UTILS_H_
|
||||
#define _UTILS_H_
|
||||
|
||||
struct mycurl_string {
|
||||
char *ptr;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
void s_sleep(unsigned int s, unsigned int u);
|
||||
|
||||
// is_valid_ip_address:
|
||||
// return 0:ipaddress unlegal
|
||||
int is_valid_ip_address(const char *ip_address);
|
||||
int show_net_ifname();
|
||||
int get_net_ifname(char *if_buf, int blen);
|
||||
int get_net_mac(char *net_if_name, char *mac, int mac_len);
|
||||
int dns_unified(const char *dname, char *udname_buf, int udname_buf_len);
|
||||
|
||||
#endif //_UTILS_H_
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#ifndef _VERSION_H_
|
||||
#define _VERSION_H_
|
||||
|
||||
#define VERSION "0.05."
|
||||
#define PROTOCOL_VERESION "0.10.0"
|
||||
#define VERSION "1.11.587"
|
||||
#define PROTOCOL_VERESION "0.43.0"
|
||||
#define CLIENT_V 1
|
||||
|
||||
#endif //_VERSION_H_
|
||||
|
||||
@@ -19,9 +19,9 @@
|
||||
* *
|
||||
\********************************************************************/
|
||||
|
||||
/** @file xfrp_client.c
|
||||
@brief xfrp client
|
||||
@author Copyright (C) 2016 Dengfeng Liu <liudengfeng@kunteng.org>
|
||||
/** @file xfrpc.c
|
||||
@brief xfrpc client
|
||||
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
@@ -41,12 +41,12 @@
|
||||
#include "uthash.h"
|
||||
#include "control.h"
|
||||
#include "debug.h"
|
||||
#include "xfrp_client.h"
|
||||
#include "xfrpc.h"
|
||||
#include "crypto.h"
|
||||
#include "msg.h"
|
||||
#include "utils.h"
|
||||
|
||||
void xfrp_client_loop()
|
||||
void xfrpc_loop()
|
||||
{
|
||||
init_main_control();
|
||||
run_control();
|
||||
@@ -19,7 +19,14 @@
|
||||
* *
|
||||
\********************************************************************/
|
||||
|
||||
/** @file agent.c
|
||||
@brief agent for router to communicate with frp server
|
||||
@author Copyright (C) 2016 Dengfeng Liu <liudengfeng@kunteng.org>
|
||||
/** @file xfrpc.h
|
||||
@brief xfrpc client header file
|
||||
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
|
||||
*/
|
||||
|
||||
#ifndef _XFRPC_H_
|
||||
#define _XFRPC_H_
|
||||
|
||||
void xfrpc_loop();
|
||||
|
||||
#endif //_XFRPC_H_
|
||||
@@ -1,10 +1,9 @@
|
||||
[common]
|
||||
server_addr = wifidog.kunteng.org
|
||||
server_addr = your_server_ip
|
||||
server_port = 7000
|
||||
auth_token = 123
|
||||
privilege_token = 12345678
|
||||
|
||||
[ssh]
|
||||
type = tcp
|
||||
local_ip = 127.0.0.1
|
||||
local_port = 22
|
||||
remote_port = 6128
|
||||
2
zip.c
2
zip.c
@@ -21,7 +21,7 @@
|
||||
|
||||
/** @file zip.c
|
||||
@brief zlib related function
|
||||
@author Copyright (C) 2016 Dengfeng Liu <liudengfeng@kunteng.org>
|
||||
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
Reference in New Issue
Block a user