326 Commits

Author SHA1 Message Date
Dengfeng Liu
29a854e5d6 Update README.md 2022-05-08 10:19:18 +08:00
Dengfeng Liu
d49331426a Update Makefile 2022-05-07 13:57:34 +08:00
Dengfeng Liu
fc3b88c2d6 Update README.md 2022-05-03 10:55:53 +08:00
Dengfeng Liu
fa8b8c5463 Update README.md 2022-05-01 12:11:20 +08:00
Dengfeng Liu
34ff461506 fix: when libevent get two packet together, should process the second packet
Signed-off-by: Dengfeng Liu <liudf0716@gmail.com>
2022-05-01 11:02:15 +08:00
Dengfeng Liu
4d850336a9 Merge branch 'master' of https://github.com/liudf0716/xfrpc 2022-04-28 15:48:23 +08:00
Dengfeng Liu
a3eb3de9d9 feat: remove mbedtls support
Signed-off-by: Dengfeng Liu <liudf0716@gmail.com>
2022-04-28 15:47:32 +08:00
Dengfeng Liu
c390f1c9c9 Update README.md 2022-04-28 15:37:39 +08:00
Dengfeng Liu
e30d191b4a Update README.md 2022-04-28 15:29:56 +08:00
Dengfeng Liu
d315792cc8 Update README.md 2022-04-28 10:08:10 +08:00
Dengfeng Liu
8ac3ef77bf feat: add frps support
Signed-off-by: Dengfeng Liu <liudf0716@gmail.com>
2022-04-28 09:52:34 +08:00
Dengfeng Liu
ab46826072 Merge branch 'master' of https://github.com/liudf0716/xfrpc 2022-04-17 11:53:38 +00:00
Dengfeng Liu
73f88ee92d feat: support frps 0.41.0
Signed-off-by: Dengfeng Liu <liudf0716@gmail.com>
2022-04-15 10:31:53 +00:00
Dengfeng Liu
a52f59f629 feat: support frps 0.41.0
Signed-off-by: Dengfeng Liu <liudf0716@gmail.com>
2022-04-14 08:57:21 +00:00
Dengfeng Liu
848120d15b Update control.c 2022-04-14 16:23:31 +08:00
Dengfeng Liu
2fc5ea8bdd Update msg.h 2022-04-14 16:10:41 +08:00
Dengfeng Liu
734f5e5448 Update msg.h 2022-04-14 16:08:33 +08:00
Dengfeng Liu
da55d8ac32 Update msg.h 2022-04-14 15:37:08 +08:00
Dengfeng Liu
2de5c3681f Update msg.c 2022-04-14 14:33:51 +08:00
Dengfeng Liu
37badbee7c Update msg.c 2022-04-14 11:06:36 +08:00
Dengfeng Liu
1f90d9ab93 Update msg.c 2022-04-14 10:29:46 +08:00
Dengfeng Liu
33f2bd5648 Update version.h 2022-04-14 10:25:11 +08:00
Dengfeng Liu
bac0ab888d Update login.c 2022-04-14 10:19:16 +08:00
Dengfeng Liu
a557194e9f Update login.h 2022-04-14 10:08:53 +08:00
Dengfeng Liu
f0d29bc624 Update xfrpc_min.ini 2022-04-14 09:38:26 +08:00
Dengfeng Liu
808cda5a6b Update linux.yml 2022-04-12 18:52:14 +08:00
Dengfeng Liu
1fa59df3f5 fix: change to correct email address
Signed-off-by: Dengfeng Liu <liudf0716@gmail.com>
2022-04-10 04:13:59 +00:00
Dengfeng Liu
c2b5e9cc92 Delete frpc.ini 2022-04-10 11:45:02 +08:00
Dengfeng Liu
e41aee6dd0 Update and rename frpc_min.ini to xfrpc_min.ini 2022-04-10 11:44:06 +08:00
Dengfeng Liu
f199b6acba Update README.md 2022-04-08 14:03:42 +08:00
Dengfeng Liu
a8886a1a95 Update README.md 2022-04-08 14:03:17 +08:00
Dengfeng Liu
38f47a28fa Update xfrpc.init 2022-04-06 17:00:18 +08:00
Dengfeng Liu
60d93b7022 Update xfrpc.init 2022-04-06 16:03:29 +08:00
Dengfeng Liu
b38e96e268 Rename xfrpc.ini to xfrpc.init 2022-04-06 15:57:50 +08:00
Dengfeng Liu
88a1f6ecb7 Update xfrpc.ini 2022-04-06 15:45:37 +08:00
Dengfeng Liu
ae37ae4e40 Update xfrpc.conf 2022-04-01 15:50:26 +08:00
Dengfeng Liu
4fd793b183 Update xfrpc.ini 2022-04-01 15:40:27 +08:00
Dengfeng Liu
3288e55453 Update xfrpc.ini 2022-03-31 18:41:12 +08:00
Dengfeng Liu
e9fa00409c Create xfrpc.ini 2022-03-31 17:37:17 +08:00
Dengfeng Liu
60427893f2 Create xfrpc.conf 2022-03-31 17:17:41 +08:00
Dengfeng Liu
ecfa12eb42 Update Makefile 2022-03-30 17:20:17 +08:00
Dengfeng Liu
f8a2dfaf3a fix: replace is_error macro
Signed-off-by: Dengfeng Liu <liudf0716@gmail.com>
2022-03-30 03:12:32 +00:00
Dengfeng Liu
ae0d65b31f Update README.md 2022-03-30 10:37:34 +08:00
Dengfeng Liu
c2aac15b29 Update Makefile 2022-03-29 18:40:36 +08:00
Dengfeng Liu
7ff52050dc Create Makefile 2022-03-29 17:38:10 +08:00
Dengfeng Liu
b71a7c2490 Create linux.yml 2021-12-14 09:52:16 +08:00
Dengfeng Liu
36671d76c0 compile: add lib depend checking
Signed-off-by: Dengfeng Liu <liu_df@qq.com>
2021-12-14 09:45:42 +08:00
Dengfeng Liu
5130aabeb5 Create CMakeParseArguments.cmake 2021-12-14 09:21:22 +08:00
Dengfeng Liu
bacf92da68 Update CMakeLists.txt 2021-12-14 09:19:41 +08:00
Dengfeng Liu
757b5db65a Update README.md 2021-12-13 14:10:55 +08:00
Dengfeng Liu
f3a0668217 fix: fix compile error when openssl version greater than 1.1.0
Signed-off-by: Dengfeng Liu <liu_df@qq.com>
2021-12-13 14:01:23 +08:00
Dengfeng Liu
6d1bbbc4df Update README.md 2021-11-29 14:37:21 +08:00
KerwinKoo
c31106689a remove curl utils funcs
because of do not get ftp data port by http, remove dependence of Libcurl
2017-08-21 10:01:33 +08:00
KerwinKoo
ce522f5675 using ftp_cfg_proxy_name field name instead of ftp_ctl_proxy_name 2017-08-18 14:53:36 +08:00
KerwinKoo
6bd859747a complate ftp remote data port auto match func 2017-08-17 16:41:37 +08:00
KerwinKoo
7d5f53aebb fix BUG: unconnectted when server_addr is IP address 2017-08-17 15:49:26 +08:00
KerwinKoo
f28efdf2b1 add remote_data_port check from responsed message 2017-08-17 15:25:08 +08:00
KerwinKoo
a9a75c6554 fix npr_proxy_remote_port unmarshal bug 2017-08-17 14:37:51 +08:00
KerwinKoo
26f49d26db add new_proxy_response msg unmarshel 2017-08-17 12:06:21 +08:00
KerwinKoo
508ddd60e0 do not use HTTP mothod to init ftp remote data port 2017-08-17 12:05:46 +08:00
KerwinKoo
08b908273a remove unused semicolon 2017-08-17 11:14:37 +08:00
KerwinKoo
8402967a0e save client 2017-08-09 14:56:48 +08:00
KerwinKoo
a2e4264b01 devtmp 2017-08-09 14:42:43 +08:00
KerwinKoo
ce057a05a7 add url commit 2017-08-08 18:23:18 +08:00
KerwinKoo
7515c15123 add url func into utils 2017-08-08 18:19:40 +08:00
KerwinKoo
60871860ae don't check the remote_data_port
because of xfrps will distribute a ftp_data port for each client, no need direct it activity.
2017-08-08 16:51:56 +08:00
KerwinKoo
f8d065b09e add domain check for server_addr field 2017-07-25 17:54:38 +08:00
KerwinKoo
2f2e64ae31 modify domain check code 2017-07-25 17:44:31 +08:00
KerwinKoo
a4812dd596 trans custom_domains to lower 2017-07-25 17:30:42 +08:00
KerwinKoo
2e420e921c fix dns error bug 2017-07-25 16:25:46 +08:00
KerwinKoo
99972f257a delete DNS of server addr 2017-07-25 13:57:07 +08:00
KerwinKoo
8e4ca75d36 Merge pull request #8 from KunTengRom/libdns
debug
2017-07-25 13:42:21 +08:00
KerwinKoo
360019d1a4 debug 2017-07-25 13:41:13 +08:00
KerwinKoo
204c086a03 fix remote_port is -1 will not be set
Signed-off-by: KerwinKoo <gukaiqiang@gmail.com>
2017-07-25 11:25:26 +08:00
KerwinKoo
316834ffd0 don't show port 2017-07-21 16:14:43 +08:00
KerwinKoo
aefbd2e062 add -r to show run id and port 2017-07-21 14:41:45 +08:00
KerwinKoo
ff6f60f079 add Openwrt Router check 2017-07-19 18:24:47 +08:00
KerwinKoo
b2a34fa18f adjust version info 2017-07-19 17:23:29 +08:00
KerwinKoo
984192c200 using right DNS server IP 2017-07-19 16:26:28 +08:00
KerwinKoo
5747426565 adjust code of control 2017-07-19 13:34:25 +08:00
KerwinKoo
0f78a61082 add dns servers static 2017-07-18 17:18:36 +08:00
KerwinKoo
fa852f0b7d fix domain name analyse error 2017-07-18 17:01:23 +08:00
KerwinKoo
ff9ecd1b48 add some debug 2017-07-18 16:22:22 +08:00
KerwinKoo
620c05b6bc add get net mac declear 2017-07-18 16:03:42 +08:00
KerwinKoo
5fffc80367 add commit 2017-07-18 15:36:34 +08:00
KerwinKoo
52ce3d69b4 remove unused file and added into gitignore
remove file:
install_manifest.txt
2017-07-18 15:35:46 +08:00
KerwinKoo
259592e35c change run_id from passive to proactive mode. 2017-07-18 15:32:39 +08:00
KerwinKoo
8866fc3a3a only using 114 dns server ip 2017-07-18 14:53:51 +08:00
KerwinKoo
3dca97a235 get the right ifname 2017-07-18 14:26:55 +08:00
KerwinKoo
9511680227 add get_net_ifname func in utils 2017-07-18 14:16:59 +08:00
KerwinKoo
acb79bcf1f don't using encrypt 2017-07-11 18:13:16 +08:00
KerwinKoo
75adc0a669 adjust source code 2017-07-11 18:08:31 +08:00
KerwinKoo
2ef0200276 adjust control.c 2017-07-11 17:27:32 +08:00
KerwinKoo
7940a4f949 update README 2017-07-11 11:04:28 +08:00
KerwinKoo
81779637ba update README for FTP proxy descript 2017-07-11 11:01:11 +08:00
KerwinKoo
91d6129426 add domain support for ftp
close #4
close #5
2017-07-10 19:32:21 +08:00
KerwinKoo
d333533639 do never use request buffer 2017-07-10 18:28:25 +08:00
KerwinKoo
2429f79721 add free_ftp_pasv after ftp change buffer 2017-07-10 14:01:18 +08:00
KerwinKoo
044626152c rewrite debug info 2017-07-10 09:50:38 +08:00
KerwinKoo
0d7643ceb1 finish ftp proxy support!! 2017-07-07 19:22:57 +08:00
KerwinKoo
0e581ebf6f do ftp proxy 2017-07-07 17:49:15 +08:00
KerwinKoo
2fcfa6a001 add get_ftp_data_proxy_name func 2017-07-07 15:42:14 +08:00
KerwinKoo
546dfb74d3 add commit 2017-07-07 15:13:23 +08:00
KerwinKoo
a02a5a19c7 add new_ftp_data_proxy_service func 2017-07-07 14:56:28 +08:00
KerwinKoo
09b67f7dc6 set code style 2017-07-07 13:45:21 +08:00
KerwinKoo
731584cbd3 fix debug 2017-07-07 13:41:35 +08:00
KerwinKoo
25a994213f do not support domain name for ftp proxy 2017-07-07 11:52:43 +08:00
KerwinKoo
c4a9f4c97e add is_valid_ip_address func in utils 2017-07-07 11:33:13 +08:00
KerwinKoo
a56d0d4d58 add try times when xfrps do connecting 2017-07-07 11:29:18 +08:00
KerwinKoo
9f01265981 finish ftp proxy 2017-07-07 11:22:30 +08:00
KerwinKoo
1e96d85f88 add remote_data_port in proxy check 2017-07-07 10:35:22 +08:00
KerwinKoo
a668a6deff using proxy instead of bufferevent 2017-07-07 10:31:20 +08:00
KerwinKoo
9ae47ffaa4 add new_proxy_buf define 2017-07-07 10:08:10 +08:00
KerwinKoo
8d1c6f69ca add ftp proxy but have not insert remote ip and port
need a method to insert port
2017-07-06 18:47:41 +08:00
KerwinKoo
4bcc36489b debug 2017-07-06 16:43:39 +08:00
KerwinKoo
e9e2bf759a debug 2017-07-06 16:30:12 +08:00
KerwinKoo
c6e3af8ac8 add pasv_pack func 2017-07-06 16:28:49 +08:00
KerwinKoo
5ab2ac455d remove msg field in pasv ftp 2017-07-06 16:00:44 +08:00
KerwinKoo
ddc3aff29b add ftp pasv_unpack func 2017-07-06 15:33:16 +08:00
KerwinKoo
8f75d7c40c modify argu name 2017-07-06 14:21:39 +08:00
KerwinKoo
3c02e4fbc4 add ftp support in proxy 2017-07-06 14:20:49 +08:00
KerwinKoo
5b2b3a63ab remove unused field in proxy_client struct 2017-07-05 20:33:42 +08:00
KerwinKoo
b96e3d9364 remove control_request struct
it's unused
2017-07-05 20:30:16 +08:00
KerwinKoo
f9636ce89c remove name field in proxy_client 2017-07-05 20:20:05 +08:00
KerwinKoo
c1b7585cd5 add is_ftp_proxy check 2017-07-05 18:41:49 +08:00
KerwinKoo
6f350a33d5 change binary name from xfrp_client to xfrpc 2017-07-05 15:24:45 +08:00
KerwinKoo
b3efc1087a remove unused filed in proxy_client struct 2017-07-05 10:00:23 +08:00
KerwinKoo
e57a99cf6a remove unused field in base_conf struct 2017-07-05 09:44:16 +08:00
KerwinKoo
571de7556d add assert after strdup 2017-07-04 17:08:33 +08:00
KerwinKoo
2ffa39e7cb reset heartbeat interval to 30s 2017-07-04 16:37:11 +08:00
KerwinKoo
1aba513a05 update config.c 2017-07-04 16:32:54 +08:00
KerwinKoo
5d0d1f105e update code 2017-07-04 16:29:21 +08:00
KerwinKoo
cb95f86b08 update code 2017-07-04 16:27:42 +08:00
KerwinKoo
7028aa3baa fix bug 9+16*x bits bug 2017-07-04 16:18:12 +08:00
KerwinKoo
94314af51a add declearation warnming in cmake 2017-07-04 10:56:24 +08:00
KerwinKoo
b587a2d30f add tcp_mux in send_msg_frp_server func 2017-07-04 10:53:39 +08:00
KerwinKoo
f2e482aa2e add ftp support check 2017-07-04 10:50:27 +08:00
KerwinKoo
bf4a66f554 using json_object_object_get_ex instead of json_object_object_get func 2017-07-03 17:53:21 +08:00
KerwinKoo
d2b85c64b6 rewrite debug info 2017-07-03 16:44:56 +08:00
KerwinKoo
2fc391d8a0 safe free 2017-07-03 16:35:23 +08:00
KerwinKoo
253432601e using SAFE_FREE instead of normal free 2017-07-03 16:27:04 +08:00
KerwinKoo
2f3eb22ad9 add service type check 2017-07-03 16:21:03 +08:00
KerwinKoo
0452348207 remove debug infor 2017-07-03 16:12:01 +08:00
KerwinKoo
cf4f937c25 gukq 20170703 xfrpc update
fix 25 bits length error bug

