2019年9月

本文原地址: http://www.feitianzhi.com/boke/index.php/archives/22/

转载请注明出处,有疑问或错误请发邮件到[email protected] 或加QQ群:869598376


概述

      VPN是一种非常成熟的技术,各大操作系统都默认支持pptp,l2tp等技术,但这些技术的使用成本过高,如pptp依赖GRE,l2tp有特殊的关键字,在通信过程中存在被截断的可能;

      KVPN并不仅是为解决传统vpn的缺陷而开发,KVPN是为优化网络速度而开发,KVPN同时支持tcp,udp,http的传输协议,在使用过程中自动选择最优路线进行通信(问:http比tcp优?答:http是为利用历史原因出现的http cdn加速,让本只支持http的cdn加速为我其他应用服务);

KVPN应用场景

  1. 穿透性要求:kvpn数据流无特殊固定的关键字,同时支持动态的数据扰乱,让数据流不具备可识别性,承载方式同时支持tcp,udp,http,数据与普通数据亲近,让数据具备极强的穿透性(延伸扩展:把数据封装于http承载的jpg图片中--只要能用http请求图片的网络都能过,把数据封装在h264,h265视频流中--这样能支持rtsp,rtmp,hls,gb28181的网都能过);
  2. TCP加速要求:tcp是系统实现的可靠传输,重传机制和效率受系统的影响,在总带宽有限的条件下(如果只有我一个人用是够的条件下),如何保证自己的业务畅快运行(实现不公平竞争),是招标pk时经常需要面对的问题;kvpn在进行vpn数据传输时,对tcp数据进行识别,在数据还未发出时就假冒对放作出tcp的回执确认,让系统永远认为网络非常顺畅,kvpn再自己把假冒的数据使用udp(加冗余,快速丢包重传,抢占他人带宽--平时大家都用过迅雷抢带宽)把数据发给对端,实现数据快速通信;
  3. 改善udp效果:udp是不可靠通信,在网络差时会丢包,会对业务产生影响(有的应用程序只能在好的网络下可正常运行--使用udp但没有重传机制),kvpn是基于本机不丢包的前提,在网络传输过程中使用可靠的tcp或带重传机制的udp进行数据传输,保证业务的正常运行;
  4. 低成本的网络加速:因历史原因到一些地方的服务器的延时高,速度慢,而在目前互联网洪水下浮枝(免费资源)的拾取成本较低,其中免费的http cdn加速就是一个很好的选择,kvpn可以把数据封装在http中进行传输,利用免费的cdn进行加速;
  5. 协议识别的再次分发:对于代理软件的开发成本与协议相关,如rtsp代理,代理需要拉取rtsp再对rtsp进行转发,开发需要实现rtsp的完整协议,开发成本高,那可以只识别rtsp的第一条指令,根据指令动态映射到指定服务器吗?使用kvpn在“小雉视频系统”中通过实现视频协议的识别和ip包级别动态路由来实现各种视频应用是kvpn开发的最主要的目的,此部分属于“小雉视频系统”中的高级开发;

KVPN的简单使用

本处提供简单的kvpn测试demo,并提供在centos7(小雉系统中也集成了此demo,可使用小雉系统测试)下的使用教程

  1. 下载kvpn,https://download.csdn.net/download/zhangrui_fslib_org/11693940
  2. 运行服务端
    kvpn服务端
    监听16899端口,允许用户名:user,密码:pwd登录系统
    在客户端认证成功后,本机使用1.1.1.1的ip,分配2.2.2.2给客户端使用
  3. 运行客户端
    kvpn客户端
    使用用户名:user,密码:pwd登录服务器10.172.100.81:16899
  4. 查看服务端结果
    kvpn服务端运行结果
  5. 查看客户端结果
    kvpn客户端运行结果

小雉系统中的VPN使用

小雉系统除集成KVPN外,为与各操作系统集成还集成了PPTP和L2TP,关于小雉系统您需要浏览以下文章:
小雉系统安装:http://www.feitianzhi.com/boke/index.php/archives/11/
小雉系统网络配置:http://www.feitianzhi.com/boke/index.php/archives/15/
小雉系统硬盘配置:http://www.feitianzhi.com/boke/index.php/archives/16/
小雉系统远程升级:http://www.feitianzhi.com/boke/index.php/archives/14/

  • 在小雉系统中使用pptp或l2tp,以使用10.172.100.81作为服务器

