ngrok反向隧道

前情提要:小明与小白各有一台主机,两台主机在同一内网,小明想直接通过内网ssh到小白的主机上。但是小白的ip地址会不断的变化,而小明不想每次都要麻烦小白查看ip。于是小明催生了一个想法:写个脚本在自己的主机运行输出小白的ip。

01 获取本机ip地址

> cat ip-server.c

#include  <stdio.h>
#include  <sys/socket.h>
#include  <unistd.h>
#include  <sys/types.h>
#include  <netinet/in.h>
#include  <stdlib.h>
#include  <time.h>
#include  <string.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <arpa/inet.h>

#define  SERVER_PORT 20000  //  define the defualt connect port id
#define  LENGTH_OF_LISTEN_QUEUE 10  // length of listen queue in server
#define  BUFFER_SIZE 255 

unsigned long getNumIP(char* dev){//eth0
    int fd;
    struct ifreq ifr;
    fd = socket(AF_INET, SOCK_DGRAM, 0);
    /* I want to get an IPv4 IP address */
    ifr.ifr_addr.sa_family = AF_INET;
    /* I want IP address attached to "eth0" */
    strncpy(ifr.ifr_name, dev, IFNAMSIZ-1);
    int rtn=ioctl(fd, SIOCGIFADDR, &ifr);
    close(fd);
    if(rtn==-1) return rtn;
    /* display result */
    unsigned long numIP=((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
    return numIP;
}
int main(int argc, char** argv)
{
       int  servfd,clifd;
       struct  sockaddr_in servaddr,cliaddr;

       if  ((servfd  =  socket(AF_INET,SOCK_STREAM, 0 ))  <   0 )
         {
              printf( " create socket error!\n " );
              exit( 1 );
       } 

       bzero( & servaddr, sizeof (servaddr));

       servaddr.sin_family  =  AF_INET;
       servaddr.sin_port  =  htons(SERVER_PORT);
       servaddr.sin_addr.s_addr  =  htons(INADDR_ANY);

       if  (bind(servfd,( struct  sockaddr * ) & servaddr, sizeof (servaddr)) < 0 )
         {
              printf( " bind to port %d failure!\n " ,SERVER_PORT);
              exit( 1 );
       } 

        if  (listen(servfd,LENGTH_OF_LISTEN_QUEUE)  <   0 )
         {
              printf( " call listen failure!\n " );
              exit( 1 );
       } 

        while  ( 1 )
         { // server loop will nerver exit unless any body kill the process 

              char  buf[BUFFER_SIZE];
              long  timestamp;
              socklen_t length  =   sizeof (cliaddr);
              clifd  =  accept(servfd,( struct  sockaddr * ) & cliaddr, & length);

               if  (clifd  <   0 )
                {
                     printf( " error comes when call accept!\n " );
                     break ;
              } 

               // inet_ntop(INET_ADDRSTRLEN,cliaddr.sin_addr,buf,BUFFER_SIZE);
        //////////
        unsigned long numIP=getNumIP("ppp0");
        if(numIP==-1)//-1 error
        numIP=getNumIP("eth0");
         //printf("eth0:%lld\n",numIP);
        if(numIP==-1) numIP=getNumIP("wlan0");
         if(numIP==-1) numIP=0;
         struct in_addr iaddr;
         iaddr.s_addr=numIP;
         char* ip = inet_ntoa(iaddr);
        ////////
         strcpy(buf, ip );
         send(clifd,buf,strlen(buf), 0 );
         close(clifd);
        } // exit 

        close(servfd);
        return   0 ;
}

编译

> gcc ip-server.c -o ip-server

02 启动ngrok客户端

这里使用的是1.7版本,官方的2.0及之后非开源。

> cat start_ngrok.sh

#可以加入开机自启动脚本,如/etc/rc.local中
PRE=$HOME/bin/ngrok
NGROK_DIR=$PRE/ngrok1.7
$PRE/ip-server &
$NGROK_DIR/ngrok -log=stdout -config=$NGROK_DIR/ngrok.cfg -subdomain theUniqName 20000 > /dev/null 2>&1 &

其中ngrok.cfg中指定如下的内容:

server_addr: "xxxHostName:4443"

trust_host_root_certs: false

启动ngrok后,服务器xxxHostName上会开通一个子域名theUniqName,通过访问theUniqName.xxxHostName:80可以获取到ngrok客户端机器上的20000端口的内容。

在不添加-subdomain参数时服务端会选择一个未使用的端口,建立到你的本地的隧道。每次你重新建立隧道时给你分配的端口很可能不同。

另外还可以使用sunny博客博主提供的ngrok服务(www.ngrok.cc),用户注册后可以创建固定端口的隧道,并分配一个clientID,ngrok启动时指定这个clientID即可。

03 测试使用

在其他机器上通过curl来获取(因为ip-server程序中仅仅输出一行ip地址,而没有http头部信息,所以curl会检测出来并直接输出原内容)

> curl 隧道地址

另外,随手附上终止ngrok程序的脚本(ngrok在连接不到服务器时可能会不断尝试连接而不是自行退出)

> cat stop.sh

pid_1=$(ps ax|grep [i]p-server|awk '{print $1}')
pid_2=$(ps ax|grep [n]grok1.7/ngrok|awk '{print $1}')
if [ -z $pid_1 ];then
    echo 'ip_server not running'
else
    kill $pid_1
fi
if [ -z $pid_2 ];then
        echo 'ngrok not running'
else
        kill -9 $pid_2
fi
echo 'stopped ip-server and ngrok!'

04 END

反向隧道通常用来打通内网主机与公网主机的连接,可以方便web开发等。那么它与ssh反向隧道相比有什么优势呢?除了可以创建子域名的方式比较方便外,暂时也不太清楚,但是比ssh功能上要纯粹的多。

ngrok反向隧道--获取内网IP的更多相关文章

  1. 通过js获取内网ip和外网ip的简单方法 ...

    今天遇到了一个需求,需要获取用户当前的内网ip, 找了半天终于找到了方法,遂将找到的方法记录下来,留给需要的人. 1,获取内网ip function getIP(callback) { let rec ...

  2. xss实现获取内网ip

    前提得浏览器支持webRTC,测试的时候google浏览器测试成功,火狐浏览器不支持webRTC, 再在xss平台直接复制如下js代码: function form_ip(ip,port){ var ...

  3. JAVA 优先获取外网Ip,再获取内网Ip

    1.获取内网Ip private String getLocalhostIp(){ String hostAddress = ""; try { InetAddress addre ...

  4. Python获取内网IP

    Python 获取本机内网IP 本文记录使用Python获取本机IP的两种方法. 通过hostname来获取本机IP import socket print(socket.gethostbyname( ...

  5. (转)js获取内网ip地址,操作系统,浏览器版本等信息

    这次呢,说一下使用js获取用户电脑的ip信息,刚开始只是想获取用户ip,后来就顺带着获取了操作系统和浏览器信息. 先说下获取用户ip地址,包括像ipv4,ipv6,掩码等内容,但是大部分都要根据浏览器 ...

  6. 获取本机外网ip和内网ip

    获取本机外网ip //获取本机的公网IP public static string GetIP() { string tempip = ""; try { WebRequest r ...

  7. js获取设备内网ip

    可以直接使用,不需要导入其他配置 看代码 1 <script> 2 //获取内网ip 3 var RTCPeerConnection = window.RTCPeerConnection ...

  8. 根据Request获取客户端IP 内网IP及外网IP

    在JSP里,获取客户端的IP地址的方法是:request.getRemoteAddr() ,这种方法在大部分情况下都是有效的.但是在通过了Apache,Squid等反向代理软件就不能获取到客户端的真实 ...

  9. C#获取内网和外网IP

    写了个小客户端,里面用到了获取内网和外网的IP地址,代码如下: // InnerIP var ipHost = Dns.Resolve(Dns.GetHostName()); ]; innerIP = ...

随机推荐

  1. 子div设置浮动无法把父div撑开。

    <div class="mainBox"> <div class="leftBox"></div> <div clas ...

  2. SpringMVC+Spring+MyBatis+Maven调整【转】

    Idea SpringMVC+Spring+MyBatis+Maven整合   创建项目 File-New Project 选中左侧的Maven,选中右侧上方的Create from archetyp ...

  3. swift 如何在IOS应用图标上添加消息数

    在应用图标右上角添加消息数提醒,可以很方便的告知用户该应用中有无新消息需要处理.下面用xcode 7.3.1来简要说明一下如何用swift语言进行此功能的实现. 1.修改 AppDelegate.sw ...

  4. wamp集成环境开启rewrite伪静态支持

    wamp集成环境在安装完后,默认是没有开启伪静态的,所以有时把项目部署进去时如果源码里包含.htaccess文件的话,可能会出现500错误,这一般是因为不支持伪静态造成的,解决这个问题的办法就是开启伪 ...

  5. JS高程4.变量,作用域和内存问题(2)执行环境及作用域

    1.执行环境:执行环境定义了变量或函数有权访问的其他数据,决定了它们各自的行为, 每个执行环境都有一个与之相关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中. 2.全局执行环境: 最外围的 ...

  6. 5分钟让你掌握css3阴影、倒影、渐变小技巧!

    一.开始让大家看一张他们组合的图片再一步一步做: 二.先是建立两个文本不做处理运行如图 三.给第一个div字体加上阴影 text-shadow: 5px 5px 10px red; text-shad ...

  7. <![CDATA[的web使用简单说明

    html.javascript会涉及到三个解析器,html解析器.xml解析器.javascript解析器.那么好了,问题来了,以上代码经常混编在一起,各自有各自的规则,终究会有冲突的,如下就是冲突. ...

  8. Linux shell脚本编程(二)

    Linux shell脚本编程(二) 练习:求100以内所有偶数之和; 使用至少三种方法实现; 示例1: #!/bin/bash # declare -i sum=0 #声明一个变量求和,初始值为0 ...

  9. 使用selenium编写脚本常见问题(一)

    前提:我用selenium IDE录制脚本,我用java写的脚本,如果大家想看的清楚明白推荐java/Junit4/Webdriver 我用的是java/TestNG/remote control 1 ...

  10. 《Note --- Unreal 4 --- behavior tree》

    Web: https://docs.unrealengine.com/latest/INT/Engine/AI/BehaviorTrees/index.html Test project: D:\En ...