Signed-off-by: KerwinKoo <gukaiqiang@gmail.com>
2017-07-03 16:06:28 +08:00
KerwinKoo
9c2d183c84 dbg 2017-06-29 17:56:51 +08:00
KerwinKoo
b28fbd316f dbng 2017-06-29 17:53:40 +08:00
KerwinKoo
2e5637d916 dbg 2017-06-29 17:46:32 +08:00
KerwinKoo
2cb82c3c61 dbg 2017-06-29 17:34:24 +08:00
KerwinKoo
06582cc998 dbg 2017-06-29 17:24:21 +08:00
KerwinKoo
c8641376aa DBG 2017-06-29 17:19:35 +08:00
Dengfeng Liu
1b4f677849 Update README.md 2017-06-29 16:38:12 +08:00
Dengfeng Liu
83d0ffe5f0 Update README.md 2017-06-29 16:36:06 +08:00
KerwinKoo
0914758eb1 fix code fromat 2017-06-29 16:29:10 +08:00
KerwinKoo
878d544174 free some calloc func 2017-06-29 16:25:09 +08:00
KerwinKoo
f8cb721589 rewrite connect_server func 2017-06-29 15:13:33 +08:00
KerwinKoo
f23ab1b528 move login_resp_check to login file 2017-06-29 11:58:11 +08:00
KerwinKoo
154be51eb1 add frame free in base_control_ping 2017-06-29 11:49:45 +08:00
KerwinKoo
a3d6c4c5d5 fix control.c 2017-06-29 11:27:50 +08:00
KerwinKoo
8e6f963f8e add tcp mux check in ping 2017-06-29 11:16:32 +08:00
KerwinKoo
3efda5f37c only init_sid_index when used tcp mux 2017-06-29 10:54:01 +08:00
KerwinKoo
c1bc883f50 fix frame free 2017-06-29 10:47:11 +08:00
KerwinKoo
bff9cbdd1f add free in send_msg_frp_server 2017-06-29 10:44:47 +08:00
KerwinKoo
1680f814d6 fix main_ctl not inited bug 2017-06-29 10:26:44 +08:00
KerwinKoo
1e2b79d2aa add free frame 2017-06-29 10:22:51 +08:00
KerwinKoo
02348cca62 move some code to login 2017-06-29 10:17:20 +08:00
KerwinKoo
6eb8eb3dd9 reworite connect_event_cb func 2017-06-28 17:24:03 +08:00
KerwinKoo
f795e93b07 rewrite control event funcs 2017-06-28 17:11:06 +08:00
KerwinKoo
93f7d19a44 add free_control func 2017-06-28 16:29:48 +08:00
KerwinKoo
da6b6e4d42 set tcp_mux to default: false 2017-06-28 16:09:19 +08:00
KerwinKoo
c4374a7ac6 remove main_control_conn func 2017-06-28 16:03:03 +08:00
KerwinKoo
9888eaee0f rewrite init_main_control type to void 2017-06-28 15:57:18 +08:00
KerwinKoo
a606e6c69f move login code to login file 2017-06-28 15:55:14 +08:00
KerwinKoo
de68f1bdc2 add login source file 2017-06-28 15:43:41 +08:00
KerwinKoo
ef7e3c11bd remove unused codes from cofig 2017-06-28 15:30:22 +08:00
KerwinKoo
cf01fcfdfa rm xfrp_test_server 2017-06-28 14:22:40 +08:00
KerwinKoo
57c37f0431 add user support in login 2017-06-28 14:09:06 +08:00
KerwinKoo
fe86a827c1 reconnect when login failed 2017-06-22 16:12:17 +08:00
KerwinKoo
82f811636b to fix login error ...... 2017-06-21 18:05:12 +08:00
KerwinKoo
5a070f5177 add dnsbase 2017-06-20 20:43:33 +08:00
KerwinKoo
79829448a3 fix some code 2017-06-20 20:14:27 +08:00
KerwinKoo
1af77ad396 Merge pull request #1 from KunTengRom/dev
Dev
2017-06-20 19:56:15 +08:00
KerwinKoo
c811f06be5 Merge branch 'master' into dev 2017-06-20 19:56:02 +08:00
KerwinKoo
d55ddc1617 remove some debug code 2017-06-20 19:29:53 +08:00
KerwinKoo
2052cb7aaf add dnsbase from master 2017-06-20 17:52:41 +08:00
KerwinKoo
2cb775bb6a fix code for LEDE linux 2017-06-20 16:46:52 +08:00
KerwinKoo
6270914f8b dbg for LEDE 2017-06-20 16:39:39 +08:00
KerwinKoo
4098a52dfb add custom_domains fild marshal 2017-06-20 16:13:20 +08:00
KerwinKoo
5abc4e7144 fix some unused coude 2017-06-20 15:18:27 +08:00
KerwinKoo
8a74157dd0 remove some debug message 2017-06-20 15:15:07 +08:00
KerwinKoo
303beb044d match KunTengTeam xfrps 2017-06-20 15:09:41 +08:00
KerwinKoo
d8b63a151a update save at 0619 2017-06-19 18:35:51 +08:00
KerwinKoo
cb4db43dad rewirte send_msg_frp_server debug info 2017-06-19 18:25:14 +08:00
KerwinKoo
9bbaf98ba1 update code 2017-06-19 17:39:40 +08:00
KerwinKoo
c220c32543 fix multy data recved from frps once time
using data tail func
2017-06-19 17:29:51 +08:00
KerwinKoo
ddc0ec168e update the new arch 2017-06-19 16:13:24 +08:00
KerwinKoo
c38b46bcbc using proxy_servce instead of client single
remove new_proxy struct, client struct only as a shell for proxy_service struct
2017-06-19 14:44:24 +08:00
KerwinKoo
718f663e0f update 0616 night 2017-06-16 21:18:48 +08:00
KerwinKoo
6dbe902494 add porxy_service and proxy_service_handler 2017-06-16 18:16:24 +08:00
KerwinKoo
25d3e48ad2 v1 2017-06-16 15:27:42 +08:00
KerwinKoo
b701a544bf fix some compile warning 2017-06-16 14:52:59 +08:00
KerwinKoo
9c3b309acb fix 2017-06-16 10:42:43 +08:00
Dengfeng Liu
5ab1126c79 Update control.c 2017-06-16 10:06:51 +08:00
Dengfeng Liu
ff6b689d4c Update xfrp_client.c 2017-06-16 10:03:06 +08:00
KerwinKoo
fe3c2c129b fix commit codes 2017-06-15 20:46:12 +08:00
KerwinKoo
88d97b2aa4 debug 2017-06-15 20:40:52 +08:00
KerwinKoo
d526cde22b remove some debug info 2017-06-15 20:40:28 +08:00
Dengfeng Liu
9161880d0f Create client.c 2017-06-15 20:37:57 +08:00
Dengfeng Liu
291b2f6b6c Update control.h 2017-06-15 20:36:42 +08:00
Dengfeng Liu
c30779c856 Create control.c 2017-06-15 20:35:10 +08:00
Dengfeng Liu
7e81088e30 Create xfrp_client.c 2017-06-15 20:34:59 +08:00
Dengfeng Liu
097a8b9368 Create client.h 2017-06-15 20:24:49 +08:00
Dengfeng Liu
a057456f6a Create control.c 2017-06-15 20:19:43 +08:00
Dengfeng Liu
666b5cabec Create control.c 2017-06-15 20:18:55 +08:00
Dengfeng Liu
8bada1fda6 Create control.c 2017-06-15 20:16:52 +08:00
Dengfeng Liu
fc40fb82e5 Create control.c 2017-06-15 20:12:45 +08:00
KerwinKoo
f715eec29d finish version 1 2017-06-15 20:01:30 +08:00
KerwinKoo
156db9a0b2 fallow client message 2017-06-15 16:07:39 +08:00
KerwinKoo
4a9c880b9f do client channel 2017-06-15 13:46:03 +08:00
Dengfeng Liu
33711b72cd Create msg.c 2017-06-15 13:45:26 +08:00
Dengfeng Liu
67bbcd5a67 Create msg.c 2017-06-15 13:44:10 +08:00
KerwinKoo
e8666b7d15 start new proxy work connect to server 2017-06-15 11:47:27 +08:00
ZengFei Zhang
d558f7b9df no remote port is required in http type 2017-06-15 09:24:16 +08:00
KerwinKoo
9a817b14d3 dbg 2017-06-14 18:36:16 +08:00
KerwinKoo
036eb47da3 finish multy_recv_buffer_raw 2017-06-14 17:13:24 +08:00
KerwinKoo
b45917435f write multy_recv_buffer_raw again 2017-06-14 17:11:37 +08:00
KerwinKoo
e226e1b856 add multy_recv_buffer_raw func
fix multy tcp buffer recved at once
2017-06-14 16:48:42 +08:00
KerwinKoo
05b81daf40 split recv_cb 2017-06-14 11:57:52 +08:00
KerwinKoo
779055fc72 debug 2017-06-13 18:28:33 +08:00
KerwinKoo
0709ddd9fe ADD Free 2017-06-13 14:16:44 +08:00
KerwinKoo
ca464375ae add tcp-mux match
close tcp-mux now
2017-06-13 14:12:02 +08:00
KerwinKoo
6d5aeabf82 dong start work connection 2017-06-13 11:30:19 +08:00
KerwinKoo
83155c48db fix ping method 2017-06-13 10:43:14 +08:00
KerwinKoo
efb6b23829 add free and debug 2017-06-12 16:10:51 +08:00
KerwinKoo
ceb5bbc95c fix ping error 2017-06-12 15:35:00 +08:00
KerwinKoo
aad98510ac rewrite TypePong func 2017-06-12 15:21:48 +08:00
KerwinKoo
56851a8848 add poong 2017-06-12 15:04:37 +08:00
KerwinKoo
3162a3d114 add and use new_work_conn_marshal 2017-06-12 14:12:22 +08:00
KerwinKoo
6ad4d4543e using session funcs to control 2017-06-12 11:48:28 +08:00
KerwinKoo
33fe62bbcc add session funcs cfile 2017-06-12 11:13:10 +08:00
KerwinKoo
4582aedb33 save 2017-06-09 18:12:57 +08:00
KerwinKoo
81c33b4b4d add login_resp_unmarshal free 2017-06-09 17:34:27 +08:00
KerwinKoo
8353c07059 fix login failed bug when privilege_token is nil 2017-06-09 16:05:34 +08:00
KerwinKoo
3bf8cd11af debug without encrypt fuck!!!! 2017-06-09 15:28:58 +08:00
KerwinKoo
df1d47a263 debug 2017-06-09 10:14:56 +08:00
KerwinKoo
ebc8780514 fuck 2017-06-09 10:14:20 +08:00
KerwinKoo
8407c65f8a fuck encrypt! 2017-06-08 21:00:48 +08:00
KerwinKoo
7c2171ae39 fix encrypt bug
even though i don't know what happend,Its OK after if close debug code ...
2017-06-08 15:33:17 +08:00
KerwinKoo
1d5e76939a rewrite debug mode for encrypt 2017-06-08 11:29:57 +08:00
KerwinKoo
02075a5259 dbg 2017-06-08 11:08:00 +08:00
KerwinKoo
9736e1c6a3 dbg 2017-06-08 11:07:36 +08:00
KerwinKoo
d0b41c747c do again crypt 2017-06-08 11:05:58 +08:00
KerwinKoo
a195307977 do decode debug 2017-06-07 20:55:02 +08:00
KerwinKoo
78de83b6a3 rewrite decrypt_data func 2017-06-07 20:08:10 +08:00
KerwinKoo
c82f0b3319 do again crypt 2017-06-07 19:56:12 +08:00
KerwinKoo
485fbcdc80 handle some unused funcs 2017-06-07 19:33:35 +08:00
KerwinKoo
2c0507bf3c do again new_proxy_request_marshal 2017-06-07 18:01:03 +08:00
KerwinKoo
177955db92 finish encoder 2017-06-07 17:42:48 +08:00
KerwinKoo
0cfe4723b9 finish encrypt example with frp 2017-06-07 15:12:10 +08:00
KerwinKoo
e77b734ac4 udpate 0606 2017-06-06 21:10:27 +08:00
KerwinKoo
6c898dfe9e add test_code for decoder and encoder 2017-06-06 16:32:29 +08:00
KerwinKoo
47ed1930a8 add encrypt data func 2017-06-06 14:46:06 +08:00
KerwinKoo
6d631931a5 todo encrypt_data func 2017-06-05 18:32:51 +08:00
KerwinKoo
e5d337d2c0 add msg reader and writer init funcs 2017-06-05 16:40:59 +08:00
KerwinKoo
d593ee1863 add login_mutex lock 2017-06-05 15:36:26 +08:00
KerwinKoo
0fb850f622 debug 05 2017-06-05 02:53:07 +08:00
KerwinKoo
108285b26c add decoder_init funcs 2017-06-04 16:10:29 +08:00
KerwinKoo
f7a15bd4f1 fix frps iv recved failed bug 2017-06-04 15:25:56 +08:00
KerwinKoo
f1910e5cf7 now working on recv_login_resp_cb 2017-06-02 21:56:56 +08:00
KerwinKoo
3a4b6e0e82 add msg_type_valid_check func 2017-06-02 17:56:52 +08:00
KerwinKoo
996fecbd5c fix login not succed bug 2017-06-02 17:23:22 +08:00
KerwinKoo
5f086651b9 update 2017-06-01 20:32:57 +08:00
KerwinKoo
c814efda45 rename encoder to crypto 2017-06-01 15:57:43 +08:00
KerwinKoo
a7d430fa91 add login_resp_unmarshal 2017-06-01 15:19:01 +08:00
KerwinKoo
ddb2d9fcc5 add debug info 2017-06-01 14:46:21 +08:00
KerwinKoo
d2ab1fd8e3 update 0527
Signed-off-by: KerwinKoo <gukaiqiang@gmail.com>
2017-05-27 19:00:45 +08:00
KerwinKoo
b8a411f9e5 update encode 2017-05-27 15:51:37 +08:00
KerwinKoo
a0aacad505 dbug auth_key to login message 2017-05-27 15:50:24 +08:00
Dengfeng Liu
6c7370e841 Update README.md 2017-05-27 15:06:15 +08:00
Dengfeng Liu
63ba1787e3 Update README.md 2017-05-27 15:03:34 +08:00
Dengfeng Liu
07d68da331 Update README.md 2017-05-27 15:02:57 +08:00
Dengfeng Liu
e00eefcde4 Update README.md 2017-05-27 15:01:29 +08:00
Dengfeng Liu
1a1dc33179 Update README.md 2017-05-27 14:54:32 +08:00
KerwinKoo
d7666dbcd5 update 2017-05-25 21:13:09 +08:00
KerwinKoo
1012f14e73 add main encoder init into mainfuncs 2017-05-25 18:11:11 +08:00
KerwinKoo
4a684ca912 add init_main_encoder funcs 2017-05-25 17:50:53 +08:00
KerwinKoo
59f228ff80 tested encryp_key
the result is

29 201 136 254 206 150 233 65 13 82 120 149 203 228 122 128

same to frpc written by go
2017-05-25 16:05:05 +08:00
KerwinKoo
f1e7c10841 update control for encode 2017-05-25 15:32:26 +08:00
KerwinKoo
59dd6def8e add fastpbkdf2 to CMakefile 2017-05-25 14:20:48 +08:00
KerwinKoo
25987974fe add fastpbkdf2.h for encoder
fastpbkdf2.h is clone from https://github.com/ctz/fastpbkdf2.git
2017-05-25 14:16:51 +08:00
KerwinKoo
d020ed6a37 add encode.c
Frp data connection is encoded by pbkdf2
2017-05-25 11:40:43 +08:00
KerwinKoo
7a9798518b after do send TypeNewProxy 2017-05-25 09:28:35 +08:00
KerwinKoo
adb2edac37 complate send_new_proxy
start send_msg_frp_server with TypeNewProxy
2017-05-24 18:02:26 +08:00
KerwinKoo
f3cf93e308 complate raw_new_proxy func 2017-05-24 15:16:07 +08:00
KerwinKoo
e49eeedec1 add raw_new_proxy func 2017-05-24 14:15:20 +08:00
KerwinKoo
435a531555 add new_proxy struct 2017-05-24 11:46:21 +08:00
KerwinKoo
148e6a20c9 start do proxy_service_start functions 2017-05-24 11:30:06 +08:00
KerwinKoo
b24f4ddc3c fix bug when use unpack 2017-05-24 10:56:27 +08:00
KerwinKoo
6e6be02218 add unpack func 2017-05-24 10:38:13 +08:00
KerwinKoo
321a1fd816 now doing unpack 2017-05-23 21:09:19 +08:00
KerwinKoo
ab4cf89542 add auth ky in login struct 2017-05-23 18:22:46 +08:00
KerwinKoo
a33af765c5 complate login test 2017-05-23 17:33:45 +08:00
KerwinKoo
0f3100fa7d complate frame funcs 2017-05-23 17:14:50 +08:00
KerwinKoo
f4b86e4ca8 finish login and create send_msg_frp_server func 2017-05-23 16:16:22 +08:00
KerwinKoo
2d1d1d675b add puck and msg type in msg model 2017-05-23 14:54:38 +08:00
KerwinKoo
449da60529 add ping func
send cmdNOP and do ticker ping to keep alive with frp
2017-05-23 11:49:24 +08:00
KerwinKoo
1d32f7ce92 add cmd switch into control 2017-05-23 03:37:32 +08:00
KerwinKoo
59f231462c remove session and rewrite frame struct 2017-05-22 18:49:39 +08:00
KerwinKoo
80f6afb6d4 complate request func 2017-05-22 17:50:01 +08:00
KerwinKoo
40fe88a0db create open_session succeed
using open_session connected frps
2017-05-22 17:23:22 +08:00
Dengfeng Liu
d802c5c340 Update README.md 2017-05-22 15:52:13 +08:00
Dengfeng Liu
fbf1b128d7 Update README.md 2017-05-22 15:48:29 +08:00
KerwinKoo
8dea9caeaa add frame struct 2017-05-22 15:32:58 +08:00
Dengfeng Liu
f9312e8188 Update README.md 2017-05-22 14:29:22 +08:00
KerwinKoo
defc63a726 add control struct 2017-05-22 14:13:26 +08:00
KerwinKoo
7c39e9caa8 compile continue. but tomorry is weekday
I will develop in home NOT IN company

Signed-off-by: KerwinKoo <gukaiqiang@gmail.com>
2017-05-19 21:08:43 +08:00
KerwinKoo
ab9580287c update type enum
Signed-off-by: KerwinKoo <gukaiqiang@gmail.com>
2017-05-19 21:01:40 +08:00
KerwinKoo
df4d2b0904 update msg_type to match frp 0.10.0
Signed-off-by: KerwinKoo <gukaiqiang@gmail.com>
2017-05-19 19:27:46 +08:00
Dengfeng Liu
8c002aece2 Update README.md 2017-05-19 18:45:51 +08:00
KerwinKoo
6ef9ab241c fix forward-declare forbiden bug
ISO C++ Standard will WARNING forward-declare forbiden of enum type because without knowing the type of enum.