服务器配置



客户端配置,以windows为例




  • kvpn的使用

服务器配置,以10.172.100.81作为服务器



客户端配置,以10.172.100.82作为客户端


本文原地址: http://www.feitianzhi.com/boke/index.php/archives/21/

转载请注明出处,有疑问或错误请发邮件到[email protected] 或加QQ群:869598376


参考文章:https://www.oschina.net/question/234345_52687

用例子说话

二进制

对应源码

有一个程序

a.out

main.c

需要加载插件A

libA.so

liba.c

A需要另一个动态库

libB.so

libB1.c 或 libB2.c

本文的关注点就是:到底是哪一个libB.so被加载

目录结构:

/home/debao/ttt/a.out
/home/debao/ttt/libA.so
/home/debao/ttt/libB.so
/usr/lib/libB.so
具体源码
main.c ==> ./a.out

include <stdio.h>

include <dlfcn.h>

typedef int (*funcA)(int, int);
int main()
{

void * plugin = dlopen("./libA.so", RTLD_LAZY);
funcA f = (funcA)dlsym(plugin, "funcA");
printf("main: %d\n", f(3,4));
return 0;

}
liba.c ==> ./libA.so

include <stdio.h>

int funcB(int, int);
int funcA(int a, int b)
{

printf("hello from funcA\n");
return funcB(a, b);

}
libb1.c ==> ./libB.so

include <stdio.h>

int funcB(int a, int b)
{

printf("Hello from funcB 1\n");
return a*b;

}
libb2.c ==> /usr/lib/libB.so

include <stdio.h>

int funcB(int a, int b)
{

printf("Hello from funcB 2\n");
return a*b;

}
编译库文件
编译动态库libB.so

$ gcc -shared -fPIC libb2.c -o libB2.so
$ sudo mv libB2.so /usr/lib/libB.so
$ gcc -shared -fPIC libb.c -o libB.so
编译动态库libA.so

$ gcc -shared -fPIC liba.c -o libA.so -L. -lB
顺便看看该elf文件的头部信息:

$ readelf libA.so -d

Dynamic section at offset 0xf20 contains 21 entries:
Tag Type Name/Value
0x00000001 (NEEDED) Shared library: [libB.so]
0x00000001 (NEEDED) Shared library: [libc.so.6]
...
恩,只有库的文件名信息,而没有路径信息。

编译程序
第一次编译运行(什么路径都不加)

$ gcc main.c -ldl
$ ./a.out
hello from funcA
Hello from funcB 2
main: 12
程序:dlopen从当前目录找到libA.so,然后却在/usr/lib/中找到libB.so(没有使用当前目录的libB.so,这是我们需要的么?)

第二次编译运行(使用DT_RPATH)

$ gcc main.c -ldl -Wl,--rpath=.
$ ./a.out
hello from funcA
Hello from funcB 1
main: 12
恩,使用当前目录的libB.so,很理想的东西

可是,由于DT_RPATH无法被环境变量LD_LIBRARY_PATH覆盖,不是不建议被使用,而是建议使用DT_RUNPATH么?

第三次编译运行(使用DT_RUNPATH)

$ gcc main.c -ldl -Wl,--rpath=.,--enable-new-dtags
$ ./a.out
hello from funcA
Hello from funcB 2
main: 12
问题重新出现,使用的系统路径中的libB.so 而不是当前目录下的。

程序头部信息
通过下列命令可以查看:

$ readelf -d a.out
为了完整起见,列出前面3次编译的程序的信息:

没有rpath和runpath

Dynamic section at offset 0xf20 contains 21 entries:
Tag Type Name/Value
0x00000001 (NEEDED) Shared library: [libdl.so.2]
0x00000001 (NEEDED) Shared library: [libc.so.6]
0x0000000c (INIT) 0x8048360
...
包含rpath

Dynamic section at offset 0xf18 contains 22 entries:
Tag Type Name/Value
0x00000001 (NEEDED) Shared library: [libdl.so.2]
0x00000001 (NEEDED) Shared library: [libc.so.6]
0x0000000f (RPATH) Library rpath: [.]
0x0000000c (INIT) 0x8048360
....
包含rpath和runpath

