Posts Tagged ‘Linux’

SSH 使用 — 如何从外网连接内网计算机

June 11th, 2016

SSH是我们经常使用的工具,但是因为现在组网方式非常复杂,导致跨越NAT非常难因应对,同一局域网下的SSH使用,我这里就不再赘述。我们来聊聊如何从外网连接内网的ssh-server。

首先我们可以选择偷懒的方式,设置主机别名,这样就不用每次都输入ssh user@remote -p port 了,我们可以在~/.ssh/config 里面追加以下内容:

Host lab
   HostName xxx.xxx.xxx.xxx
   User user
   Port port

保存之后,即可用 ssh lab 登入,如果还配置了公钥登入,那就连密码都不用输入了。

================

两台主机之间传输数据可以使用scp命令,它与ssh -p port 很类似,稍微的差别在与指定端口时用的是大写的 -P 而不是小写的。有了这些基础知识,下面我们聊聊如何从外网连接内网的ssh-server。为了实现这个功能,我们必须拥有一台公网主机,现在国内的vps非常便宜,阿里云或者腾讯云都可以。

假设现在我有一台处在公网的机器 bridge,这台机器拥有公网IP 。你在实验室也有一台机子lab,这台机子只能在实验室内部访问,但他可以访问公网,你希望能在任何地方都能访问这台机器。那么使用 ssh -R 可以轻松地做到这个事情。

lab$ ssh -R 10022:localhost:22 bridge
bridge$ ssh user@localhost -p 10022
lab$

只要上面这个过程成功了,就说明在你执行 ssh -R 10022:localhost:22 bridge(ssh -R 远端:本地 bridge,如果远端不添加0.0.0.0 就意味着只能bridge自己访问这个lab,如果添加了0.0.0.0就意味着可以其他机器可以通过bridge访问到)之后,你成功地将本地上的 22 端口反向转发到了 bridge 的 10022 端口。只要保持这个 ssh 不断,任何一台机器都可以首先连接到 bridge,然后通过 ssh user@localhost -p 10022 连回到 lab。

不过上面这么做并不稳健,如果因为网络波动导致 ssh -R 那个连接断了,那么从 bridge 就完全失去了到 lab 的控制。万幸的是,有一个叫做 autossh 的软件,可以自动的检测断线,并在断线的时候重连。在 Ubuntu 上你可以使用 sudo apt-get install autossh 来安装。

lab$ autossh -NfR 10022:localhost:22 bridge

上面这句话里面 -N 表示非不执行命令,只做端口转发;-f 表示在后台运行,-R 10022:localhost:22 就是把本地的22端口转发到远程的10022端口。我们也可以设置为开机时运行:在 /etc/rc.local 里面 exit 0 这句话之前加上

su - user -c autossh -NfR 10022:localhost:22 bridge

其中 user 是用户名。需要注意的是,开机时运行 autossh 需要配置公钥登入。

临时创建网站供查看

比如我在本地跑了一个网站,我想临时把我的网站发给朋友看看。在本地运行 python -m SimpleHTTPServer 即可在本地的8000端口启动一个网站,你可以在浏览器中通过 http://localhost:8000/ 看到。下面我们想让远方的朋友看到这个网站。

local$ ssh -NR 0.0.0.0:18000:localhost:8000 bridge

远方的朋友即可通过 http://bridge:18000/ 看到了。注意到这里和上面的命令有一个小小的不同,就是多了 0.0.0.0,这告诉 ssh,要把18000端口绑定在远端的所有IP上。如果像之前那样省略的话,缺省值是只绑定在 localhost,也就是只有在 jumpbox 本机才可以访问,而其他人都不能访问。

临时代理创建

比方说在本地的127.0.0.1:1080运行了HTTP代理服务,现在我想让另一台机子 remote 也能够使用这个HTTP代理。

local$ ssh -NR 11080:localhost:1080 remote
local$ ssh remote
remote$ export http_proxy=http://127.0.0.1:11080/
remote$ export https_proxy=http://127.0.0.1:11080/
remote$ curl http://ifconfig.co

用作 SOCKS5 代理

要是想要在家访问公司内网的一些网站,但是公司又没有提供进入内网的VPN,那怎么办呢?通过 ssh -D 可以在本地建立起一个 SOCKS5 代理:local$ ssh -ND 1080 workplace

 

【1】 ssh manual

用 qemu 来调试 Kernel

January 13th, 2016