Signed-off-by: KerwinKoo <gukaiqiang@gmail.com>
2017-05-19 14:04:03 +08:00
KerwinKoo
fc50424ab6 add login protocol struct
Signed-off-by: KerwinKoo <gukaiqiang@gmail.com>
2017-05-19 13:33:09 +08:00
KerwinKoo
b1f2756f6d remove unused header files
Signed-off-by: KerwinKoo <gukaiqiang@gmail.com>
2017-05-18 20:25:24 +08:00
KerwinKoo
a0798afeab modify README
Signed-off-by: KerwinKoo <gukaiqiang@gmail.com>
2017-05-18 20:15:07 +08:00
KerwinKoo
b4249d0be1 Merge branch 'master' of github.com:KunTengRom/xfrp 2017-05-18 20:12:27 +08:00
KerwinKoo
5e7437617f ignore bin path
Signed-off-by: KerwinKoo <gukaiqiang@gmail.com>
2017-05-18 20:12:00 +08:00
ZengFei Zhang
2e499f25c5 Update README.md 2017-05-18 19:16:51 +08:00
KerwinKoo
80746008ff git igore bin files that generated by "make"
Signed-off-by: KerwinKoo <gukaiqiang@gmail.com>
2017-05-18 16:20:20 +08:00
50 changed files with 4848 additions and 730 deletions

31
.github/workflows/linux.yml vendored Normal file
View 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

7
.gitignore vendored
View File

@@ -37,3 +37,10 @@ CMakeFiles/
CMakeCache.txt
Makefile
cmake_install.cmake
install_manifest.txt
# bin generated
xfrpc
xfrp_test_server
bin
.vscode

View File