Dynamic section at offset 0xf10 contains 23 entries:
Tag Type Name/Value
0x00000001 (NEEDED) Shared library: [libdl.so.2]
0x00000001 (NEEDED) Shared library: [libc.so.6]
0x0000000f (RPATH) Library rpath: [.]
0x0000001d (RUNPATH) Library runpath: [.]
原因
RPATH and RUNPATH给出这个问题的答案:

Unless loading object has RUNPATH:

RPATH of the loading object,
    then the RPATH of its loader (unless it has a RUNPATH), ...,
    until the end of the chain, which is either the executable
    or an object loaded by dlopen
Unless executable has RUNPATH:
    RPATH of the executable

LD_LIBRARY_PATH
RUNPATH of the loading object
ld.so.cache
default dirs
用它解释第一个程序:

libA.so 没有RUNPATH,故而
使用其RPATH (没有)
递归查找其loader直到链条的顶端(可执行程序或被dlopen打开的对象)的RPATH或者遇RUNPATH退出 (没有命中)
可执行程序没有RUNPATH,故而
使用其RPATH (没有)
环境变量LD_LIBRARY_PATH,(没有)
libA.so 的RUNPATH (没有)
ld.so.cache (没有命中)
默认路径/usr/lib (命中)
用它解释第二个程序:

libA.so 没有RUNPATH,故而
使用其RPATH (没有)
递归查找其loader直到链条的顶端(可执行程序或被dlopen打开的对象)的RPATH或者遇RUNPATH退出 (没有命中)
可执行程序没有RUNPATH,故而
使用其RPATH (命中)
用它解释第三个程序:

libA.so 没有RUNPATH,故而
使用其RPATH (没有)
递归查找其loader直到链条的顶端(可执行程序或被dlopen打开的对象)的RPATH或者遇RUNPATH退出 (没有命中)
可执行程序有RUNPATH,(继续前行)
环境变量LD_LIBRARY_PATH,(没有)
libA.so 的RUNPATH (没有)
ld.so.cache (没有命中)
默认路径/usr/lib (命中)
有意思的就是这个程序了,可执行程序的RUNPATH是一个重要的判断条件,却并不被做为这儿搜索路径!!

本文原地址: http://www.feitianzhi.com/boke/index.php/archives/20/

转载请注明出处,有疑问或错误请发邮件到[email protected] 或加QQ群:869598376


本文纯探讨技术实现,请大家抱着学习交流之目的进行阅览。

-rpath和-rpath-link的区别

(1)-rpath和-rpath-link都可以在链接时指定库的路径;
(2)运行可执行文件时,-rpath-link指定的路径不再有效(链接器没有将库的路径包含进可执行文件中),
           而-rpath指定的路径还有效(因为链接器已经将库的路径包含在可执行文件中);
(3)-L指定的是链接时的库路径,生成的可执行文件在运行时库的路径仍由LD_LIBRARY_PATH环境变量指定;

(4)不管采用何种选项链接,当提示找不到动态库时均可通过设置LD_LIBRARY_PATH解决。
其中 $$ORIGIN表示文件的当前路径,./表示应用程序的路径,一般-rpath,'$$ORIGIN'才能获得想要的效果;
-rpath,'$$ORIGIN',--enable-new-dtags 会在程序中加再加(RUNPATH)标签,参考http://www.feitianzhi.com/boke/index.php/archives/21/

gcc -ffunction-sections -fdata-sections -Wl,–gc-sections 减小程序体积

GCC链接操作是以section作为最小的处理单元,只要一个section中的某个符号被引用,该section就会被加入到可执行程序中去。因此,GCC在编译时可以使用 -ffunction-sections 和 -fdata-sections 将每个函数或符号创建为一个sections,其中每个sections名与function或data名保持一致。而在链接阶段, -Wl,–gc-sections 指示链接器去掉不用的section(其中-wl, 表示后面的参数 -gc-sections 传递给链接器),这样就能减少最终的可执行程序的大小了。
我们常常使用下面的配置启用这个功能:

CFLAGS += -ffunction-sections -fdata-sections
LDFLAGS += -Wl,--gc-sections

让make更透明些

在编译信息里面看到详细的gcc/g++的编译参数

make VERBOSE=1

在CMakeLists.txt里面加上这句指令也可以

set(CMAKE_VERBOSE_MAKEFILE ON)