引言

  • kgdb 方式

kgdb 的方式需要两台电脑,一台是宿主机,另一台是开发机,在开发机上编译打好补丁的内核代码,然后拷贝到宿主机上运行。注:目前 kgdb 支持的版本比较低了,好像在 2.6.19 左右,如果需要调试高版本的内核比较麻烦,而且需要通过串口方式调试,必须需要两台电脑,安装配置也比较麻烦,不过该方式调试比较准确,不会因为优化问题而无法查看变量。

  • uml 方式

uml ( user mode linux kernel ),是一种在用户态调试内核的方式,该调试方式在 2.6 就进入主线了。在源码包中,进入 arch/um 文件夹,就能看到该方式。该方式存在问题是无法调试硬件相关,如果你只需要调试调度、调试文件系统等,那么你可以使用,该方式比较简单,可自行百度。

  • printk 方式

这个方式也就是说在想调试的地方打印调试信息,需要反复的编译,反复增减调试信息是比较繁琐的一个地方。

qemu 调试内核

建议不要从源中拉版本安装,因为可能源中的版本太低,这个问题困扰了我很久,如果版本太低的话,导致文件系统加载的时候会出现故障,会出现以下提示: cannot load filesystem…
首先从 http://wiki.qemu.org/Download 下载最新版的 qemu 源码,我下的是: qemu-2.4.0.tar.bz2 版本,按照下列方式安装就可以了。

$tar -xvf qemu-2.4.0.tar.bz2
$cd qemu-2.4.0
$./configuration
$make install

我就默认安装的,并没有修改安装地址,如果有需要的话请自行定制。

源码配置

$tar -xvf linux-source**
$cd linux-source**
$vim Makefile

编辑 Makefile 文件,将所有 -O2 优化方式修改为 -O0 ,这样可以部分减少查看变量时的 optimized 提示(也就是说变量被编译器优化了,放到寄存器了,无法打印)。

$make menuconfig

接下来修改内核调试选项

kernel将上述选项都选中。 然后就是 make bzImage。这样就会在 arch/i386/boot/ 下生成 bzImage 文件,内核部分就结束了。

文件系统制作

这块我主要是借鉴了网上的一个帖子: http://blog.csdn.net/wesleyluo/article/details/7943087 该帖子详细讲解了如何制作根文件系统,如果你遇到跟我一样的问题,就是制作的根文件系统无法使用的话,也就是提示找不到 filesystem ,那么请你转到 buildroot 工具,制作根文件系统。

gdb 调试

接下来就是调试你的内核啦,不要太激动啊,因为你还是有可能遇到文件系统无法加载啊, qemu 调试报错啊等等问题。
制作一个脚本来快速启动 qemu 调试

#!/bin/bash
qemu-system-i386 -kernel linux_path/arch/i386/bzImage -hda rootfs.ext2 -append "root=/dev/sda rw" -s -S

关于这个 shell 可能有些疑惑, -kernel 就是使用后边的 bzImage 作为内核镜像。 -hda 我的理解就是作为硬盘引导项, -s 是 gdb 调试的快捷方式相当于 -gdb tcp::1234, 打开一个 gdbserver 在 TCP 端口 1234.-S 选项是启动之后就暂停,等待用户命令。

然后新打开一个终端,输入

$gdb linux_path/vmlinux

等待 gdb 把符号加载完成,加载提示:

$Reading symbols from ..../vmlinux ...done

这样就加载完成了,接下来输入:

$target remote localhost:1234
$b start_kernel
$c

就开始运行然后停在了 start_kernel , OK 大功告成了。

参考:

http://blog.csdn.net/wesleyluo/article/details/7943087

copy() 与mmap()使用

September 18th, 2014

之前学了Linux内存管理,知道了内存的虚实地址转换,Linux内存映射这一块有很多应用可以极大的提高文件读写速度,其中提高的方式就是使用mmap的方式,而不是read write的方式。

我们要知道read write的方式需要事先分配一个buffer缓冲区。但是缓冲区非常有讲究,如果分配的过小就意味着os频繁的分配释放,效率比较低。如果buffer分配过大,又会很浪费内存。这也就是mmap()的优势,不仅没有浪费内存,而且速度相当的快。 » Read more: copy() 与mmap()使用

Linux进程的虚拟地址空间(笔记)

September 16th, 2014

进程虚拟空间是个32或64位的“平坦”(独立的连续区间)地址空间(空间的具体大小取决于体系结构)。