@@ -2,21 +2,41 @@ cmake_minimum_required(VERSION 2.6)
project(xfrp C)
set(src_xfrp_test_server
xfrp_test_server.c
)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
set(src_xfrp_client
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
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
)
set(libs
@@ -31,14 +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})
add_executable(xfrp_test_server ${src_xfrp_test_server})
target_link_libraries(xfrp_test_server ${test_libs})
install(TARGETS xfrp_client xfrp_test_server
install(TARGETS xfrpc
RUNTIME DESTINATION bin
)

View File

@@ -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:

167
README.md
View File

@@ -1,63 +1,170 @@
![xfrp](https://github.com/KunTengRom/xfrp/blob/master/logo.png)
![xfrpc](https://github.com/liudf0716/xfrpc/blob/master/logo.png)
[![Build Status][1]][2]
[1]: https://travis-ci.org/KunTengRom/xfrp.svg?branch=master
[2]: https://travis-ci.org/KunTengRom/xfrp
## 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) and [LEDE](https://github.com/lede-project/source) system
xfrp was [frp](https://github.com/fatedier/frp) client implemented by c for OpenWRT system
The motivation to start xfrpc 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 xfrpc project to support frp.
if you dont know what is frp, please visit [this](https://github.com/fatedier/frp)
## Development Status
the motivation to start xfrp project is that we are OpenWRTer, and openwrt usually ran in wireless router 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 target to fully compatible with latest frp release.
## compile
the following table is detail compatible feature:
| Feature | xfrpc | frpc |
| ------------- | ------------- | ---------|
| tcp | Yes | Yes |
| tcpmux | No | Yes |
| http | Yes | Yes |
| https | Yes | Yes |
| udp | No | Yes |
| p2p | No | Yes |
| xtcp | No | Yes |
| vistor | No | Yes |
## Architecture
![Architecture](https://github.com/fatedier/frp/blob/dev/doc/pic/architecture.png?raw=true)
Architecture quote from [frp](https://github.com/fatedier/frp) project, replace frpc with xfrpc.
## 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
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.
git clone https://github.com/KunTengRom/xfrp.git
Install json-c libevent in ubuntu 20.04 LTS
```shell
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
```
## quick start
## 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
tcp_mux = false
```
run in release mode :
**attention! cause xfrpc does not support tcp_mux yet, please disable tcp_mux otherwise xfrpc can not connect frps**
```shell
xfrp_client -c frpc_mini.ini -d 0
run frps
```
./frps -c frps.ini
```
+ xfrpc tcp
```
#xfrpc_mini.ini
[common]
server_addr = your_server_ip
server_port = 7000
## todo list
[ssh]
type = tcp
local_ip = 127.0.0.1
local_port = 22
remote_port = 6128
```
- support compression
+ xfrpc http
- support encrypt
```
# xfrpc_mini.ini
[common]
server_addr = x.x.x.x
server_port = 7000
- support previlege mode
[web]
type = http
local_port = 80
custom_domains = www.example.com
```
+ Run in debug mode
## how to contribute our project
```shell
xfrpc -c frpc_mini.ini -f -d 7
```
See [CONTRIBUTING](https://github.com/KunTengRom/xfrp/blob/master/CONTRIBUTING.md) for details on submitting patches and the contribution workflow.
+ Run in release mode :
```shell
xfrpc -c frpc_mini.ini -d 0
```
## How to contribute our project
See [CONTRIBUTING](https://github.com/liudf0716/xfrpc/blob/master/CONTRIBUTING.md) for details on submitting patches and the contribution workflow.
## Contact
@@ -65,3 +172,9 @@ QQ群 [331230369](https://jq.qq.com/?_wv=1027&k=47QGEhL)
## Please support us and star our project
## 广告
想学习OpenWrt开发但是摸不着门道自学没毅力基础太差怕太难学不会跟着佐大学OpenWrt开发入门培训班助你能学有所成
报名地址https://forgotfun.org/2018/04/openwrt-training-2018.html

View File

@@ -21,5 +21,5 @@
/** @file agent.c
@brief agent for router to communicate with frp server
@author Copyright (C) 2016 Dengfeng Liu <liudengfeng@kunteng.org>
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
*/

252
client.c
View File

@@ -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>
@@ -52,164 +52,140 @@
#include "const.h"
#include "uthash.h"
#include "zip.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);
#include "common.h"
#include "proxy.h"
#include "utils.h"
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) {
struct proxy_client *client = (struct proxy_client *)ctx;
if (what & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) {
debug(LOG_DEBUG, "working connection closed!");
bufferevent_free(bev);
free_proxy_client(client);
}
}
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)) {
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] : %s", client->ps->local_ip, client->ps->local_port, strerror(errno));
bufferevent_free(bev);
}
} else if (what & BEV_EVENT_CONNECTED) {
if (client->data_tail_size > 0) {
debug(LOG_DEBUG, "send client data ...");
send_client_data_tail(client);
}
}
}
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;
size_t len;
src = bufferevent_get_input(bev);
len = evbuffer_get_length(src);
if (len > 4) {
dst = bufferevent_get_output(partner);
evbuffer_drain(src, 4);
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);
unsigned int header = htonl(len);
evbuffer_prepend(src, &header, sizeof(unsigned int));
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(const struct proxy_client *client)
void
start_xfrp_tunnel(struct proxy_client *client)
{
struct event_base *base = client->base;
struct common_conf *c_conf = get_common_config();
struct bufferevent *b_svr = connect_server(base, c_conf->server_addr, c_conf->server_port);
if (!b_svr) {
if (! client->ctl_bev) {
debug(LOG_ERR, "proxy client control bev is invalid!");
return;
}
struct bufferevent *b_clt = connect_server(base, client->local_ip, client->local_port);
if (!b_clt) {
bufferevent_free(b_svr);
struct event_base *base = client->base;
struct common_conf *c_conf = get_common_config();
struct proxy_service *ps = client->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 ) {
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 ) {
debug(LOG_ERR, "frpc tunnel connect local proxy port [%d] failed!", ps->local_port);
bufferevent_free(client->ctl_bev);
return;
}
debug(LOG_DEBUG, "proxy server [%s:%d] <---> client [%s:%d]",
c_conf->server_addr, c_conf->server_port, client->local_ip, client->local_port);
bufferevent_setcb(b_svr, xfrp_decrypt_cb, NULL, xfrp_event_cb, b_clt);
bufferevent_setcb(b_clt, xfrp_encrypt_cb, NULL, xfrp_event_cb, b_svr);
bufferevent_enable(b_svr, EV_READ|EV_WRITE);
bufferevent_enable(b_clt, EV_READ|EV_WRITE);
send_msg_frp_server(NewWorkConn, client, b_svr);
c_conf->server_addr,
ps->remote_port,
ps->local_ip ? ps->local_ip:"::1",
ps->local_port);
bufferevent_data_cb proxy_s2c_cb, proxy_c2s_cb;
if (is_ftp_proxy(client->ps)) {
proxy_c2s_cb = ftp_proxy_c2s_cb;
proxy_s2c_cb = ftp_proxy_s2c_cb;
//ctl_prox->remote_data_port = client->ps->remote_data_port;
//ctl_prox->proxy_name = strdup(ps->proxy_name);
} else {
proxy_c2s_cb = tcp_proxy_c2s_cb; // local service <---> xfrpc
proxy_s2c_cb = tcp_proxy_s2c_cb; // frps <---> xfrpc
}
bufferevent_setcb(client->ctl_bev,
proxy_s2c_cb,
NULL,
xfrp_worker_event_cb,
client);
bufferevent_setcb(client->local_proxy_bev,
proxy_c2s_cb,
NULL,
xfrp_proxy_event_cb,
client);
bufferevent_enable(client->ctl_bev, EV_READ|EV_WRITE);
bufferevent_enable(client->local_proxy_bev, EV_READ|EV_WRITE);
}
void free_proxy_client(struct proxy_client *client)
int
send_client_data_tail(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);
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 del_proxy_client(struct proxy_client *client)
void
free_proxy_client(struct proxy_client *client)
{
if (client->ev_timeout) evtimer_del(client->ev_timeout);
free(client);
}
void
del_proxy_client(struct proxy_client *client)
{
struct proxy_client *all_pc = get_all_pc();
if (!client || !all_pc ) {
@@ -221,3 +197,21 @@ 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)
{
struct proxy_service *ps = NULL;
struct proxy_service *all_ps = get_all_proxy_services();
HASH_FIND_STR(all_ps, proxy_name, ps);
return ps;
}
struct proxy_client *
new_proxy_client()
{
struct proxy_client *client = calloc(1, sizeof(struct proxy_client));
assert(client);
return client;
}

View File

@@ -21,33 +21,61 @@
/** @file client.h
@brief xfrp client proxy client related
@author Copyright (C) 2016 Dengfeng Liu <liudengfeng@kunteng.org>
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
*/
#ifndef _CLIENT_H_
#define _CLIENT_H_
#include <stdint.h>
#include "uthash.h"
#include "common.h"
struct event_base;
struct base_conf;
struct bufferevent;
struct event;
struct proxy_service;
struct proxy_client {
struct event_base *base;
struct bufferevent *ctl_bev;
struct bufferevent *ctl_bev; // xfrpc proxy <---> frps
struct bufferevent *local_proxy_bev; // xfrpc proxy <---> local service
struct event *ev_timeout;
struct base_conf *bconf;
char *name; // pointer to bconf->name
//private arguments
UT_hash_handle hh;
int connected;
int work_started;
struct proxy_service *ps;
unsigned char *data_tail; // storage untreated data
size_t data_tail_size;
};
struct proxy_service {
char *proxy_name;
char *proxy_type;
char *ftp_cfg_proxy_name;
int use_encryption;
int use_compression;
char *local_ip;
int local_port;
int remote_port;
char *custom_domains;
int remote_data_port;
int local_port;
// http and https only
char *custom_domains;
char *subdomain;
char *locations;
char *host_header_rewrite;
char *http_user;
char *http_pwd;
//provate arguments
UT_hash_handle hh;
};
@@ -55,10 +83,18 @@ struct proxy_client {
// frp server send xfrp client NoticeUserConn request
// when xfrp client receive that request, it will start
// frp tunnel
void start_frp_tunnel(const struct proxy_client *client);
// if client has data-tail(not NULL), client value will be changed
void start_xfrp_tunnel(struct proxy_client *client);
void del_proxy_client(struct proxy_client *client);
void free_proxy_client(struct proxy_client *client);
#endif
struct proxy_service *get_proxy_service(const char *proxy_name);
int send_client_data_tail(struct proxy_client *client);
int is_ftp_proxy(const struct proxy_service *ps);
struct proxy_client *new_proxy_client();
#endif //_CLIENT_H_

View 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()

View 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)

View 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)

View File

@@ -0,0 +1,340 @@
#.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)
if(OPENSSL_INCLUDE_DIR AND EXISTS "${OPENSSL_INCLUDE_DIR}/openssl/opensslv.h")
file(STRINGS "${OPENSSL_INCLUDE_DIR}/openssl/opensslv.h" openssl_version_str
REGEX "^# *define[\t ]+OPENSSL_VERSION_NUMBER[\t ]+0x([0-9a-fA-F])+.*")
# 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}")
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)

View 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()

View 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()

View File

@@ -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);
@@ -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) {
@@ -145,7 +148,8 @@ parse_commandline(int argc, char **argv)
case 'c':
if (optarg) {
confile = strdup(optarg);
confile = strdup(optarg); //never free it
assert(confile);
flag = 1;
}
break;
@@ -162,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);

24
common.c Normal file
View File

@@ -0,0 +1,24 @@
#include "uthash.h"
#include "common.h"
uint64_t ntoh64(const uint64_t input)
{
uint64_t rval;
uint8_t *data = (uint8_t *)&rval;
data[0] = input >> 56;
data[1] = input >> 48;
data[2] = input >> 40;
data[3] = input >> 32;
data[4] = input >> 24;
data[5] = input >> 16;
data[6] = input >> 8;
data[7] = input >> 0;
return rval;
}
uint64_t hton64(const uint64_t input)
{
return (ntoh64(input));
}

40
common.h Normal file
View File

@@ -0,0 +1,40 @@
#ifndef _COMMON_H_
#define _COMMON_H_
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include "uthash.h"
#define BIGENDIAN_64BIT 1
//#define BIGENDIAN_32BIT 1
#define SAFE_FREE(m) \
if (m) free(m)
uint64_t ntoh64(const uint64_t input);
uint64_t hton64(const uint64_t input);
#ifdef BIGENDIAN_64BIT
typedef uint64_t msg_size_t;
#define msg_ntoh(l) \
ntoh64(l)
#define msg_hton(b) \
hton64(b)
#elif BIGENDIAN_32BIT
#define msg_ntoh(l) \
ntohl(l)
#define msg_hton(b) \
htonl(b)
typedef uint32_t msg_size_t;
#endif //BIGENDIAN_64BIT
typedef unsigned short ushort;
#endif //_COMMON_H_

316
config.c
View File

@@ -21,24 +21,31 @@
/** @file config.c
@brief xfrp client config related
@author Copyright (C) 2016 Dengfeng Liu <liudengfeng@kunteng.org>
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <time.h>
#include <syslog.h>
#include <sys/utsname.h>
#include "ini.h"
#include "uthash.h"
#include "config.h"
#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 void new_ftp_data_proxy_service(struct proxy_service *ftp_ps);
struct common_conf *get_common_config()
{
@@ -56,17 +63,24 @@ void free_common_config()
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);
SAFE_FREE(c_conf->server_ip);
};
void set_common_server_ip(const char *ip)
{
struct common_conf *c_conf = get_common_config();
c_conf->server_ip = strdup(ip);
assert(c_conf->server_ip);
debug(LOG_DEBUG, "server IP address: [%s]", c_conf->server_ip);
}
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);
}
@@ -75,6 +89,11 @@ 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))
@@ -83,14 +102,19 @@ static int is_true(const char *val)
return 0;
}
static char *get_valid_type(const char *val)
static const char *get_valid_type(const char *val)
{
if (!val)
return NULL;
#define MATCH_VALUE(s) strcmp(val, s) == 0
if (MATCH_VALUE("tcp") || MATCH_VALUE("http") || MATCH_VALUE("https") || MATCH_VALUE("udp")) {
return strdup(val);
if (MATCH_VALUE("tcp") ||
MATCH_VALUE("http") ||
MATCH_VALUE("https") ||
MATCH_VALUE("udp") ||
MATCH_VALUE("ftp")) {
return val;
}
return NULL;
@@ -98,7 +122,7 @@ static 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;
}
@@ -107,118 +131,173 @@ static void dump_common_conf()
c_conf->server_addr, c_conf->server_port, c_conf->auth_token, c_conf->privilege_token, c_conf->heartbeat_interval, c_conf->heartbeat_timeout);
}
static void dump_proxy_client(const int index, const struct proxy_client *pc)
static void dump_proxy_service(const int index, struct proxy_service *ps)
{
if (!pc || !pc->bconf)
if (!ps)
return;
if (1 == pc->bconf->privilege_mode) {
if (NULL == pc->bconf->privilege_token) {
debug(LOG_ERR, "Proxy [%s] error: privilege_token must be set when privilege_mode = true", pc->bconf->name);
exit(0);
}
if (0 > pc->remote_port) {
debug(LOG_ERR, "Proxy [%s] error: remote_port must be set when privilege_mode = true", pc->bconf->name);
exit(0);
}
}
if (0 > pc->local_port) {
debug(LOG_ERR, "Proxy [%s] error: local_port not found", pc->bconf->name);
if (0 > ps->local_port) {
debug(LOG_ERR, "Proxy [%s] error: local_port not found", ps->proxy_name);
exit(0);
}
if (NULL == pc->bconf->type) {
pc->bconf->type = strdup("tcp");
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, "Proxy %d: {name:%s, local_port:%d, type:%s}", index, pc->bconf->name, pc->local_port, pc->bconf->type);
debug(LOG_DEBUG,
"Proxy service %d: {name:%s, local_port:%d, type:%s}",
index,
ps->proxy_name,
ps->local_port,
ps->proxy_type);
}
static void dump_all_pc()
static void dump_all_ps()
{
struct proxy_client *s = NULL, *tmp = NULL;
struct proxy_service *ps = NULL, *tmp = NULL;
int index = 0;
HASH_ITER(hh, p_clients, s, tmp) {
dump_proxy_client(index++, s);
HASH_ITER(hh, p_services, ps, tmp) {
dump_proxy_service(index++, ps);
}
}
static struct proxy_client *new_proxy_client(const char *name)
static struct proxy_service *new_proxy_service(const char *name)
{
struct proxy_client *pc = calloc(sizeof(struct proxy_client), 1);
assert(pc);
struct base_conf *bc = calloc(sizeof(struct base_conf), 1);
assert(bc);
if (! name)
return NULL;
struct proxy_service *ps = (struct proxy_service *)calloc(sizeof(struct proxy_service), 1);
assert(ps);
assert(c_conf);
bc->name = strdup(name);
bc->use_encryption = 0;
bc->use_gzip = 0;
bc->privilege_mode = 0;
bc->pool_count = 0;
pc->bconf = bc;
pc->name = strdup(name);
pc->local_port = -1;
pc->remote_port = -1;
ps->proxy_name = strdup(name);
ps->ftp_cfg_proxy_name = NULL;
assert(ps->proxy_name);
if (c_conf->auth_token)
bc->auth_token = strdup(c_conf->auth_token);
if (c_conf->privilege_token)
bc->privilege_token = strdup(c_conf->privilege_token);
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;
return pc;
ps->custom_domains = NULL;
ps->subdomain = NULL;
ps->locations = NULL;
ps->host_header_rewrite = NULL;
ps->http_user = NULL;
ps->http_pwd = NULL;
return ps;
}
static int service_handler(void *user, const char *section, const char *nm, const char *value)
// create a new proxy service with suffix "_ftp_data_proxy"
static void new_ftp_data_proxy_service(struct proxy_service *ftp_ps)
{
struct proxy_client *pc = NULL;
struct proxy_service *ps = NULL;
char *ftp_data_proxy_name = get_ftp_data_proxy_name((const char *)ftp_ps->proxy_name);
if (strcmp(section, "common") == 0)
HASH_FIND_STR(p_services, 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, p_services, 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 (strcmp(section, "common") == 0) {
SAFE_FREE(section);
return 0;
HASH_FIND_STR(p_clients, section, pc);
if (!pc) {
pc = new_proxy_client(section);
HASH_ADD_KEYPTR(hh, p_clients, pc->name, strlen(pc->name), pc);
debug(LOG_DEBUG, "Section[%s] not found in p_clients, add pc[%s]",
section, pc->name);
}
HASH_FIND_STR(p_services, section, ps);
if (!ps) {
ps = new_proxy_service(section);
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);
}
#define MATCH_NAME(s) strcmp(nm, s) == 0
#define TO_BOOL(v) strcmp(value, "true") ? 0:1
if (MATCH_NAME("type")) {
pc->bconf->type = get_valid_type(value);
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")) {
pc->local_ip = strdup(value);
ps->local_ip = strdup(value);
assert(ps->local_ip);
} else if (MATCH_NAME("local_port")) {
pc->local_port = atoi(value);
ps->local_port = atoi(value);
} else if (MATCH_NAME("use_encryption")) {
pc->bconf->use_encryption = is_true(value);
} else if (MATCH_NAME("use_gzip")) {
pc->bconf->use_gzip = is_true(value);
} else if (MATCH_NAME("privilege_mode")) {
pc->bconf->privilege_mode = is_true(value);
} else if (MATCH_NAME("pool_count")) {
pc->bconf->pool_count = atoi(value);
ps->use_encryption = is_true(value);
} else if (MATCH_NAME("remote_port")) {
pc->remote_port = atoi(value);
ps->remote_port = atoi(value);
} else if (MATCH_NAME("remote_data_port")) {
ps->remote_data_port = atoi(value);
} else if (MATCH_NAME("http_user")) {
pc->bconf->http_username = strdup(value);
ps->http_user = strdup(value);
assert(ps->http_user);
} else if (MATCH_NAME("http_pwd")) {
pc->bconf->http_password = strdup(value);
ps->http_pwd = strdup(value);
assert(ps->http_pwd);
} else if (MATCH_NAME("subdomain")) {
pc->bconf->subdomain= strdup(value);
ps->subdomain = strdup(value);
assert(ps->http_pwd);
} else if (MATCH_NAME("custom_domains")) {
pc->custom_domains= strdup(value);
ps->custom_domains = strdup(value);
assert(ps->custom_domains);
} else if (MATCH_NAME("locations")) {
pc->locations= strdup(value);
ps->locations = strdup(value);
assert(ps->locations);
} else if (MATCH_NAME("host_header_rewrite")) {
pc->bconf->host_header_rewrite= strdup(value);
ps->host_header_rewrite = strdup(value);
assert(ps->host_header_rewrite);
} else if (MATCH_NAME("use_encryption")) {
ps->use_encryption = TO_BOOL(value);
} else if (MATCH_NAME("use_compression")) {
ps->use_compression = TO_BOOL(value);
}
SAFE_FREE(section);
return 1;
}
@@ -228,33 +307,55 @@ static int common_handler(void *user, const char *section, const char *name, con
#define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0
if (MATCH("common", "server_addr")) {
if (config->server_addr) free(config->server_addr);
config->server_addr = strdup(value);
SAFE_FREE(config->server_addr);
int addr_len = strlen(value) + 1;
config->server_addr = (char *)calloc(1, addr_len);
assert(config->server_addr);
if(dns_unified(value, config->server_addr, addr_len)) {
debug(LOG_ERR, "error: server_addr [%s] is invalid!", value);
exit(0);
}
if (is_valid_ip_address(value))
set_common_server_ip(value);
} 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);
assert(config->http_proxy);
} else if (MATCH("common", "log_file")) {
if (config->log_file) free(config->log_file);
SAFE_FREE(config->log_file);
config->log_file = strdup(value);
assert(config->log_file);
} else if (MATCH("common", "log_way")) {
if (config->log_way) free(config->log_way);
SAFE_FREE(config->log_way);
config->log_way = strdup(value);
assert(config->log_way);
} else if (MATCH("common", "log_level")) {
if (config->log_level) free(config->log_level);
SAFE_FREE(config->log_level);
config->log_level = strdup(value);
assert(config->log_level);
} 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);
assert(config->privilege_token);
} 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);
assert(config->auth_token);
} else if (MATCH("common", "user")) {
SAFE_FREE(config->user);
config->user = strdup(value);
assert(config->user);
} else if (MATCH("common", "tcp_mux")) {
config->tcp_mux = 0; // set tcp_mux to default: false
}
return 1;
}
@@ -264,23 +365,49 @@ 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");
assert(config->log_file);
config->log_way = strdup("console");
assert(config->log_way);
config->log_level = strdup("info");
assert(config->log_level);
config->log_max_days = 3;
config->heartbeat_interval = 10;
config->heartbeat_timeout = 30;
config->heartbeat_interval = 30;
config->heartbeat_timeout = 60;
config->tcp_mux = 0;
config->user = NULL;
config->server_ip = NULL;
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);
debug(LOG_INFO, "Reading configuration file '%s'", confile);
debug(LOG_DEBUG, "Reading configuration file '%s'", confile);
if (ini_parse(confile, common_handler, c_conf) < 0) {
debug(LOG_ERR, "Config file parse failed");
@@ -299,7 +426,12 @@ void load_config(const char *confile)
exit(0);
}
ini_parse(confile, service_handler, NULL);
ini_parse(confile, proxy_service_handler, NULL);
dump_all_pc();
dump_all_ps();
}
int is_running_in_router()
{
return c_conf->is_router;
}

View File

@@ -21,42 +21,51 @@
/** @file config.h
@brief xfrp client config related
@author Copyright (C) 2016 Dengfeng Liu <liudengfeng@kunteng.org>
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
*/
#ifndef _CONFIG_H_
#define _CONFIG_H_
#include "client.h"
#include "common.h"
#define FTP_RMT_CTL_PROXY_SUFFIX "_ftp_remote_ctl_proxy"
struct base_conf{
char *name;
char *auth_token;
char *type;
int use_encryption;
int use_gzip;
int privilege_mode;
int use_encryption;
int use_gzip;
int privilege_mode;
char *privilege_token;
int pool_count;
int pool_count;
char *host_header_rewrite;
char *http_username;
char *http_password;
char *subdomain;
};
// common config
struct common_conf {
char *server_addr; /* default 0.0.0.0 */
int server_port; /* default 7000 */
char *server_addr; /* default 0.0.0.0 */
char *server_ip;
int server_port; /* default 7000 */
char *http_proxy;
char *log_file; /* default consol */
char *log_way; /* default console */
char *log_level; /* default info */
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 *auth_token;
int heartbeat_interval; /* default 10 */
int heartbeat_timeout; /* default 30 */
int tcp_mux; /* default 0 */
char *user;
/* 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();
@@ -65,5 +74,8 @@ 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);
void set_common_server_ip(const char *ip);
int is_running_in_router();
#endif
#endif //_CONFIG_H_

20
const.h
View File

@@ -21,7 +21,7 @@
/** @file const.h
@brief xfrp constant parameter define
@author Copyright (C) 2016 Dengfeng Liu <liudengfeng@kunteng.org>
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
*/
#ifndef _CONST_H_
@@ -35,14 +35,14 @@ enum server_status {
};
// msg type
enum msg_type {
NewCtlConn = 0,
NewWorkConn,
NoticeUserConn,
NewCtlConnRes,
HeartbeatReq,
HeartbeatRes,
NewWorkConnUdp
};
// enum msg_type {
// NewCtlConn = 0,
// NewWorkConn,
// NoticeUserConn,
// NewCtlConnRes,
// HeartbeatReq,
// HeartbeatRes,
// NewWorkConnUdp
// };
#endif

927
control.c
View File

@@ -21,7 +21,7 @@
/** @file control.c
@brief xfrp control protocol implemented
@author Copyright (C) 2016 Dengfeng Liu <liudengfeng@kunteng.org>
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
*/
#include <string.h>
@@ -29,14 +29,10 @@
#include <stdio.h>
#include <errno.h>
#include <assert.h>
#include <time.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <json-c/json.h>
#include <syslog.h>
#include <event2/bufferevent.h>
@@ -44,10 +40,9 @@
#include <event2/listener.h>
#include <event2/util.h>
#include <event2/event.h>
#include <event2/dns.h>
#include <event2/event_struct.h>
#include <openssl/md5.h>
#include "debug.h"
#include "client.h"
#include "uthash.h"
@@ -56,199 +51,53 @@
#include "msg.h"
#include "control.h"
#include "uthash.h"
#include "crypto.h"
#include "utils.h"
#include "session.h"
#include "common.h"
#include "login.h"
static char *calc_md5(const char *data, int datalen)
static struct control *main_ctl;
static int clients_conn_signel = 0;
static int is_login = 0;
static void sync_new_work_connection(struct bufferevent *bev);
static void recv_cb(struct bufferevent *bev, void *ctx);
static int
is_client_connected()
{
unsigned char digest[16] = {0};
char *out = (char*)malloc(33);
MD5_CTX md5;
MD5_Init(&md5);
MD5_Update(&md5, data, datalen);
MD5_Final(digest, &md5);
for (int n = 0; n < 16; ++n) {
snprintf(&(out[n*2]), 3, "%02x", (unsigned int)digest[n]);
}
return out;
return clients_conn_signel;
}
static char *get_auth_key(const char *name, const char *token)
static int
client_connected(int is_connected)
{
char seed[128] = {0};
snprintf(seed, 128, "%s%s%ld", name, token, time(NULL));
return calc_md5(seed, strlen(seed));
if (is_connected)
clients_conn_signel = 1;
else
clients_conn_signel = 0;
return clients_conn_signel;
}
static struct control_request *
get_control_request(enum msg_type type, const struct proxy_client *client)
static int
set_client_work_start(struct proxy_client *client, int is_start_work)
{
if (!client)
return NULL;
struct control_request *req = calloc(sizeof(struct control_request), 1);
long ntime = time(NULL);
req->type = type;
req->proxy_name = strdup(client->name);
#define STRDUP(v) v?strdup(v):NULL
switch(type) {
case NewCtlConn:
req->use_encryption = client->bconf->use_encryption;
req->use_gzip = client->bconf->use_gzip;
req->pool_count = client->bconf->pool_count;
req->privilege_mode = client->bconf->privilege_mode;
req->proxy_type = STRDUP(client->bconf->type);
req->host_header_rewrite = STRDUP(client->bconf->host_header_rewrite);
req->http_username = STRDUP(client->bconf->http_username);
req->http_password = STRDUP(client->bconf->http_password);
req->subdomain = STRDUP(client->bconf->subdomain);
if (req->privilege_mode) {
req->remote_port = client->remote_port;
req->custom_domains = STRDUP(client->custom_domains);
req->locations = STRDUP(client->locations);
}
break;
case NewWorkConn:
break;
case NoticeUserConn:
break;
case NewCtlConnRes:
break;
case HeartbeatReq:
break;
case HeartbeatRes:
break;
case NewWorkConnUdp:
break;
}
req->privilege_mode = client->bconf->privilege_mode;
req->timestamp = ntime;
if (req->privilege_mode) {
req->privilege_key = get_auth_key(client->name, client->bconf->privilege_token);
} else {
req->auth_key = get_auth_key(client->name, client->bconf->auth_token);
}
return req;
if (is_start_work) {
assert(client->ps);
client->work_started = 1;
}else
client->work_started = 0;
return client->work_started;
}
static void
control_request_free(struct control_request *req)
{
if (!req)
return;
if (req->proxy_name) free(req->proxy_name);
if (req->auth_key) free(req->auth_key);
if (req->privilege_key) free(req->privilege_key);
if (req->proxy_type) free(req->proxy_type);
if (req->custom_domains) free(req->custom_domains);
if (req->locations) free(req->locations);
if (req->host_header_rewrite) free(req->host_header_rewrite);
if (req->http_username) free(req->http_username);
if (req->http_password) free(req->http_password);
if (req->subdomain) free(req->subdomain);
free(req);
}
void send_msg_frp_server(enum msg_type type, const struct proxy_client *client, struct bufferevent *bev)
{
char *msg = NULL;
struct control_request *req = get_control_request(type, client); // get control request by client
int len = control_request_marshal(req, &msg); // marshal control request to json string
assert(msg);
struct bufferevent *bout = NULL;
if (bev) {
bout = bev;
} else {
bout = client->ctl_bev;
}
bufferevent_write(bout, msg, len);
bufferevent_write(bout, "\n", 1);
debug(LOG_DEBUG, "Send msg to frp server [%s]", msg);
free(msg);
control_request_free(req); // free control request
}
// connect to server
struct bufferevent *connect_server(struct event_base *base, const char *name, const int port)
{
struct bufferevent *bev = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE);
assert(bev);
if (bufferevent_socket_connect_hostname(bev, NULL, AF_INET, name, port)<0) {
bufferevent_free(bev);
return NULL;
}
return bev;
}
static void set_heartbeat_interval(struct event *timeout)
{
struct timeval tv;
struct common_conf *c_conf = get_common_config();
evutil_timerclear(&tv);
tv.tv_sec = c_conf->heartbeat_interval;
event_add(timeout, &tv);
}
static void hb_sender_cb(evutil_socket_t fd, short event, void *arg)
{
struct proxy_client *client = arg;
send_msg_frp_server(HeartbeatReq, client, NULL);
set_heartbeat_interval(client->ev_timeout);
}
static void heartbeat_sender(struct proxy_client *client)
{
client->ev_timeout = evtimer_new(client->base, hb_sender_cb, client);
set_heartbeat_interval(client->ev_timeout);
}
static void process_frp_msg(char *res, struct proxy_client *client)
{
struct control_response *c_res = control_response_unmarshal(res);
if (c_res == NULL)
return;
switch(c_res->type) {
case HeartbeatRes:
break;
case NoticeUserConn:
// when user connect
start_frp_tunnel(client);
break;
default:
break;
}
control_response_free(c_res);
}
static void login_xfrp_read_msg_cb(struct bufferevent *bev, void *ctx)
{
struct evbuffer *input = bufferevent_get_input(bev);
int len = evbuffer_get_length(input);
if (len <= 0)
return;
char *buf = calloc(1, len+1);
if (evbuffer_remove(input, buf, len) > 0) {
process_frp_msg(buf, ctx);
}
free(buf);
}
static void login_xfrp_event_cb(struct bufferevent *bev, short what, void *ctx)
static void
client_start_event_cb(struct bufferevent *bev, short what, void *ctx)
{
struct proxy_client *client = ctx;
assert(client);
struct common_conf *c_conf = get_common_config();
if (what & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) {
@@ -257,37 +106,715 @@ static void login_xfrp_event_cb(struct bufferevent *bev, short what, void *ctx)
bufferevent_free(client->ctl_bev);
client->ctl_bev = NULL;
}
debug(LOG_ERR, "Proxy [%s]: connect server [%s:%d] error", client->name, c_conf->server_addr, c_conf->server_port);
debug(LOG_ERR, "Proxy connect server [%s:%d] error: %s", c_conf->server_addr, c_conf->server_port, strerror(errno));
bufferevent_free(bev);
free_proxy_client(client);
} else if (what & BEV_EVENT_CONNECTED) {
debug(LOG_INFO, "Proxy [%s] connected: send msg to frp server", client->name);
bufferevent_setcb(bev, login_xfrp_read_msg_cb, NULL, login_xfrp_event_cb, client);
bufferevent_setcb(bev, recv_cb, NULL, client_start_event_cb, client);
bufferevent_enable(bev, EV_READ|EV_WRITE);
send_msg_frp_server(NewCtlConn, client, NULL);
sync_new_work_connection(bev);
client_connected(1);
debug(LOG_INFO, "proxy service start");
}
}
static void login_frp_server(struct proxy_client *client)
static void
new_client_connect()
{
struct proxy_client *client = new_proxy_client();
struct common_conf *c_conf = get_common_config();
assert(c_conf);
client->base = main_ctl->connect_base;
struct bufferevent *bev = connect_server(client->base, c_conf->server_addr, c_conf->server_port);
if (!bev) {
debug(LOG_DEBUG, "Connect server [%s:%d] failed", c_conf->server_addr, c_conf->server_port);
return;
}
debug(LOG_INFO, "Proxy [%s]: connect server [%s:%d] ......", client->name, c_conf->server_addr, c_conf->server_port);
debug(LOG_INFO, "work connection: connect server [%s:%d] ......", c_conf->server_addr, c_conf->server_port);
client->ctl_bev = bev;
bufferevent_enable(bev, EV_WRITE);
bufferevent_setcb(bev, NULL, NULL, login_xfrp_event_cb, client);
bufferevent_setcb(bev, NULL, NULL, client_start_event_cb, client);
}
void control_process(struct proxy_client *client)
static void
start_proxy_services()
{
login_frp_server(client);
struct proxy_service *all_ps = get_all_proxy_services();
assert(all_ps);
struct proxy_service *ps = NULL, *tmp = NULL;
heartbeat_sender(client);
debug(LOG_INFO, "Start xfrp proxy services ...");
HASH_ITER(hh, all_ps, ps, tmp) {
if(ps == NULL) {
debug(LOG_ERR, "proxy service is invalid!");
return;
}
send_new_proxy(ps);
}
}
static void
ping(struct bufferevent *bev)
{
struct bufferevent *bout = NULL;
if (bev) {
bout = bev;
} else {
bout = main_ctl->connect_bev;
}
if ( ! bout) {
debug(LOG_ERR, "bufferevent is not legal!");
return;
}
uint32_t sid = get_main_control()->session_id;
char *ping_msg = "{}";
send_enc_msg_frp_server(bev, TypePing, ping_msg, strlen(ping_msg), sid);
}
static void
sync_new_work_connection(struct bufferevent *bev)
{
struct bufferevent *bout = bev;
assert(bout);
/* send new work session regist request to frps*/
struct work_conn *work_c = new_work_conn();
work_c->run_id = get_run_id();
if (! work_c->run_id) {
debug(LOG_ERR, "cannot found run ID, it should inited when login!");
SAFE_FREE(work_c);
return;
}
char *new_work_conn_request_message = NULL;
int nret = new_work_conn_marshal(work_c, &new_work_conn_request_message);
if (0 == nret) {
debug(LOG_ERR, "new work connection request run_id marshal failed!");
return;
}
send_msg_frp_server(bev, TypeNewWorkConn, new_work_conn_request_message, nret, 0);
SAFE_FREE(new_work_conn_request_message);
SAFE_FREE(work_c);
}
struct bufferevent *
connect_server(struct event_base *base, const char *name, const int port)
{
struct bufferevent *bev = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE);
assert(bev);
if (bufferevent_socket_connect_hostname(bev, main_ctl->dnsbase,
AF_INET, name, port) < 0 ) {
bufferevent_free(bev);
return NULL;
}
return bev;
}
static void
set_ticker_ping_timer(struct event *timeout)
{
struct timeval tv;
struct common_conf *c_conf = get_common_config();
evutil_timerclear(&tv);
tv.tv_sec = c_conf->heartbeat_interval;
event_add(timeout, &tv);
}
static void
hb_sender_cb(evutil_socket_t fd, short event, void *arg)
{
debug(LOG_DEBUG, "hb_sender_cb");
if (is_client_connected()) {
debug(LOG_DEBUG, "ping frps");
ping(NULL);
}
set_ticker_ping_timer(main_ctl->ticker_ping);
}
// return: 0: raw succeed 1: raw failed
static int
proxy_service_resp_raw(struct new_proxy_response *npr)
{
if (npr->error && strlen(npr->error) > 2) {
debug(LOG_ERR, "error: new proxy response error_field:%s", npr->error);
return 1;
}
if ((! npr->proxy_name) || (strlen(npr->proxy_name) <= 0)) {
debug(LOG_ERR, "error: new proxy response proxy name unmarshal failed!");
return 1;
}
struct proxy_service *ps = NULL;
ps = get_proxy_service(npr->proxy_name);
if (! ps) {
debug(LOG_ERR, "error: proxy_name responsed by TypeNewProxyResp not found!");
return 1;
}
if (! ps->proxy_type) {
debug(LOG_ERR, "error: proxy_type is NULL, it should be never happend!");
return 1;
}
if (ps->ftp_cfg_proxy_name) {
struct proxy_service *main_ps = get_proxy_service(ps->ftp_cfg_proxy_name);
if (main_ps) {
debug(LOG_DEBUG, "find main ftp proxy service name [%s]", main_ps->proxy_name);
} else {
debug(LOG_ERR, "error: cannot find main ftp proxy service!");
return 1;
}
if (npr->remote_port <= 0) {
debug(LOG_ERR, "error: ftp remote_data_port [%d] that request from server is invalid!", npr->remote_port);
return 1;
}
main_ps->remote_data_port = npr->remote_port;
}
return 0;
}
static void
dump_all_unknown_encypt(uint8_t *enc_msg, int ilen)
{
uint8_t *iv = get_main_decoder()->iv;
uint8_t *key = get_main_decoder()->key;
FILE *fout = fopen("unkown.encrypt", "w");
assert(fout);
fwrite(iv, 16, 1, fout);
fwrite(key, 16, 1, fout);
fwrite((uint8_t *)&ilen, sizeof(int), 1, fout);
fwrite(enc_msg, ilen, 1, fout);
fclose(fout);
}
static int
handle_enc_msg(uint8_t *enc_msg, int ilen, uint8_t **out)
{
if (ilen <= 0) {
debug(LOG_INFO, "enc_msg length should not be %d", ilen);
return -1;
}
uint8_t *buf = enc_msg;
if ( !is_decoder_inited() && get_block_size() <= ilen) {
init_main_decoder(buf);
buf += get_block_size();
ilen -= get_block_size();
debug(LOG_DEBUG, "first recv stream message, init decoder iv succeed! %d", ilen);
if (!ilen) {
// recv only iv
debug(LOG_DEBUG, "recv eas1238 iv data");
return 0;
}
}
uint8_t *dec_msg = NULL;
size_t len = decrypt_data(buf, ilen, get_main_decoder(), &dec_msg);
*out = dec_msg;
debug(LOG_DEBUG, "dec out len %d ", len);
return len;
}
static void
print_enc_msg(uint8_t *enc_msg, int len)
{
printf("enc_msg is [%d]:\n", len);
for (int i = 0; i < len; i++) {
if (i%16 == 0)
printf("\n");
printf("%1x ", enc_msg[i]);
}
printf("\n");
}
static void
handle_control_work(const uint8_t *buf, int len, void *ctx)
{
uint8_t *frps_cmd = NULL;
uint8_t cmd_type;
uint8_t *enc_msg = buf;
if (!ctx)
handle_enc_msg(enc_msg, len, &frps_cmd);
else
frps_cmd = buf;
if (!frps_cmd)
return; // only recv iv
struct msg_hdr *msg = (struct msg_hdr *)frps_cmd;
cmd_type = msg->type;
debug(LOG_DEBUG, "cmd_type is %d data is %s", cmd_type, msg->data);
switch(cmd_type) {
case TypeReqWorkConn:
debug(LOG_DEBUG, "TypeReqWorkConn cmd");
if (! is_client_connected()) {
start_proxy_services();
client_connected(1);
}
new_client_connect();
break;
case TypeNewProxyResp:
debug(LOG_DEBUG, "TypeNewProxyResp cmd");
struct new_proxy_response *npr = new_proxy_resp_unmarshal(msg->data);
if (npr == NULL) {
debug(LOG_ERR, "new proxy response buffer unmarshal faild!");
return;
}
proxy_service_resp_raw(npr);
SAFE_FREE(npr);
break;
case TypeStartWorkConn:
debug(LOG_DEBUG, "TypeStartWorkConn cmd");
struct start_work_conn_resp *sr = start_work_conn_resp_unmarshal(msg->data);
if (! sr) {
debug(LOG_ERR,
"TypeStartWorkConn unmarshal failed, it should never be happend!");
break;
}
struct proxy_service *ps = get_proxy_service(sr->proxy_name);
if (! ps) {
debug(LOG_ERR,
"TypeStartWorkConn requested proxy service [%s] not found, it should nerver be happend!",
sr->proxy_name);
break;
}
assert(ctx);
struct proxy_client *client = ctx;
client->ps = ps;
int r_len = len - sizeof(struct msg_hdr) - msg_hton(msg->length);
debug(LOG_DEBUG,
"proxy service [%s] [%s:%d] start work connection. remain data length %d",
sr->proxy_name,
ps->local_ip,
ps->local_port,
r_len);
if (r_len > 0) {
client->data_tail_size = r_len;
client->data_tail = msg->data + msg_hton(msg->length);
debug(LOG_DEBUG, "data_tail is %s", client->data_tail);
}
start_xfrp_tunnel(client);
set_client_work_start(client, 1);
break;
case TypePong:
break;
default:
debug(LOG_INFO, "command type dont support: ctx is %d", ctx?1:0);
print_enc_msg(enc_msg, len);
dump_all_unknown_encypt(enc_msg, len);
}
if (!ctx)
free(frps_cmd);
}
static int
handle_login_response(const uint8_t *buf, int len)
{
struct msg_hdr *mhdr = (struct msg_hdr *)buf;
if (mhdr->type != TypeLoginResp) {
debug(LOG_ERR, "type incorrect: it should be login response, but %d", mhdr->type);
return 0;
}
struct login_resp *lres = login_resp_unmarshal(mhdr->data);
if (!lres) {
return 0;
}
if (!login_resp_check(lres)) {
debug(LOG_ERR, "login failed");
free(lres);
return 0;
}
free(lres);
is_login = 1;
int login_len = msg_hton(mhdr->length);
debug(LOG_ERR, "login success! %d len %d", login_len, len);
if (len-login_len-sizeof(struct msg_hdr) == 0)
return 1;
// in case, system get 3 packet together
uint8_t *enc_msg = mhdr->data+login_len;
uint8_t *frps_cmd = NULL;
int nret = handle_enc_msg(enc_msg, len-login_len-sizeof(struct msg_hdr), &frps_cmd);
assert(nret > 0);
// start proxy services must first send
start_proxy_services();
client_connected(1);
debug(LOG_DEBUG, "TypeReqWorkConn cmd, msg :%s", &frps_cmd[8]);
assert (frps_cmd[0] == TypeReqWorkConn);
new_client_connect();
return 1;
}
static void
handle_frps_msg(unsigned char *buf, int len, void *ctx)
{
if (!is_login) {
// login response
handle_login_response(buf, len);
}else if (!ctx) {
// control msg
debug(LOG_DEBUG, "main control message");
handle_control_work(buf, len, NULL);
}else {
// client msg
debug(LOG_DEBUG, "client message");
handle_control_work(buf, len, ctx);
}
}
// ctx: if recv_cb was called by common control, ctx == NULL
// else ctx == client struct
static void
recv_cb(struct bufferevent *bev, void *ctx)
{
struct evbuffer *input = bufferevent_get_input(bev);
int len = evbuffer_get_length(input);
if (len <= 0) {
return;
}
unsigned char *buf = calloc(len+1, 1);
assert(buf);
evbuffer_remove(input, buf, len);
debug(LOG_DEBUG, "recv msg from frps %d ", len);
handle_frps_msg(buf, len, ctx);
SAFE_FREE(buf);
return;
}
static void
connect_event_cb (struct bufferevent *bev, short what, void *ctx)
{
struct common_conf *c_conf = get_common_config();
static int retry_times = 0;
if (what & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) {
if (retry_times >= 10) { // only try 10 times consecutively
debug(LOG_ERR,
"have retry connect to xfrp server for %d times, exit!",
retry_times);
exit(0);
}
retry_times++;
debug(LOG_ERR, "error: connect server [%s:%d] failed",
c_conf->server_addr,
c_conf->server_port);
free_control();
init_main_control();
start_base_connect();
close_main_control();
} else if (what & BEV_EVENT_CONNECTED) {
retry_times = 0;
login();
}
}
static void
keep_control_alive()
{
main_ctl->ticker_ping = evtimer_new(main_ctl->connect_base, hb_sender_cb, NULL);
if ( ! main_ctl->ticker_ping) {
debug(LOG_ERR, "Ping Ticker init failed!");
return;
}
set_ticker_ping_timer(main_ctl->ticker_ping);
}
static void
server_dns_cb(int event_code, struct evutil_addrinfo *addr, void *ctx)
{
if (event_code) {
set_common_server_ip((const char *)evutil_gai_strerror(event_code));
} else {
struct evutil_addrinfo *ai;
if (addr->ai_canonname)
debug(LOG_DEBUG, "addr->ai_canonname [%s]", addr->ai_canonname);
for (ai = addr; ai; ai = ai->ai_next) {
char buf[128];
const char *s = NULL;
if (ai->ai_family == AF_INET) {
struct sockaddr_in *sin = (struct sockaddr_in *)ai->ai_addr;
s = evutil_inet_ntop(AF_INET, &sin->sin_addr, buf, 128);
} else if (ai->ai_family == AF_INET6) {
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ai->ai_addr;
s = evutil_inet_ntop(AF_INET6, &sin6->sin6_addr, buf, 128);
}
if (s) set_common_server_ip(s);
}
if (addr) evutil_freeaddrinfo(addr);
}
}
void
start_base_connect()
{
struct common_conf *c_conf = get_common_config();
main_ctl->connect_bev = connect_server(main_ctl->connect_base,
c_conf->server_addr,
c_conf->server_port);
if ( ! main_ctl->connect_bev) {
debug(LOG_ERR, "error: connect server [%s:%d] failed", c_conf->server_addr, c_conf->server_port);
exit(0);
}
debug(LOG_INFO, "connect server [%s:%d]...", c_conf->server_addr, c_conf->server_port);
bufferevent_enable(main_ctl->connect_bev, EV_WRITE|EV_READ);
bufferevent_setcb(main_ctl->connect_bev, recv_cb, NULL, connect_event_cb, NULL);
}
void
login()
{
char *lg_msg = NULL;
int len = login_request_marshal(&lg_msg); //marshal login request
if ( !lg_msg ) {
debug(LOG_ERR,
"error: login_request_marshal failed, it should never be happenned");
exit(0);
}
send_msg_frp_server(NULL, TypeLogin, lg_msg, len, main_ctl->session_id);
SAFE_FREE(lg_msg);
}
void
send_msg_frp_server(struct bufferevent *bev,
const enum msg_type type,
const char *msg,
const size_t msg_len,
uint32_t sid)
{
struct bufferevent *bout = NULL;
if (bev) {
bout = bev;
} else {
bout = main_ctl->connect_bev;
}
assert(bout);
debug(LOG_DEBUG, "send plain msg ----> [%c: %s]", type, msg);
struct msg_hdr *req_msg = calloc(msg_len+sizeof(struct msg_hdr), 1);
assert(req_msg);
req_msg->type = type;
req_msg->length = msg_hton((uint64_t)msg_len);
memcpy(req_msg->data, msg, msg_len);
bufferevent_write(bout, (uint8_t *)req_msg, msg_len+sizeof(struct msg_hdr));
free(req_msg);
}
void
send_enc_msg_frp_server(struct bufferevent *bev,
const enum msg_type type,
const char *msg,
const size_t msg_len,
uint32_t sid)
{
struct bufferevent *bout = NULL;
if (bev) {
bout = bev;
} else {
bout = main_ctl->connect_bev;
}
assert(bout);
debug(LOG_DEBUG, "send enc msg ----> [%c: %s]", type, msg);
struct msg_hdr *req_msg = calloc(msg_len+sizeof(struct msg_hdr), 1);
assert(req_msg);
req_msg->type = type;
req_msg->length = msg_hton((uint64_t)msg_len);
memcpy(req_msg->data, msg, msg_len);
if (get_main_encoder() == NULL) {
debug(LOG_DEBUG, "init_main_encoder .......");
struct frp_coder *coder = init_main_encoder();
bufferevent_write(bout, coder->iv, 16);
}
uint8_t *enc_msg = NULL;
size_t olen = encrypt_data((uint8_t *)req_msg, msg_len+sizeof(struct msg_hdr), get_main_encoder(), &enc_msg);
assert(olen > 0);
debug(LOG_DEBUG, "encrypt_data length %d", olen);
bufferevent_write(bout, enc_msg, olen);
free(enc_msg);
free(req_msg);
}
struct control *
get_main_control()
{
return main_ctl;
}
void
start_login_frp_server(struct event_base *base)
{
struct common_conf *c_conf = get_common_config();
struct bufferevent *bev = connect_server(base, c_conf->server_addr, c_conf->server_port);
if (!bev) {
debug(LOG_DEBUG,
"Connect server [%s:%d] failed",
c_conf->server_addr,
c_conf->server_port);
return;
}
debug(LOG_INFO, "Xfrpc login: connect server [%s:%d] ...", c_conf->server_addr, c_conf->server_port);
bufferevent_enable(bev, EV_WRITE|EV_READ);
bufferevent_setcb(bev, NULL, NULL, connect_event_cb, NULL);
}
void
send_new_proxy(struct proxy_service *ps)
{
if (! ps) {
debug(LOG_ERR, "proxy service is invalid!");
return;
}
char *new_proxy_msg = NULL;
int len = new_proxy_service_marshal(ps, &new_proxy_msg);
if ( ! new_proxy_msg) {
debug(LOG_ERR, "proxy service request marshal failed");
return;
}
debug(LOG_DEBUG, "control proxy client: [Type %d : proxy_name %s : msg_len %d]", TypeNewProxy, ps->proxy_name, len);
send_enc_msg_frp_server(NULL, TypeNewProxy, new_proxy_msg, len, main_ctl->session_id);
SAFE_FREE(new_proxy_msg);
}
void
init_main_control()
{
if (main_ctl && main_ctl->connect_base) {
event_base_loopbreak(main_ctl->connect_base);
free(main_ctl);
}
main_ctl = calloc(sizeof(struct control), 1);
assert(main_ctl);
struct common_conf *c_conf = get_common_config();
if (c_conf->tcp_mux) {
uint32_t *sid = init_sid_index();
assert(sid);
main_ctl->session_id = *sid;
debug(LOG_DEBUG, "Connect Frps with control session ID: %d", main_ctl->session_id);
}
struct event_base *base = NULL;
struct evdns_base *dnsbase = NULL;
base = event_base_new();
if (! base) {
debug(LOG_ERR, "error: event base init failed!");
exit(0);
}
main_ctl->connect_base = base;
dnsbase = evdns_base_new(base, 1);
if (! dnsbase) {
debug(LOG_ERR, "error: evdns base init failed!");
exit(0);
}
main_ctl->dnsbase = dnsbase;
evdns_base_set_option(dnsbase, "timeout", "1.0");
// thanks to the following article
// http://www.wuqiong.info/archives/13/
evdns_base_set_option(dnsbase, "randomize-case:", "0"); //TurnOff DNS-0x20 encoding
evdns_base_nameserver_ip_add(dnsbase, "180.76.76.76"); //BaiduDNS
evdns_base_nameserver_ip_add(dnsbase, "223.5.5.5"); //AliDNS
evdns_base_nameserver_ip_add(dnsbase, "223.6.6.6"); //AliDNS
evdns_base_nameserver_ip_add(dnsbase, "114.114.114.114"); //114DNS
// if server_addr is ip, done control init.
if (is_valid_ip_address((const char *)c_conf->server_addr))
return;
// if server_addr is domain, analyze it to ip for server_ip
debug(LOG_DEBUG, "Get ip address of [%s] from DNServer", c_conf->server_addr);
struct evutil_addrinfo hints;
struct evdns_getaddrinfo_request *dns_req;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_flags = EVUTIL_AI_CANONNAME;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
dns_req = evdns_getaddrinfo(dnsbase,
c_conf->server_addr,
NULL /* no service name given */,
&hints,
server_dns_cb,
NULL);
if (! dns_req) {
debug(LOG_ERR, "error: can not analyse the dns of [%s]", c_conf->server_addr);
exit(0);
}
}
void
close_main_control()
{
assert(main_ctl);
event_base_dispatch(main_ctl->connect_base);
event_base_free(main_ctl->connect_base);
evdns_base_free(main_ctl->dnsbase, 0);
}
void
run_control()
{
start_base_connect();
keep_control_alive();
}
void
free_control()
{
if (!main_ctl)
return;
SAFE_FREE(main_ctl);
}

View File

@@ -21,16 +21,57 @@
/** @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_
#define _CONTROL_H_
#include "const.h"
#include "uthash.h"
#include "msg.h"
struct proxy_client;
struct bufferevent;
struct event_base;
enum msg_type;
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
};
void connect_eventcb(struct bufferevent *bev, short events, void *ptr);
void start_base_connect();
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);
void send_enc_msg_frp_server(struct bufferevent *bev,
const enum msg_type type,
const char *msg,
const size_t msg_len,
uint32_t sid);
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 send_msg_frp_server(enum msg_type type, const struct proxy_client *client, struct bufferevent *bev);
#endif //_CONTROL_H_

221
crypto.c Normal file
View File

@@ -0,0 +1,221 @@
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <time.h>
#include <syslog.h>
#include <openssl/ssl.h>
#include "fastpbkdf2.h"
#include "crypto.h"
#include "config.h"
#include "common.h"
#include "debug.h"
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;
size_t
get_block_size()
{
return block_size;
}
struct frp_coder *
new_coder(const char *privilege_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->salt = strdup(salt);
encrypt_key(enc->privilege_token, strlen(enc->privilege_token), enc->salt, enc->key, block_size);
encrypt_iv(enc->iv, block_size);
return enc;
}
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->privilege_token = strdup(coder->privilege_token);
enc->salt = strdup(coder->salt);
return enc;
}
size_t
get_encrypt_block_size()
{
return block_size;
}
struct frp_coder *
init_main_encoder()
{
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 common_conf *c_conf = get_common_config();
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()
{
return main_encoder;
}
struct frp_coder *
get_main_decoder()
{
return main_decoder;
}
int
is_encoder_inited()
{
struct frp_coder *e = get_main_encoder();
return e != NULL;
}
int
is_decoder_inited()
{
struct frp_coder *d = get_main_decoder();
return d != NULL;
}
// 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, uint8_t *key, size_t block_size)
{
unsigned char *key_ret = key;
fastpbkdf2_hmac_sha1((void *)token,
token_len, (void *)salt,
strlen(salt),
64,
(void *)key_ret,
block_size);
return key_ret;
}
// the result should be free after using
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));
for(size_t i=0; i<iv_len; i++) {
iv_buf[i] = (rand() % 254 ) + 1;
}
return iv_buf;
}
static void
print_hex(uint8_t *val, size_t len)
{
for(int i = 0; i < len; i++)
printf("%1x", val[i]);
printf("\n");
}
// 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)
{
uint8_t *intext = src_data;
assert(intext);
assert(encoder);
struct frp_coder *c = encoder;
int outlen = 0, tmplen = 0;
uint8_t *outbuf = NULL;
assert(c);
outbuf = calloc(srclen, 1);
assert(outbuf);
*ret = outbuf;
static EVP_CIPHER_CTX *ctx = NULL;
if (!ctx) {
ctx = EVP_CIPHER_CTX_new();
EVP_EncryptInit_ex(ctx, EVP_aes_128_cfb(), NULL, c->key, c->iv);
}
if(!EVP_EncryptUpdate(ctx, outbuf, &tmplen, intext, (int)srclen)) {
debug(LOG_ERR, "EVP_EncryptUpdate error!");
goto E_END;
}
outlen += tmplen;
if(!EVP_EncryptFinal_ex(ctx, outbuf+tmplen, &tmplen)) {
debug(LOG_ERR, "EVP_EncryptFinal_ex error!");
goto E_END;
}
outlen += tmplen;
E_END:
return outlen;
}
size_t
decrypt_data(const uint8_t *enc_data, size_t enclen, struct frp_coder *decoder, uint8_t **ret)
{
uint8_t *inbuf = enc_data;
uint8_t *outbuf = calloc(enclen+1, 1);
struct frp_coder *c = decoder;
assert(inbuf);
assert(outbuf);
*ret = outbuf;
assert(decoder);
int outlen = 0, tmplen = 0;
static EVP_CIPHER_CTX *ctx= NULL;
if (!ctx) {
ctx= EVP_CIPHER_CTX_new();
EVP_DecryptInit_ex(ctx, EVP_aes_128_cfb(), NULL, c->key, c->iv);
}
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+outlen, &tmplen)) {
debug(LOG_ERR, "EVP_DecryptFinal_ex error");
goto D_END;
}
outlen += tmplen;
D_END:
return outlen;
}
void
free_encoder(struct frp_coder *encoder) {
if (encoder) {
SAFE_FREE(encoder->privilege_token);
SAFE_FREE(encoder->salt);
free(encoder);
}
}

32
crypto.h Normal file
View File

@@ -0,0 +1,32 @@
#ifndef _CRYPTO_H_
#define _CRYPTO_H_
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "common.h"
struct frp_coder {
uint8_t key[16];
char *salt;
uint8_t iv[16];
char *privilege_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);
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);
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(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 *get_main_encoder();
struct frp_coder *get_main_decoder();
size_t get_block_size();
void free_encoder(struct frp_coder *encoder);
#endif // _CRYPTO_H_

399
fastpbkdf2.c Normal file
View File

@@ -0,0 +1,399 @@
/*
* fast-pbkdf2 - Optimal PBKDF2-HMAC calculation
* Written in 2015 by Joseph Birr-Pixton <jpixton@gmail.com>
*
* To the extent possible under law, the author(s) have dedicated all
* copyright and related and neighboring rights to this software to the
* public domain worldwide. This software is distributed without any
* warranty.
*
* You should have received a copy of the CC0 Public Domain Dedication
* along with this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#include "fastpbkdf2.h"
#include <assert.h>
#include <string.h>
#include <openssl/sha.h>
/* --- MSVC doesn't support C99 --- */
#ifdef _MSC_VER
#define restrict
#define _Pragma __pragma
#endif
/* --- Common useful things --- */
#define MIN(a, b) ((a) > (b)) ? (b) : (a)
static inline void write32_be(uint32_t n, uint8_t out[4])
{
#if defined(__GNUC__) && __GNUC__ >= 4 && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
*(uint32_t *)(out) = __builtin_bswap32(n);
#else
out[0] = (n >> 24) & 0xff;
out[1] = (n >> 16) & 0xff;
out[2] = (n >> 8) & 0xff;
out[3] = n & 0xff;
#endif
}
static inline void write64_be(uint64_t n, uint8_t out[8])
{
#if defined(__GNUC__) && __GNUC__ >= 4 && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
*(uint64_t *)(out) = __builtin_bswap64(n);
#else
write32_be((n >> 32) & 0xffffffff, out);
write32_be(n & 0xffffffff, out + 4);
#endif
}
/* --- Optional OpenMP parallelisation of consecutive blocks --- */
#ifdef WITH_OPENMP
# define OPENMP_PARALLEL_FOR _Pragma("omp parallel for")
#else
# define OPENMP_PARALLEL_FOR
#endif
/* Prepare block (of blocksz bytes) to contain md padding denoting a msg-size
* message (in bytes). block has a prefix of used bytes.
*
* Message length is expressed in 32 bits (so suitable for sha1, sha256, sha512). */
static inline void md_pad(uint8_t *block, size_t blocksz, size_t used, size_t msg)
{
memset(block + used, 0, blocksz - used - 4);
block[used] = 0x80;
block += blocksz - 4;
write32_be((uint32_t) (msg * 8), block);
}
/* Internal function/type names for hash-specific things. */
#define HMAC_CTX(_name) HMAC_ ## _name ## _ctx
#define HMAC_INIT(_name) HMAC_ ## _name ## _init
#define HMAC_UPDATE(_name) HMAC_ ## _name ## _update
#define HMAC_FINAL(_name) HMAC_ ## _name ## _final
#define PBKDF2_F(_name) pbkdf2_f_ ## _name
#define PBKDF2(_name) pbkdf2_ ## _name
/* This macro expands to decls for the whole implementation for a given
* hash function. Arguments are:
*
* _name like 'sha1', added to symbol names
* _blocksz block size, in bytes
* _hashsz digest output, in bytes
* _ctx hash context type
* _init hash context initialisation function
* args: (_ctx *c)
* _update hash context update function
* args: (_ctx *c, const void *data, size_t ndata)
* _final hash context finish function
* args: (void *out, _ctx *c)
* _xform hash context raw block update function
* args: (_ctx *c, const void *data)
* _xcpy hash context raw copy function (only need copy hash state)
* args: (_ctx * restrict out, const _ctx *restrict in)
* _xtract hash context state extraction
* args: args (_ctx *restrict c, uint8_t *restrict out)
* _xxor hash context xor function (only need xor hash state)
* args: (_ctx *restrict out, const _ctx *restrict in)
*
* The resulting function is named PBKDF2(_name).
*/
#define DECL_PBKDF2(_name, _blocksz, _hashsz, _ctx, \
_init, _update, _xform, _final, _xcpy, _xtract, _xxor) \
typedef struct { \
_ctx inner; \
_ctx outer; \
} HMAC_CTX(_name); \
\
static inline void HMAC_INIT(_name)(HMAC_CTX(_name) *ctx, \
const uint8_t *key, size_t nkey) \
{ \
/* Prepare key: */ \
uint8_t k[_blocksz]; \
\
/* Shorten long keys. */ \
if (nkey > _blocksz) \
{ \
_init(&ctx->inner); \
_update(&ctx->inner, key, nkey); \
_final(k, &ctx->inner); \
\
key = k; \
nkey = _hashsz; \
} \
\
/* Standard doesn't cover case where blocksz < hashsz. */ \
assert(nkey <= _blocksz); \
\
/* Right zero-pad short keys. */ \
if (k != key) \
memcpy(k, key, nkey); \
if (_blocksz > nkey) \
memset(k + nkey, 0, _blocksz - nkey); \
\
/* Start inner hash computation */ \
uint8_t blk_inner[_blocksz]; \
uint8_t blk_outer[_blocksz]; \
\
for (size_t i = 0; i < _blocksz; i++) \
{ \
blk_inner[i] = 0x36 ^ k[i]; \
blk_outer[i] = 0x5c ^ k[i]; \
} \
\
_init(&ctx->inner); \
_update(&ctx->inner, blk_inner, sizeof blk_inner); \
\
/* And outer. */ \
_init(&ctx->outer); \
_update(&ctx->outer, blk_outer, sizeof blk_outer); \
} \
\
static inline void HMAC_UPDATE(_name)(HMAC_CTX(_name) *ctx, \
const void *data, size_t ndata) \
{ \
_update(&ctx->inner, data, ndata); \
} \
\
static inline void HMAC_FINAL(_name)(HMAC_CTX(_name) *ctx, \
uint8_t out[_hashsz]) \
{ \
_final(out, &ctx->inner); \
_update(&ctx->outer, out, _hashsz); \
_final(out, &ctx->outer); \
} \
\
\
/* --- PBKDF2 --- */ \
static inline void PBKDF2_F(_name)(const HMAC_CTX(_name) *startctx, \
uint32_t counter, \
const uint8_t *salt, size_t nsalt, \
uint32_t iterations, \
uint8_t *out) \
{ \
uint8_t countbuf[4]; \
write32_be(counter, countbuf); \
\
/* Prepare loop-invariant padding block. */ \
uint8_t Ublock[_blocksz]; \
md_pad(Ublock, _blocksz, _hashsz, _blocksz + _hashsz); \
\
/* First iteration: \
* U_1 = PRF(P, S || INT_32_BE(i)) \
*/ \
HMAC_CTX(_name) ctx = *startctx; \
HMAC_UPDATE(_name)(&ctx, salt, nsalt); \
HMAC_UPDATE(_name)(&ctx, countbuf, sizeof countbuf); \
HMAC_FINAL(_name)(&ctx, Ublock); \
_ctx result = ctx.outer; \
\
/* Subsequent iterations: \
* U_c = PRF(P, U_{c-1}) \
*/ \
for (uint32_t i = 1; i < iterations; i++) \
{ \
/* Complete inner hash with previous U */ \
_xcpy(&ctx.inner, &startctx->inner); \
_xform(&ctx.inner, Ublock); \
_xtract(&ctx.inner, Ublock); \
/* Complete outer hash with inner output */ \
_xcpy(&ctx.outer, &startctx->outer); \
_xform(&ctx.outer, Ublock); \
_xtract(&ctx.outer, Ublock); \
_xxor(&result, &ctx.outer); \
} \
\
/* Reform result into output buffer. */ \
_xtract(&result, out); \
} \
\
static inline void PBKDF2(_name)(const uint8_t *pw, size_t npw, \
const uint8_t *salt, size_t nsalt, \
uint32_t iterations, \
uint8_t *out, size_t nout) \
{ \
assert(iterations); \
assert(out && nout); \
\
/* Starting point for inner loop. */ \
HMAC_CTX(_name) ctx; \
HMAC_INIT(_name)(&ctx, pw, npw); \
\
/* How many blocks do we need? */ \
uint32_t blocks_needed = (uint32_t)(nout + _hashsz - 1) / _hashsz; \
\
OPENMP_PARALLEL_FOR \
for (uint32_t counter = 1; counter <= blocks_needed; counter++) \
{ \
uint8_t block[_hashsz]; \
PBKDF2_F(_name)(&ctx, counter, salt, nsalt, iterations, block); \
\
size_t offset = (counter - 1) * _hashsz; \
size_t taken = MIN(nout - offset, _hashsz); \
memcpy(out + offset, block, taken); \
} \
}
static inline void sha1_extract(SHA_CTX *restrict ctx, uint8_t *restrict out)
{
write32_be(ctx->h0, out);
write32_be(ctx->h1, out + 4);
write32_be(ctx->h2, out + 8);
write32_be(ctx->h3, out + 12);
write32_be(ctx->h4, out + 16);
}
static inline void sha1_cpy(SHA_CTX *restrict out, const SHA_CTX *restrict in)
{
out->h0 = in->h0;
out->h1 = in->h1;
out->h2 = in->h2;
out->h3 = in->h3;
out->h4 = in->h4;
}
static inline void sha1_xor(SHA_CTX *restrict out, const SHA_CTX *restrict in)
{
out->h0 ^= in->h0;
out->h1 ^= in->h1;
out->h2 ^= in->h2;
out->h3 ^= in->h3;
out->h4 ^= in->h4;
}
DECL_PBKDF2(sha1,
SHA_CBLOCK,
SHA_DIGEST_LENGTH,
SHA_CTX,
SHA1_Init,
SHA1_Update,
SHA1_Transform,
SHA1_Final,
sha1_cpy,
sha1_extract,
sha1_xor)
static inline void sha256_extract(SHA256_CTX *restrict ctx, uint8_t *restrict out)
{
write32_be(ctx->h[0], out);
write32_be(ctx->h[1], out + 4);
write32_be(ctx->h[2], out + 8);
write32_be(ctx->h[3], out + 12);
write32_be(ctx->h[4], out + 16);
write32_be(ctx->h[5], out + 20);
write32_be(ctx->h[6], out + 24);
write32_be(ctx->h[7], out + 28);
}
static inline void sha256_cpy(SHA256_CTX *restrict out, const SHA256_CTX *restrict in)
{
out->h[0] = in->h[0];
out->h[1] = in->h[1];
out->h[2] = in->h[2];
out->h[3] = in->h[3];
out->h[4] = in->h[4];
out->h[5] = in->h[5];
out->h[6] = in->h[6];
out->h[7] = in->h[7];
}
static inline void sha256_xor(SHA256_CTX *restrict out, const SHA256_CTX *restrict in)
{
out->h[0] ^= in->h[0];
out->h[1] ^= in->h[1];
out->h[2] ^= in->h[2];
out->h[3] ^= in->h[3];
out->h[4] ^= in->h[4];
out->h[5] ^= in->h[5];
out->h[6] ^= in->h[6];
out->h[7] ^= in->h[7];
}
DECL_PBKDF2(sha256,
SHA256_CBLOCK,
SHA256_DIGEST_LENGTH,
SHA256_CTX,
SHA256_Init,
SHA256_Update,
SHA256_Transform,
SHA256_Final,
sha256_cpy,
sha256_extract,
sha256_xor)
static inline void sha512_extract(SHA512_CTX *restrict ctx, uint8_t *restrict out)
{
write64_be(ctx->h[0], out);
write64_be(ctx->h[1], out + 8);
write64_be(ctx->h[2], out + 16);
write64_be(ctx->h[3], out + 24);
write64_be(ctx->h[4], out + 32);
write64_be(ctx->h[5], out + 40);
write64_be(ctx->h[6], out + 48);
write64_be(ctx->h[7], out + 56);
}
static inline void sha512_cpy(SHA512_CTX *restrict out, const SHA512_CTX *restrict in)
{
out->h[0] = in->h[0];
out->h[1] = in->h[1];
out->h[2] = in->h[2];
out->h[3] = in->h[3];
out->h[4] = in->h[4];
out->h[5] = in->h[5];
out->h[6] = in->h[6];
out->h[7] = in->h[7];
}
static inline void sha512_xor(SHA512_CTX *restrict out, const SHA512_CTX *restrict in)
{
out->h[0] ^= in->h[0];
out->h[1] ^= in->h[1];
out->h[2] ^= in->h[2];
out->h[3] ^= in->h[3];
out->h[4] ^= in->h[4];
out->h[5] ^= in->h[5];
out->h[6] ^= in->h[6];
out->h[7] ^= in->h[7];
}
DECL_PBKDF2(sha512,
SHA512_CBLOCK,
SHA512_DIGEST_LENGTH,
SHA512_CTX,
SHA512_Init,
SHA512_Update,
SHA512_Transform,
SHA512_Final,
sha512_cpy,
sha512_extract,
sha512_xor)
void fastpbkdf2_hmac_sha1(const uint8_t *pw, size_t npw,
const uint8_t *salt, size_t nsalt,
uint32_t iterations,
uint8_t *out, size_t nout)
{
PBKDF2(sha1)(pw, npw, salt, nsalt, iterations, out, nout);
}
void fastpbkdf2_hmac_sha256(const uint8_t *pw, size_t npw,
const uint8_t *salt, size_t nsalt,
uint32_t iterations,
uint8_t *out, size_t nout)
{
PBKDF2(sha256)(pw, npw, salt, nsalt, iterations, out, nout);
}
void fastpbkdf2_hmac_sha512(const uint8_t *pw, size_t npw,
const uint8_t *salt, size_t nsalt,
uint32_t iterations,
uint8_t *out, size_t nout)
{
PBKDF2(sha512)(pw, npw, salt, nsalt, iterations, out, nout);
}