为了方便管理,虚拟空间被划分为许多大小可变的(但必须是4096的倍数)内存区域,如果要查看某个进程占用的内存区域,可以使用命令cat /proc/<pid>/maps获得.pid是进程的id号

» Read more: Linux进程的虚拟地址空间(笔记)

list 实际应用

September 3rd, 2014

一个head头包含两个不同的链表,每个链表会有交叉,在高级的场景下使用,例如多cgroup 与多css_set关系!

#include "list.h"
#define MAX_LEN 256

struct task_struct{
	list_head priority_list;
	list_head timer_list;
	int priority;
	int timeout;
	char name[MAX_LEN];
};

struct task_struct* init_task(int priority,int timeout,char *name,int str_len)
{
	struct task_struct *T = (struct task_struct * )malloc(sizeof(struct task_struct));
	T->priority = priority;
	T->timeout = timeout;
	strncpy(T->name,name,str_len);
	return T;

}

struct list_head* p_add_task(list_head *head,struct task_struct *task)
{
	struct list_head *pos;
	struct task_struct *p;
	if(list_empty(head))
	{
		list_add(&task->priority_list,head);
		return head;
	}
	list_for_each(pos,head)//big->little
	{
		p=list_entry(pos, struct task_struct, priority_list);
		if( p->priority  < task->priority)//insert node > current node
		{
			list_add(&task->priority_list,pos->prev);
			return head;
		}
	}
	list_add_tail(&task->priority_list,head);
	return head;
}
struct list_head* t_add_task(list_head *head,struct task_struct *task)
{
	struct list_head *pos;
	struct task_struct *p;
	if(list_empty(head))
	{
		list_add(&task->timer_list,head);
		return head;
	}
	list_for_each(pos,head)//little ->big
	{
		p=list_entry(pos, struct task_struct, timer_list);
		if( p->timeout  > task->timeout)//insert node > current node
		{
			list_add(&task->timer_list,pos->prev);
			return head;
		}
	}
	list_add_tail(&task->timer_list,head);
	return head;
}

struct task_struct* p_del_task(list_head *head,struct task_struct *task)
{
	list_del(&task->priority_list);
	return task;
}
struct task_struct* t_del_task(list_head *head,struct task_struct *task)
{
	list_del(&task->timer_list);
	return task;
}

int Print_priority_list(struct task_struct *task)
{
	struct list_head *pos;
	struct task_struct *p;
	printf("P\tT\tN\n");
	list_for_each(pos,&task->priority_list)
	{
		p=list_entry(pos, struct task_struct, priority_list);
		printf("%d\t%d\t%s\n", p->priority,p->timeout,p->name);
	}
}

int Print_timer_list(struct task_struct *task)
{
	struct list_head *pos;
	struct task_struct *p;
	printf("P\tT\tN\n");
	list_for_each(pos,&task->timer_list)
	{
		p=list_entry(pos, struct task_struct, timer_list);
		printf("%d\t%d\t%s\n", p->priority,p->timeout,p->name);
	}
}

int main()
{
	struct task_struct head={
		.priority_list = LIST_HEAD_INIT(head.priority_list),
		.timer_list = LIST_HEAD_INIT(head.timer_list),
 		.priority = -1,
		.timeout = -1,
		.name = NULL
	};

	char temp1[MAX_LEN] = "T1";
	char temp2[MAX_LEN] = "T2";
	char temp3[MAX_LEN] = "T3";
	struct task_struct *T1,*T2,*T3;
	T1 = init_task(1,10,temp1,strlen(temp1));
	T2 = init_task(3,5,temp2,strlen(temp2));
	T3 = init_task(2,2,temp3,strlen(temp3));
	
	p_add_task(&head.priority_list,T2);
	p_add_task(&head.priority_list,T3);
	p_add_task(&head.priority_list,T1);

	t_add_task(&head.timer_list,T3);
	t_add_task(&head.timer_list,T2);	
	t_add_task(&head.timer_list,T1);
	


	Print_priority_list(&head);
	printf("\n");
	Print_timer_list(&head);

	p_del_task(&head.priority_list,T2);
	p_del_task(&head.priority_list,T3);
	p_del_task(&head.priority_list,T1);

	t_del_task(&head.timer_list,T3);
	t_del_task(&head.timer_list,T2);
	t_del_task(&head.timer_list,T1);
	return 0;
}

http://www.lizhaozhong.info/archives/951