71
fastpbkdf2.h Normal file
View File

@@ -0,0 +1,71 @@
/*
* fastpbkdf2 - Faster PBKDF2-HMAC calculation
* Written in 2015 by Joseph Birr-Pixton <jpixton@gmail.com>
*
* To the extent possible under law, the author(s) have dedicated all
* copyright and related and neighboring rights to this software to the
* public domain worldwide. This software is distributed without any
* warranty.
*
* You should have received a copy of the CC0 Public Domain Dedication
* along with this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#ifndef FASTPBKDF2_H
#define FASTPBKDF2_H
#include <stdlib.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/** Calculates PBKDF2-HMAC-SHA1.
*
* @p npw bytes at @p pw are the password input.
* @p nsalt bytes at @p salt are the salt input.
* @p iterations is the PBKDF2 iteration count and must be non-zero.
* @p nout bytes of output are written to @p out. @p nout must be non-zero.
*
* This function cannot fail; it does not report errors.
*/
void fastpbkdf2_hmac_sha1(const uint8_t *pw, size_t npw,
const uint8_t *salt, size_t nsalt,
uint32_t iterations,
uint8_t *out, size_t nout);
/** Calculates PBKDF2-HMAC-SHA256.
*
* @p npw bytes at @p pw are the password input.
* @p nsalt bytes at @p salt are the salt input.
* @p iterations is the PBKDF2 iteration count and must be non-zero.
* @p nout bytes of output are written to @p out. @p nout must be non-zero.
*
* This function cannot fail; it does not report errors.
*/
void fastpbkdf2_hmac_sha256(const uint8_t *pw, size_t npw,
const uint8_t *salt, size_t nsalt,
uint32_t iterations,
uint8_t *out, size_t nout);
/** Calculates PBKDF2-HMAC-SHA512.
*
* @p npw bytes at @p pw are the password input.
* @p nsalt bytes at @p salt are the salt input.
* @p iterations is the PBKDF2 iteration count and must be non-zero.
* @p nout bytes of output are written to @p out. @p nout must be non-zero.
*
* This function cannot fail; it does not report errors.
*/
void fastpbkdf2_hmac_sha512(const uint8_t *pw, size_t npw,
const uint8_t *salt, size_t nsalt,
uint32_t iterations,
uint8_t *out, size_t nout);
#ifdef __cplusplus
}
#endif
#endif

112
login.c Normal file
View File

@@ -0,0 +1,112 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <time.h>
#include <syslog.h>
#include <sys/utsname.h>
#include "ini.h"
#include "uthash.h"
#include "config.h"
#include "client.h"
#include "debug.h"
#include "msg.h"
#include "version.h"
#include "login.h"
#include "utils.h"
static struct login *c_login;
char *get_run_id()
{
return c_login->run_id;
}
struct login *get_common_login_config()
{
return c_login;
}
int is_logged()
{
return c_login->logged;
}
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);
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)
{
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);
}
debug(LOG_ERR, "login falied!");
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;
}

39
login.h Normal file
View File

@@ -0,0 +1,39 @@
#ifndef _LOGIN_H_
#define _LOGIN_H_
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include "uthash.h"
struct login {
char *version;
char *hostname;
char *os;
char *arch;
char *user;
char *privilege_key;
long int timestamp;
char *run_id;
char *metas;
int pool_count;
/* fields not need json marshal */
int logged; //0 not login 1:logged
};
struct login_resp {
char *version;
char *run_id;
char *error;
};
void init_login();
char *get_run_id();
struct login *get_common_login_config();
int is_logged();
int login_resp_check(struct login_resp *lr);
#endif //_LOGIN_H_

9
main.c
View File

@@ -21,15 +21,16 @@
/** @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"
int main(int argc, char **argv)
{
parse_commandline(argc, argv);
xfrp_client_loop();
init_login();
xfrpc_loop();
}

402
msg.c
View File

@@ -21,110 +21,378 @@
/** @file msg.c
@brief xfrp client msg related
@author Copyright (C) 2016 Dengfeng Liu <liudengfeng@kunteng.org>
@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>
#include <syslog.h>
#include <netinet/in.h>
#include "msg.h"
#include "const.h"
#include "config.h"
#include "debug.h"
#include "common.h"
#include "login.h"
#include "client.h"
#include "utils.h"
int control_request_marshal(const struct control_request *req, char **msg)
#define JSON_MARSHAL_TYPE(jobj,key,jtype,item) \
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};
char *
calc_md5(const char *data, int datalen)
{
const char *tmp = NULL;
int nret = 0;
struct json_object *j_ctl_req = json_object_new_object();
if (!j_ctl_req)
unsigned char digest[16] = {0};
char *out = (char*)malloc(33);
assert(out);
MD5_CTX md5;
MD5_Init(&md5);
MD5_Update(&md5, data, datalen);
MD5_Final(digest, &md5);
for (int n = 0; n < 16; ++n) {
snprintf(&(out[n*2]), 3, "%02x", (unsigned int)digest[n]);
}
return out;
}
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, ",");
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);
json_object_object_add(j_ctl_req, "custom_domains", jarray_cdomains);
}
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 seed[128] = {0};
*timestamp = time(NULL);
if (token)
snprintf(seed, 128, "%s%ld", token, *timestamp);
else
snprintf(seed, 128, "%ld", *timestamp);
return calc_md5(seed, strlen(seed));
}
size_t
login_request_marshal(char **msg)
{
size_t nret = 0;
struct json_object *j_login_req = json_object_new_object();
if (j_login_req == NULL)
return 0;
json_object_object_add(j_ctl_req, "type", json_object_new_int(req->type));
json_object_object_add(j_ctl_req, "proxy_name", json_object_new_string(req->proxy_name));
json_object_object_add(j_ctl_req, "auth_key",
json_object_new_string(req->auth_key?req->auth_key:""));
if (req->type == HeartbeatReq)
goto end_process;
json_object_object_add(j_ctl_req, "use_encryption", json_object_new_boolean(req->use_encryption));
json_object_object_add(j_ctl_req, "use_gzip", json_object_new_boolean(req->use_gzip));
json_object_object_add(j_ctl_req, "pool_count", json_object_new_int(req->pool_count));
json_object_object_add(j_ctl_req, "privilege_mode", json_object_new_boolean(req->privilege_mode));
json_object_object_add(j_ctl_req, "privilege_key",
json_object_new_string(req->privilege_key?req->privilege_key:""));
json_object_object_add(j_ctl_req, "proxy_type",
json_object_new_string(req->proxy_type?req->proxy_type:""));
json_object_object_add(j_ctl_req, "remote_port", json_object_new_int(req->remote_port));
if (!req->custom_domains)
json_object_object_add(j_ctl_req, "custom_domains", NULL);
else {
// need to implement it
;
}
if (!req->locations)
json_object_object_add(j_ctl_req, "locations", NULL);
else {
// need to implement it
;
}
json_object_object_add(j_ctl_req, "host_header_rewrite",
json_object_new_string(req->host_header_rewrite?req->host_header_rewrite:""));
json_object_object_add(j_ctl_req, "http_username",
json_object_new_string(req->http_username?req->http_username:""));
json_object_object_add(j_ctl_req, "http_password",
json_object_new_string(req->http_password?req->http_password:""));
json_object_object_add(j_ctl_req, "subdomain",
json_object_new_string(req->subdomain?req->subdomain:""));
json_object_object_add(j_ctl_req, "timestamp", json_object_new_int(req->timestamp));
struct login *lg = get_common_login_config();
if (!lg)
return 0;
SAFE_FREE(lg->privilege_key);
struct common_conf *cf = get_common_config();
char *auth_key = get_auth_key(cf->auth_token, &lg->timestamp);
lg->privilege_key = strdup(auth_key);
assert(lg->privilege_key);
end_process:
tmp = json_object_to_json_string(j_ctl_req);
JSON_MARSHAL_TYPE(j_login_req, "version", string, lg->version);
JSON_MARSHAL_TYPE(j_login_req, "hostname", string, SAFE_JSON_STRING(lg->hostname));
JSON_MARSHAL_TYPE(j_login_req, "os", string, lg->os);
JSON_MARSHAL_TYPE(j_login_req, "arch", string, lg->arch);
JSON_MARSHAL_TYPE(j_login_req, "user", string, SAFE_JSON_STRING(lg->user));
JSON_MARSHAL_TYPE(j_login_req, "privilege_key", string, SAFE_JSON_STRING(lg->privilege_key));
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_ctl_req);
json_object_put(j_login_req);
SAFE_FREE(auth_key);
return nret;
}
struct control_response *control_response_unmarshal(const char *jres)
int
new_proxy_service_marshal(const struct proxy_service *np_req, char **msg)
{
const char *tmp = NULL;
int nret = 0;
struct json_object *j_np_req = json_object_new_object();
if ( ! j_np_req)
return 0;
JSON_MARSHAL_TYPE(j_np_req, "proxy_name", string, np_req->proxy_name);
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);
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));
json_object *j_location_array = json_object_new_array();
if (np_req->locations) {
json_object_object_add(j_np_req, "locations", j_location_array);
} else {
json_object_object_add(j_np_req, "locations", NULL);
}
JSON_MARSHAL_TYPE(j_np_req, "host_header_rewrite", string, SAFE_JSON_STRING(np_req->host_header_rewrite));
JSON_MARSHAL_TYPE(j_np_req, "http_user", string, SAFE_JSON_STRING(np_req->http_user));
JSON_MARSHAL_TYPE(j_np_req, "http_pwd", string, SAFE_JSON_STRING(np_req->http_pwd));
tmp = json_object_to_json_string(j_np_req);
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)
{
const char *tmp = NULL;
int nret = 0;
struct json_object *j_new_work_conn = json_object_new_object();
if (! j_new_work_conn)
return 0;
JSON_MARSHAL_TYPE(j_new_work_conn, "run_id", string, SAFE_JSON_STRING(work_c->run_id));
tmp = json_object_to_json_string(j_new_work_conn);
if (tmp && strlen(tmp) > 0) {
nret = strlen(tmp);
*msg = strdup(tmp);
assert(*msg);
}
json_object_put(j_new_work_conn);
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);
}else
goto END_ERROR;
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 json_object *j_lg_res = json_tokener_parse(jres);
if (j_lg_res == NULL)
return NULL;
struct login_resp *lr = calloc(1, sizeof(struct login_resp));
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 json_object *j_start_w_res = json_tokener_parse(resp_msg);
if (j_start_w_res == NULL)
return NULL;
struct start_work_conn_resp *sr = calloc(1, sizeof(struct start_work_conn_resp));
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 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 error;
}
assert(ctl_res);
struct json_object *jtype = json_object_object_get(j_ctl_res, "type");
if (jtype == NULL) {
goto error;
}
struct json_object *jtype = NULL;
if(! json_object_object_get_ex(j_ctl_res, "type", &jtype))
goto END_ERROR;
ctl_res->type = json_object_get_int(jtype);
struct json_object *jcode = json_object_object_get(j_ctl_res, "code");
if (jcode == NULL)
goto error;
struct json_object *jcode = NULL;
if(! json_object_object_get_ex(j_ctl_res, "code", &jcode))
goto END_ERROR;
ctl_res->code = json_object_get_int(jcode);
struct json_object *jmsg = json_object_object_get(j_ctl_res, "msg");
if (jmsg)
struct json_object *jmsg = NULL;
if(json_object_object_get_ex(j_ctl_res, "msg", &jmsg)) {
ctl_res->msg = strdup(json_object_get_string(jmsg));
error:
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;
if (res->msg) free(res->msg);
free(res);
SAFE_FREE(res->msg);
SAFE_FREE(res);
}
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)
return 1;
}
return 0;
}

105
msg.h
View File

@@ -21,48 +21,97 @@
/** @file msg.h
@brief xfrp msg struct
@author Copyright (C) 2016 Dengfeng Liu <liudengfeng@kunteng.org>
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
*/
#ifndef _MSG_H_
#define _MSG_H_
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <inttypes.h>
#include "client.h"
#include "common.h"
#define TYPE_LEN 1 //byte, char
#define MSG_TYPE_I 0
#define MSG_LEN_I 1
#define MSG_DATA_I 9
// msg_type match frp v0.10.0
enum msg_type {
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 __attribute__((__packed__)) msg_hdr {
char type;
uint64_t length;
uint8_t data[];
};
struct start_work_conn_resp {
char *proxy_name;
};
int new_proxy_service_marshal(const struct proxy_service *np_req, char **msg);
int msg_type_valid_check(char msg_type);
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);
// 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);
// parse json string to control response
struct control_response *control_response_unmarshal(const char *jres);
struct work_conn *new_work_conn();
int new_work_conn_marshal(const struct work_conn *work_c, char **msg);
void control_response_free(struct control_response *res);
#endif //_MSG_H_

54
openwrt/Makefile Normal file
View File

@@ -0,0 +1,54 @@
#
# Copyright (C) 2022 Dengfeng Liu
#
# This is free software, licensed under the GNU General Public License v3.
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
PKG_NAME:=xfrpc
PKG_VERSION:=master
PKG_RELEASE:=1
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL:=https://github.com/liudf0716/xfrpc.git
PKG_SOURCE_VERSION:=$(PKG_VERSION)
PKG_MIRROR_HASH:=a7141da8a85203d8341fd6d2551f1228396ae54aace6ec0bad2dfeb89e0a377d
PKG_MAINTAINER:=Dengfeng Liu <liudf0716@gmail.com>
PKG_LICENSE:=GPL-3.0-or-later
PKG_LICENSE_FILES:=COPYING
include $(INCLUDE_DIR)/package.mk
include $(INCLUDE_DIR)/cmake.mk
define Package/xfrpc
SUBMENU:=Web Servers/Proxies
SECTION:=net
CATEGORY:=Network
DEPENDS:=+zlib +libjson-c +libevent2 +libevent2-openssl
TITLE:= C language fast reverse proxy client
URL:=https://github.com/liudf0716/xfrpc
endef
define Package/xfrpc/description
xfrpc is C language fast reverse proxy client
compare with golang version frpc
xfrpc can run in almost all openwrt device
endef
define Package/xfrpc/conffiles
/etc/config/xfrpc
endef
define Package/xfrpc/install
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/xfrpc $(1)/usr/bin/xfrpc
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) ./files/xfrpc.init $(1)/etc/init.d/xfrpc
$(INSTALL_DIR) $(1)/etc/config
$(CP) ./files/xfrpc.conf $(1)/etc/config/xfrpc
endef
$(eval $(call BuildPackage,xfrpc))

31
openwrt/files/xfrpc.conf Normal file
View File

@@ -0,0 +1,31 @@
config xfrp 'init'
option disabled 1
option loglevel 7
config xfrpc 'common'
option server_addr 127.0.0.1
option server_port 7000
option auth_token abdesf13d
config xfrpc 'ssh01'
option type tcp
option local_ip 127.0.0.1
option local_port 22
option remote_port 6000
#config xfrpc 'ftp01'
# option type ftp
# option local_ip 127.0.01
# option local_port 21
# option remote_port 8021
# option remote_data_port 8022
#config xfrpc 'web01'
# option type http
# option local_ip 127.0.0.1
# option local_port 8080
#config xfrpc 'web02'
# option type https
# option local_ip 127.0.0.1
# option local_port 8443

93
openwrt/files/xfrpc.init Normal file
View File

@@ -0,0 +1,93 @@
#!/bin/sh /etc/rc.common
# Copyright (C) 2022 Dengfeng Liu <liu_df@qq.com>
#
# This is free software, licensed under the GNU General Public License v3.
# See /LICENSE for more information.
#
START=99
USE_PROCD=1
NAME=xfrpc
PROG=/usr/bin/$NAME
handle_xfrpc() {
local name="$1"
local config="$2"
echo "[$name]" >> "$config"
handle_type() {
uci_validate_section xfrpc xfrpc "$name" \
'type:or("tcp", "udp", "ftp", "http", "https")' \
'local_ip:ipaddr:127.0.0.1' \
'local_port:uinteger'
echo "type = $type" >> "$config"
echo "local_ip = $local_ip" >> "$config"
echo "local_port = $local_port" >> "$config"
case "$type" in
"tcp"|"udp")
config_get remote_port "$name" remote_port
echo "remote_port = $remote_port" >> "$config"
;;
"ftp")
config_get remote_port "$name" remote_port
config_get remote_data_port "$name" remote_data_port
echo "remote_port = $remote_port" >> "$config"
echo "remote_data_port = $remote_data_port" >> "$config"
;;
esac
}
if [ "$name" = "common" ]; then
uci_validate_section xfrpc xfrpc "$name" \
'server_addr:ipaddr' \
'server_port:uinteger' \
'auth_token:string'
[ -z "$auth_token" ] && {
echo "no auth_token"
exit
}
echo "server_addr = $server_addr" >> "$config"
echo "server_port = $server_port" >> "$config"
echo "auth_token = $auth_token" >> "$config"
else
handle_type
fi
}
service_triggers() {
procd_add_reload_trigger "$NAME"
}
start_service() {
local conf_file="/var/etc/$NAME.ini"
> "$conf_file"
config_load "$NAME"
uci_validate_section xfrpc xfrpc init \
'disabled:bool:1' \
'loglevel:uinteger:0'
if [ $disabled = 1 ]; then
echo "xfrpc service disabled"
return
fi
config_foreach handle_xfrpc xfrpc "$conf_file"
procd_open_instance
procd_set_param command "$PROG" -c "$conf_file" -f -d $loglevel
procd_set_param file "$conf_file"
procd_set_param respawn
procd_close_instance
}
reload_service() {
stop
start
}

38
proxy.c Normal file
View File

@@ -0,0 +1,38 @@
#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"
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);
}

37
proxy.h Normal file
View File

@@ -0,0 +1,37 @@
#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
View 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_ip) {
debug(LOG_ERR, "error: FTP proxy without server ip!");
exit(0);
}
strncpy(r_fp->ftp_server_ip, c_conf->server_ip, 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;
}

49
proxy_tcp.c Normal file
View File

@@ -0,0 +1,49 @@
#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"
// read data from local service
void tcp_proxy_c2s_cb(struct bufferevent *bev, void *ctx)
{
struct proxy_client *client = (struct proxy_client *)ctx;
assert(client);
struct bufferevent *partner = client->ctl_bev;
assert(partner);
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);
}
}
// read data from frps
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);
dst = bufferevent_get_output(partner);
evbuffer_add_buffer(dst, src);
}

54
session.c Normal file
View File

@@ -0,0 +1,54 @@
#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"
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 Normal file
View File

@@ -0,0 +1,11 @@
#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_

167
testfastpbkdf2.c Normal file
View File

@@ -0,0 +1,167 @@
#include "fastpbkdf2.h"
#include <stdio.h>
#include <assert.h>
#include <string.h>
typedef void (*pbkdf2_fn)(const uint8_t *pw, size_t npw,
const uint8_t *salt, size_t nsalt,
uint32_t iterations,
uint8_t *out, size_t nout);
static void dump(const char *label, const uint8_t *data, size_t n)
{
printf("%s: ", label);
for (size_t i = 0; i < n; i++)
printf("%02x", data[i]);
printf("\n");
}
static void check(pbkdf2_fn fn,
const void *pw, size_t npw,
const void *salt, size_t nsalt,
unsigned iterations,
const void *expect, size_t nexpect)
{
uint8_t out[128];
assert(nexpect < sizeof(out));
fn(pw, npw,
salt, nsalt,
iterations,
out, nexpect);
dump("expect", expect, nexpect);
dump("got ", out, nexpect);
assert(memcmp(expect, out, nexpect) == 0);
printf("- test passed\n");
}
int main(void)
{
/* nb. do not edit this code. edit gentests.py instead. */
printf("sha1 (6 tests):\n");
check(fastpbkdf2_hmac_sha1,
"password", 8,
"salt", 4,
1,
"\x0c\x60\xc8\x0f\x96\x1f\x0e\x71\xf3\xa9\xb5\x24\xaf\x60\x12\x06\x2f\xe0\x37\xa6", 20);
check(fastpbkdf2_hmac_sha1,
"password", 8,
"salt", 4,
2,
"\xea\x6c\x01\x4d\xc7\x2d\x6f\x8c\xcd\x1e\xd9\x2a\xce\x1d\x41\xf0\xd8\xde\x89\x57", 20);
check(fastpbkdf2_hmac_sha1,
"password", 8,
"salt", 4,
4096,
"K\x00\x79\x01\xb7\x65\x48\x9a\xbe\xad\x49\xd9\x26\xf7\x21\xd0\x65\xa4\x29\xc1", 20);
check(fastpbkdf2_hmac_sha1,
"password", 8,
"salt", 4,
16777216,
"\xee\xfe\x3d\x61\xcd\x4d\xa4\xe4\xe9\x94\x5b\x3d\x6b\xa2\x15\x8c\x26\x34\xe9\x84", 20);
check(fastpbkdf2_hmac_sha1,
"passwordPASSWORDpassword", 24,
"saltSALTsaltSALTsaltSALTsaltSALTsalt", 36,
4096,
"\x3d\x2e\xec\x4f\xe4\x1c\x84\x9b\x80\xc8\xd8\x36\x62\xc0\xe4\x4a\x8b\x29\x1a\x96\x4c\xf2\xf0\x70\x38", 25);
check(fastpbkdf2_hmac_sha1,
"pass\x00\x77\x6f\x72\x64", 9,
"sa\x00\x6c\x74", 5,
4096,
"V\xfa\x6a\xa7\x55\x48\x09\x9d\xcc\x37\xd7\xf0\x34\x25\xe0\xc3", 16);
printf("ok\n");
printf("sha256 (9 tests):\n");
check(fastpbkdf2_hmac_sha256,
"passwd", 6,
"salt", 4,
1,
"U\xac\x04\x6e\x56\xe3\x08\x9f\xec\x16\x91\xc2\x25\x44\xb6\x05\xf9\x41\x85\x21\x6d\xde\x04\x65\xe6\x8b\x9d\x57\xc2\x0d\xac\xbc\x49\xca\x9c\xcc\xf1\x79\xb6\x45\x99\x16\x64\xb3\x9d\x77\xef\x31\x7c\x71\xb8\x45\xb1\xe3\x0b\xd5\x09\x11\x20\x41\xd3\xa1\x97\x83", 64);
check(fastpbkdf2_hmac_sha256,
"Password", 8,
"NaCl", 4,
80000,
"M\xdc\xd8\xf6\x0b\x98\xbe\x21\x83\x0c\xee\x5e\xf2\x27\x01\xf9\x64\x1a\x44\x18\xd0\x4c\x04\x14\xae\xff\x08\x87\x6b\x34\xab\x56\xa1\xd4\x25\xa1\x22\x58\x33\x54\x9a\xdb\x84\x1b\x51\xc9\xb3\x17\x6a\x27\x2b\xde\xbb\xa1\xd0\x78\x47\x8f\x62\xb3\x97\xf3\x3c\x8d", 64);
check(fastpbkdf2_hmac_sha256,
"password", 8,
"salt", 4,
1,
"\x12\x0f\xb6\xcf\xfc\xf8\xb3\x2c\x43\xe7\x22\x52\x56\xc4\xf8\x37\xa8\x65\x48\xc9\x2c\xcc\x35\x48\x08\x05\x98\x7c\xb7\x0b\xe1\x7b", 32);
check(fastpbkdf2_hmac_sha256,
"password", 8,
"salt", 4,
2,
"\xae\x4d\x0c\x95\xaf\x6b\x46\xd3\x2d\x0a\xdf\xf9\x28\xf0\x6d\xd0\x2a\x30\x3f\x8e\xf3\xc2\x51\xdf\xd6\xe2\xd8\x5a\x95\x47\x4c\x43", 32);
check(fastpbkdf2_hmac_sha256,
"password", 8,
"salt", 4,
4096,
"\xc5\xe4\x78\xd5\x92\x88\xc8\x41\xaa\x53\x0d\xb6\x84\x5c\x4c\x8d\x96\x28\x93\xa0\x01\xce\x4e\x11\xa4\x96\x38\x73\xaa\x98\x13\x4a", 32);
check(fastpbkdf2_hmac_sha256,
"passwordPASSWORDpassword", 24,
"saltSALTsaltSALTsaltSALTsaltSALTsalt", 36,
4096,
"\x34\x8c\x89\xdb\xcb\xd3\x2b\x2f\x32\xd8\x14\xb8\x11\x6e\x84\xcf\x2b\x17\x34\x7e\xbc\x18\x00\x18\x1c\x4e\x2a\x1f\xb8\xdd\x53\xe1\xc6\x35\x51\x8c\x7d\xac\x47\xe9", 40);
check(fastpbkdf2_hmac_sha256,
"", 0,
"salt", 4,
1024,
"\x9e\x83\xf2\x79\xc0\x40\xf2\xa1\x1a\xa4\xa0\x2b\x24\xc4\x18\xf2\xd3\xcb\x39\x56\x0c\x96\x27\xfa\x4f\x47\xe3\xbc\xc2\x89\x7c\x3d", 32);
check(fastpbkdf2_hmac_sha256,
"password", 8,
"", 0,
1024,
"\xea\x58\x08\x41\x1e\xb0\xc7\xe8\x30\xde\xab\x55\x09\x6c\xee\x58\x27\x61\xe2\x2a\x9b\xc0\x34\xe3\xec\xe9\x25\x22\x5b\x07\xbf\x46", 32);
check(fastpbkdf2_hmac_sha256,
"pass\x00\x77\x6f\x72\x64", 9,
"sa\x00\x6c\x74", 5,
4096,
"\x89\xb6\x9d\x05\x16\xf8\x29\x89\x3c\x69\x62\x26\x65\x0a\x86\x87", 16);
printf("ok\n");
printf("sha512 (4 tests):\n");
check(fastpbkdf2_hmac_sha512,
"password", 8,
"salt", 4,
1,
"\x86\x7f\x70\xcf\x1a\xde\x02\xcf\xf3\x75\x25\x99\xa3\xa5\x3d\xc4\xaf\x34\xc7\xa6\x69\x81\x5a\xe5\xd5\x13\x55\x4e\x1c\x8c\xf2\x52", 32);
check(fastpbkdf2_hmac_sha512,
"password", 8,
"salt", 4,
2,
"\xe1\xd9\xc1\x6a\xa6\x81\x70\x8a\x45\xf5\xc7\xc4\xe2\x15\xce\xb6\x6e\x01\x1a\x2e\x9f\x00\x40\x71\x3f\x18\xae\xfd\xb8\x66\xd5\x3c", 32);
check(fastpbkdf2_hmac_sha512,
"password", 8,
"salt", 4,
4096,
"\xd1\x97\xb1\xb3\x3d\xb0\x14\x3e\x01\x8b\x12\xf3\xd1\xd1\x47\x9e\x6c\xde\xbd\xcc\x97\xc5\xc0\xf8\x7f\x69\x02\xe0\x72\xf4\x57\xb5", 32);
check(fastpbkdf2_hmac_sha512,
"passwordPASSWORDpassword", 24,
"saltSALTsaltSALTsaltSALTsaltSALTsalt", 36,
1,
"n\x23\xf2\x76\x38\x08\x4b\x0f\x7e\xa1\x73\x4e\x0d\x98\x41\xf5\x5d\xd2\x9e\xa6\x0a\x83\x44\x66\xf3\x39\x6b\xac\x80\x1f\xac\x1e\xeb\x63\x80\x2f\x03\xa0\xb4\xac\xd7\x60\x3e\x36\x99\xc8\xb7\x44\x37\xbe\x83\xff\x01\xad\x7f\x55\xda\xc1\xef\x60\xf4\xd5\x64\x80\xc3\x5e\xe6\x8f\xd5\x2c\x69\x36", 72);
printf("ok\n");
return 0;
}

210
utils.c Normal file
View File

@@ -0,0 +1,210 @@
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <arpa/inet.h>
#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"
// s_sleep using select instead of sleep
// s: second, u: usec 10^6usec = 1s
void s_sleep(unsigned int s, unsigned int u)
{
struct timeval timeout;
timeout.tv_sec = s;
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;
}

19
utils.h Normal file
View File

@@ -0,0 +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_

View File

@@ -1,6 +1,8 @@
#ifndef _VERSION_H_
#define _VERSION_H_
#define VERSION "0.05."
#define VERSION "1.41.1"
#define PROTOCOL_VERESION "0.41.0"
#define CLIENT_V 1
#endif
#endif //_VERSION_H_

View File

@@ -1,80 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <event2/event.h>
#include <event2/bufferevent.h>
#define PORT 7000
#define BACKLOG 100
void readcb(struct bufferevent *bufev, void *arg)
{
char buf[1024] = {0};
size_t readlen;
int res;
readlen = bufferevent_read(bufev, buf, sizeof(buf));
printf("buf:[%s]\n", buf);
}
void writecb(struct bufferevent *bufev, void *arg)
{
}
void errorcb(struct bufferevent *bufev, short event, void *arg)
{
if (event & BEV_EVENT_EOF) {
bufferevent_free(bufev);
printf("Disconnect\n");
} else if (event & BEV_EVENT_ERROR) {
bufferevent_free(bufev);
printf("Got error\n");
} else if (event & BEV_EVENT_TIMEOUT) {
printf("Timeout\n");
}
}
void accept_handler(int fd, short event, void *arg)
{
struct event_base *evbase;
struct bufferevent *bufev;
int sock;
struct sockaddr_in addr;
socklen_t addrlen;
evbase = (struct event_base *)arg;
if (event & EV_READ) {
sock = accept(fd, (struct sockaddr*)&addr, &addrlen);
bufev = bufferevent_socket_new(evbase, sock, BEV_OPT_CLOSE_ON_FREE);
bufferevent_setcb(bufev, readcb, writecb, errorcb, NULL);
bufferevent_enable(bufev, EV_READ | EV_WRITE);
}
}
int main(int argc, char** argv)
{
struct event_base *evbase;
struct event *ev;
struct sockaddr_in sin;
int sock;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons(PORT);
sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
bind(sock, (struct sockaddr*)&sin, sizeof(sin));
listen(sock, BACKLOG);
evbase = event_base_new();
ev = event_new(evbase, sock, EV_READ | EV_PERSIST, accept_handler, evbase);
event_add(ev, NULL);
event_base_dispatch(evbase);
event_free(ev);
event_base_free(evbase);
return 0;
}

View File

@@ -19,9 +19,9 @@
* *
\********************************************************************/
/** @file xfrp_client.c
/** @file xfrpc.c
@brief xfrp client
@author Copyright (C) 2016 Dengfeng Liu <liudengfeng@kunteng.org>
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
*/
#include <string.h>
@@ -29,19 +29,11 @@
#include <stdio.h>
#include <errno.h>
#include <assert.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <json-c/json.h>
#include <syslog.h>
#include <event2/bufferevent.h>
#include <event2/buffer.h>
#include <event2/listener.h>
#include <event2/util.h>
#include <event2/event.h>
#include "commandline.h"
#include "client.h"
@@ -49,34 +41,15 @@
#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"
static void start_xfrp_client(struct event_base *base)
void xfrpc_loop()
{
struct proxy_client *all_pc = get_all_pc();
struct proxy_client *pc = NULL, *tmp = NULL;
init_main_control();
run_control();
debug(LOG_INFO, "Start xfrp client");
HASH_ITER(hh, all_pc, pc, tmp) {
pc->base = base;
control_process(pc);
}
}
void xfrp_client_loop()
{
struct event_base *base = NULL;
base = event_base_new();
if (!base) {
debug(LOG_ERR, "event_base_new() error");
exit(0);
}
start_xfrp_client(base);
event_base_dispatch(base);
event_base_free(base);
close_main_control();
}

View File

@@ -19,9 +19,14 @@
* *
\********************************************************************/
/** @file xfrp_client.h
/** @file xfrpc.h
@brief xfrp client header file
@author Copyright (C) 2016 Dengfeng Liu <liudengfeng@kunteng.org>
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
*/
void xfrp_client_loop();
#ifndef _XFRPC_H_
#define _XFRPC_H_
void xfrpc_loop();
#endif //_XFRPC_H_

View File

@@ -1,10 +1,10 @@
[common]
server_addr = wifidog.kunteng.org
server_addr = your_server_ip
server_port = 7000
auth_token = 123
privilege_token = 12345678
token = 12345678
[ssh]
type = tcp
local_ip = 127.0.0.1
local_port = 22
remote_port = 6128

2
zip.c
View File

@@ -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>

2
zip.h
View File

@@ -21,7 +21,7 @@
/** @file zip.h
@brief zlib related function
@author Copyright (C) 2016 Dengfeng Liu <liudengfeng@kunteng.org>
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
*/
#ifndef _ZIP_H_