Living a Simple Life is a Happy Life

有饭吃,自由自在,就非常开心

Open vSwitch Bridge and NetworkNameSpace Command Cheat

| Comments

  • 启动

      service openvswitch start
    
  • 创建网桥

      ovs-vsctl add-br br0
      ifconfig br0 up
    
  • 显示所有网桥

      ovs-vsctl show
    
  • 删除网桥

      ovs-vsctl del-br br0
    
  • 增加端口

      ovs-vsctl add-port br0 eth0
    
  • 设置网卡为none

      dhclient br0
    
  • 用 Namespace 模拟两台虚拟机网络

      p netns add network1
      ip netns add network2
    
  • 创建两个虚拟网卡并加入网桥

      ovs-vsctl add-port br0 vport1 -- set interface vport1 type=internal
      ovs-vsctl add-port br0 vport2 -- set interface vport2 type=internal
      tunctl -p -t vport1
      tunctl -p -t vport2
    
  • 两个虚拟网卡接入namespace

      ip link set vport1 netns network1
      ip link set vport2 netns network2
    
  • 设置虚拟网卡的IP

      ip netns exec network1 ifconfig vport1 192.168.0.1/24 up
      ip netns exec network2 ifconfig vport2 192.168.0.2/24 up
    
  • 两个namsespace PING

      ip netns exec network1 ping 192.168.0.2
      ip netns exec network2 tcpdump -i vport2
    
  • 两个namsespace NC传输

      ip netns exec network2 nc -l 1234
      ip netns exec network2 tcpdump -i vport2
      ip netns exec network1 nc 192.168.0.2 1234
    
  • 显示vlan信息

      ovs-appctl fdb/show br0
    
  • 显示openflow信息

      ovs-ofctl show br0
    
  • 显示流表信息

      ovs-ofctl dump-flows br0
    
  • 显示网桥详细信息

      ovs-vsctl list Bridge
    
  • 显示端口详细信息

      ovs-vsctl list Port
    
  • 显示接口详细信息

      ovs-vsctl list Interface
    

Webtorrent Redefine CDN?

| Comments

最近发现了一个开源的JS东东,webtorrent:

https://github.com/feross/webtorrent

用webRTC实现了一个浏览器端的bt客户端。

这个点子我还在几年前试过呢?当时想用socketio来做,但各种限制,当时webRTC还是个小众,没有被浏览器主流实现。

试了一下,效果还差强人意。

脑洞开一下,话说这会不会是快播们的春天来了。

严肃一点再想想,是不是CDN提供商们可以利用它分担压力,提升速度,走上人生巅峰….

留待后续观察。

有关于云计算及SDN

| Comments

云计算和SDN这两个名词总是被许多人挂在嘴边,他们给人的印象就是在Qcon大会上念PPT的一拨人。

作为一个实用党,下面我企图用一问一答的形式来瞎扯一番:

Q: 我是个中小企业,用openstack好还是vCenter虚拟化好?

A: 如果你能招到一个合适的人(注意,这个概率我觉得是万分之一),你可以上openstack。

如果你有足够的M,上vCenter。

如果你什么都没有,上阿里云 (我是认真的,不要黑我)。

总之,随着网络带宽提升,我觉得中小企业自建运维越来越不划算。云化是趋势。

Q: 容器技术会颠覆现有的虚拟化技术吗?

A: 不会,容器技术只是补充,全虚拟化有自己不可替代优势。

Q: SDN会替代现在的网络设备吗?

A: 可能会替代大部分网络交换设备。但是就现在的情况来看,各种SDN解决方案的性能还没有和硬件处在同一档次上。

所以将来在大型数据中心,肯定是软硬结合和持续很长一段时间。

在很多中小云平台,大部分硬件设备已经在迁移过程中了。

Q: SDN真的比传统设备灵活吗?简单吗?方便吗?

A: 首先要看方案,和传统网络一样,不同的场景实施方案也不一样。一千个现场会有一千个云实施方案。

SDN有灵活性的优势。

SDN某种意义上说,比传统网络还要复杂。

首先,真实世界的网络就是复杂的。任何隐藏复杂性的尝试都会增加复杂性。所以SDN不能拯救世界,传统硬件设备面临的复杂问题,它也一样要面对。

SDN的优势就是灵活,并非简单。

Q: 未来从事中小企业云的部署咨询工作,有戏吗?

A: 我觉得单纯做部署顾问之类的没戏。做openstack的番茄花园有戏。

如果将来GPU虚拟化成熟的话,做打金工作室的openstack 包装发行版相当有戏。

Q: SDN领域有何机会?

A: 也许SDN领域将来不会再孕育思科华为那样的大玩家,但是一定会有许多独角兽出来。

目前看到的看准一个痛点,比如苏州盛科那样,软硬结合,做芯片,交换机白牌供应商,很有机会。

或者瞅准市场空白,比如说做性能比较低的软tap,我觉得很有戏。

Is Craig Wright Real Satoshi Nakamoto?

| Comments

Craig Wright 又在声明他是”中本聪”了.

“中本聪”给出的签名是:

MEUCIQDBKn1Uly8m0UyzETObUSL4wYdBfd4ejvtoQfVcNCIK4AIgZmMsXNQWHvo6KDd2Tu6euEl13VTC3ihl6XUlhcU+fM4=

我们先对信息串进行base64解码,再转换成hex是:

3045022100c12a7d54972f26d14cb311339b5122f8c187417dde1e8efb6841f55c34220ae0022066632c5cd4161efa3a2837764eee9eb84975dd54c2de2865e9752585c53e7cce

很遗憾,我们可以在交易ID:

828ef3b079f9c23829c56fe86e85b4a69d9e06e5b54ea597eef5fb3ffef509fe

中找出这个签名。可通过:

https://blockchain.info/tx/828ef3b079f9c23829c56fe86e85b4a69d9e06e5b54ea597eef5fb3ffef509fe?format=hex

找到十六进制串的交易内容

然后搜索一下hex样子的签名,遗憾地发现,能在这个交易中找到这个签名。

但是令人疑惑的是GAVIN ANDRESEN为这位”中本聪”背书:

http://gavinandresen.ninja/satoshi

Gavin不是一个无的放矢的人,他肯定是见到了更多的证据.

但是Craig Wright 又不对其他给定的文本签名来证明自己是中本聪,反而老是用这种神神遭遭的签名来忽悠大家……

卫平布莱恩特老师说,这球有意思啊…….

最后, 如果Craig Wright这个人是为了某种目的假冒的话,只能说他真是煞费苦心啊. 我不认为一个签名造假如此low的家伙能有这种能力.

但是他的一些行为如果算恶作剧的话,又未免太高段了,参考这里:

https://www.zhihu.com/question/22199390/answer/76083139

不负责任的YY一下, Craig Wright肯定和真正的中本聪有某种关系,他在bitcoin诞生之初就了解参与过.

他不是bitcoin的发明者,因为种种迹象表明,他的技术能力实在太low了.

真正的中本聪可能是他的那个朋友:David Kleiman, 但他已经死了.

呵呵, 绝佳的侦探小说体裁啊.

Git Cheat 2

| Comments

整理一下经常忘记的Git命令 (版本v2)

http://www.ruanyifeng.com/blog/2015/12/git-cheat-sheet.html?utm_source=tool.lu

新建代码库

# 在当前目录新建一个Git代码库
git init

# 新建一个目录,将其初始化为Git代码库
git init [project-name]

# 下载一个项目和它的整个代码历史
git clone [url]

配置

Git的设置文件为.gitconfig,它可以在用户主目录下(全局配置),也可以在项目目录下(项目配置)。

# 显示当前的Git配置
git config --list

# 编辑Git配置文件
git config -e [--global]

# 设置提交代码时的用户信息
git config [--global] user.name "[name]"
git config [--global] user.email "[email address]"

增加/删除文件

# 添加指定文件到暂存区
git add [file1] [file2] ...

# 添加指定目录到暂存区,包括子目录
git add [dir]

# 添加当前目录的所有文件到暂存区
git add .

# 删除工作区文件,并且将这次删除放入暂存区
git rm [file1] [file2] ...

# 停止追踪指定文件,但该文件会保留在工作区
git rm --cached [file]

# 改名文件,并且将这个改名放入暂存区
git mv [file-original] [file-renamed]

代码提交

# 提交暂存区到仓库区
git commit -m [message]

# 提交暂存区的指定文件到仓库区
git commit [file1] [file2] ... -m [message]

# 提交工作区自上次commit之后的变化,直接到仓库区
git commit -a

# 提交时显示所有diff信息
git commit -v

# 使用一次新的commit,替代上一次提交
# 如果代码没有任何新变化,则用来改写上一次commit的提交信息
git commit --amend -m [message]

# 重做上一次commit,并包括指定文件的新变化
git commit --amend [file1] [file2] ...

分支

# 列出所有本地分支
git branch

# 克隆并在本地建立所有分支

for branch in `git branch -a | grep remotes | grep -v HEAD | grep -v master`; do
    git branch --track ${branch##*/} $branch
done

# 列出所有远程分支
git branch -r

# 列出所有本地分支和远程分支
git branch -a

# 新建一个分支,但依然停留在当前分支
git branch [branch-name]

# 新建一个分支,并切换到该分支
git checkout -b [branch]

# 新建一个分支,指向指定commit
git branch [branch] [commit]

# 新建一个分支,与指定的远程分支建立追踪关系
git branch --track [branch] [remote-branch]

# 切换到指定分支,并更新工作区
git checkout [branch-name]

# 建立追踪关系,在现有分支与指定的远程分支之间
git branch --set-upstream [branch] [remote-branch]

# 合并指定分支到当前分支
git merge [branch]

# 选择一个commit,合并进当前分支
git cherry-pick [commit]

# 删除分支
git branch -d [branch-name]

# 删除远程分支
git push origin --delete [branch-name]

# 删除不存在对应远程分支的本地分支
# 假设这样一种情况:
#    1. 我创建了本地分支b1并push到远程分支 origin/b1;
#    2. 其他人在本地使用fetch或pull创建了本地的b1分支;
#    3. 我删除了 origin/b1 远程分支;
#    4. 其他人再次执行fetch或者pull并不会删除这个他们本地的 b1 分支,运行 git branch -a 也不能看出这个branch被删除了,如何处理?

# 在fetch之后删除掉没有与远程分支对应的本地分支
git fetch -p                                                        //

# 重命名远程分支
# 在git中重命名远程分支,其实就是先删除远程分支,然后重命名本地分支,再重新提交一个远程分支
git push --delete origin devel
git branch -m devel develop
git push origin develop

# 合并branchB到branchA
# 前提是你需要的是fast-forward
# 合并本地的branchB到本地的branchA
git fetch . branchB:branchA

# 合并远端的branchB到本地的branchA
git fetch origin branchB:branchA


# 合并branch上的指定文件
# branches/A 上修改了一个文件A.h,新增了一个文件B.h,删除了一个文件C.h。
# 首先切换到master分支
git checkout master
# 不切换branch,把RemLanbranches/A上的A.h更新到当前分支
git checkout -p branches/A A.h
# 去掉-p参数,新增该B.h文件
git checkout branches/A B.h
# 删除文件目前还没找到其他办法,但效果是一样的
rm C.h

标签

# 列出所有tag
git tag

# 新建一个tag在当前commit
git tag [tag]

# 新建一个tag在指定commit
git tag [tag] [commit]

# 删除本地tag
git tag -d [tag]

# 删除远程tag
git push origin :refs/tags/[tagName]

# 查看tag信息
git show [tag]

# 提交指定tag
git push [remote] [tag]

# 提交所有tag
git push [remote] --tags

# 新建一个分支,指向某个tag
git checkout -b [branch] [tag]

查看信息

# 显示有变更的文件
git status

# 显示当前分支的版本历史
git log

# 显示commit历史,以及每次commit发生变更的文件
git log --stat

# 显示某个commit之后的所有变动,每个commit占据一行
git log [tag] HEAD --pretty=format:%s

# 显示某个commit之后的所有变动,其"提交说明"必须符合搜索条件
git log [tag] HEAD --grep feature

# 显示某个文件的版本历史,包括文件改名
git log --follow [file]
git whatchanged [file]

# 显示指定文件相关的每一次diff
git log -p [file]

# 显示指定文件是什么人在什么时间修改过
git blame [file]

# 显示暂存区和工作区的差异
git diff

# 显示暂存区和上一个commit的差异
git diff --cached [file]

# 显示工作区与当前分支最新commit之间的差异
git diff HEAD

# 显示两次提交之间的差异
git diff [first-branch]...[second-branch]

# 显示某次提交的元数据和内容变化
git show [commit]

# 显示某次提交发生变化的文件
git show --name-only [commit]

# 显示某次提交时,某个文件的内容
git show [commit]:[filename]

# 显示当前分支的最近几次提交
git reflog

远程同步

# 下载远程仓库的所有变动
$ git fetch [remote]

# 显示所有远程仓库
$ git remote -v

# 显示某个远程仓库的信息
$ git remote show [remote]

# 增加一个新的远程仓库,并命名
$ git remote add [shortname] [url]

# 取回远程仓库的变化,并与本地分支合并
$ git pull [remote] [branch]

# 上传本地指定分支到远程仓库
$ git push [remote] [branch]

# 强行推送当前分支到远程仓库,即使有冲突
$ git push [remote] --force

# 推送所有分支到远程仓库
$ git push [remote] --all

撤销

# 恢复暂存区的指定文件到工作区
git checkout [file]

# 恢复某个commit的指定文件到暂存区和工作区
git checkout [commit] [file]

# 恢复暂存区的所有文件到工作区
git checkout .

# 重置暂存区的指定文件,与上一次commit保持一致,但工作区不变
git reset [file]

# 重置暂存区与工作区,与上一次commit保持一致
git reset --hard

# 重置当前分支的指针为指定commit,同时重置暂存区,但工作区不变
git reset [commit]

# 重置当前分支的HEAD为指定commit,同时重置暂存区和工作区,与指定commit一致
git reset --hard [commit]

# 重置当前HEAD为指定commit,但保持暂存区和工作区不变
git reset --keep [commit]

# 新建一个commit,用来撤销指定commit
# 后者的所有变化都将被前者抵消,并且应用到当前分支
git revert [commit]

remote 同步

# 查看当前远程版本库
git remote -v

#添加原始版本库
git remote add cocos2d-x git://github.com/cocos2d/cocos2d-x.git

#获取原始版本库的更新
git fetch cocos2d-x

# 合并原始版本库的代码到当前版本库中,合并前确保当前分支是master
git merge cocos2d-x/master

分支的衍合

http://git-scm.com/docs/git-rebase

diff

# 只显示两个分支间的差异,如果你想找出‘master’,‘test’的共有 父分支和'test'分支之间的差异,你用3个‘.'来取代前面的两个'.' 。
git diff master..test

# 显示你当前的索引和上次提交间的差异;这些内容在不带"-a"参数运行 "git commit"命令时就会被提交。
git diff --cached

# 显示你工作目录与上次提交时之间的所有差别,这条命令所显示的 内容都会在执行"git commit -a"命令时被提交。
git diff HEAD

# 如果你要查看当前的工作目录与另外一个分支的差别,你可以用下面的命令执行:
#这会显示你当前工作目录与另外一个叫'test'分支的差别。你也以加上路径限定符,来只 比较某一个文件或目录。
git diff test

# 显示你当前工作目录下的lib目录与上次提交之间的差别(或者更准确的 说是在当前分支)。
git diff HEAD -- ./lib

# 如果不是查看每个文件的详细差别,而是统计一下有哪些文件被改动,有多少行被改 动,就可以使用‘--stat' 参数。
git diff --stat

# 显示两次更改之间所有的文件名
git diff-tree -r --no-commit-id --name-only --diff-filter=ACMRTD HEAD HEAD^

# diff两个分支
git diff master branch/1.1 --

其他

# 生成一个可供发布的压缩包
git archive

# 临时保存/恢复现在的状态
git stash
git stash pop

# svn log -v 类似效果
git log --name-status

Migrate Centos7 From Centos6

| Comments

工作环境切换到Centos7 半年有余,epel仓库里的软件版本比el6更新了不少,非常方便。

另外systemd的引入让很多程序,尤其是开机启动上,速度提升了不少。

总体来说,很多细节让你感觉很舒服,值得大家尽快切换到这个版本上了。

下面记一下从Centos6迁移到Centos7上 常见的Question:

Q: 为什么引入systemd 代替 SysV init,我就是习惯原来的 /etc/init.d/xxxx 的方法?

A: 在我看来,有两点:

  1. 快。 真的是快,嗖嗖的快

  2. 日志。 终于能取代syslog了,我对syslog素无好感,配置复杂,level巨多,还不好排障。

参考资料:

http://www.ibm.com/developerworks/cn/linux/1407_liuming_init3/

https://wiki.archlinux.org/index.php/Systemd

Q: 为什么网卡名字这么奇怪,我要原来的简单明了的办法!!!

A: 呃,好吧,我觉得虽然有一堆理由,但是网卡名字这个改变可能真的是没有产品经理的弊端。你想回到从前,很简单:

  • 在 grub 加入 net.ifnames=0 and biosdevname=0 作为内核参数

  • 在 /etc/sysconfig/network-scripts/ 内把你的网络卡配置文件换名为 ifcfg-ethX

  • 假若你拥有多个界面并希望控制每个设备的名称,不想由内核作主,你似乎有必要通过 /etc/udev/rules.d/60-net.rules 盖过 /usr/lib/udev/rules.d/60-net.rules。

Q: grub.cfg 文件生成怎么这个奇怪,还要先配置 /etc/default/grub,再用命令生成一遍?我要直接改!!

A: 醒醒吧,我对这个改动双手赞成,至少她解决了centos6上一直被人诟病的efi问题。

Q: 嗯,我想问,ifconfig和 netstat哪里去了?

A: 额,套用官方原话回答吧:

ifconfig 及 netstat 工具程序在 CentOS 5 及 6 的应用手册内被置标为降级已接近十年,而 Redhat 决定在 CentOS 7 不会缺省安装 net-utils 组件。取而代之的工具是 ss 和 ip 。假如你真的、真的很需要 ifconfig 和 netstat,你可执行 yum install net-utils。

更多请参考:

https://wiki.centos.org/zh/FAQ/CentOS7#head-d04a9f331b47791774aefd7c11371934e7350ab3

Send Large Packet by Dpdk Pktgen

| Comments

场景

测试qinq 发包,但是tcpreplay是没法带vlan tag的。所以需要用pktgen发送qinq包。

问题

qinq双层vlan tag,有些包大小超过了1518字节,pktgen不支持。

解决方案

修改 dpdk-2.1.0/x86_64-native-linuxapp-gcc/include/rte_ether.h:

#define ETHER_MAX_LEN 1522

重新编译DPDK,Pktgen,重新加载DPDK驱动

资料

  • DPDK2.1.0:

http://dpdk.org/browse/dpdk/snapshot/dpdk-2.1.0.tar.gz

  • Pktgen2.9.5:

http://dpdk.org/browse/apps/pktgen-dpdk/snapshot/pktgen-dpdk-pktgen-2.9.5.tar.gz

Capture QinQ Large Packets

| Comments

最近遇到一个QinQ的问题,总结一下。

对QinQ协议的交换机做Span,tcpdump抓包后发现,有一些包大小为1522字节,这些包都被网卡丢掉了。仔细排查后发现,网卡对于>1518的包,统一丢掉处理了。

简单的解决办法,就是将网卡的mtu增大,设置为1508或者直接1600,就OK了。

事情虽小,但还是有不少知识点的,归纳一下:

QinQ

简介

IEEE 802.1ad或称为QinQ、vlan stacking。是一种以802.1Q为基础衍生出来的通讯协定。

QinQ报文有固定的格式,就是在802.1Q的标签之上再打一层802.1Q标签,QinQ报文比正常的802.1Q报文多4个字节。这4个字节用作外层标签,即运营商网络的公网VLAN Tag。原802.1Q的Tag用作内层标签,即私网VLAN Tag。

可以参考这张图:

https://zh.wikipedia.org/wiki/IEEE802.1ad#/media/File:TCPIP802.1ad_DoubleTag.svg

QinQ的出现,扩充了原始的vlan个数,由4094 -> 4094*4094。

QinQ的作用,在大规模组网时,或者建立Paas云时,可以允许不同的租户设置相同的vlan id。

并不是所有的交换机都支持QinQ的,QinQ只是一个草案,需要交换机厂商的支持。

下面从wiki上摘抄一个典型例子:

Acme及XYZ分别在Seattle及Tacoma有一间分公司,并借由SP的L2 VPN网络连线,而他们的子公司都使用相同的LAN。 换句话说,我们可以假设,Acme使用VLAN 100-200并透过SP连结两间子公司的网络;XYZ也使用VLAN 100-200并使用SP的网络连结子公司。

而对SP而言,则必须想办法区隔Acme及XYZ的资料,使其有办法通过SP的网络并分别送至各自的子公司。

解决办法就是,使用VLAN STACKING来区隔Acme及XYZ的资料。

当Acme送出资料时,SP使用QinQ并给予该资料一个独特的SPVID 1001,使其能通过SP的网络并流向另外一间子公司,当到达子公司则移除该SPVID,该资料便能依照原始的VLAN ID进行传送。而XYZ送出资料时,SP则使用SPVID 1002来区隔。

包长

QinQ比正常的报文多了4个字节,所以QinQ报文,在链路层,最大包长到了1522个字节。

标准的Ethernet V2中,IP报文最大不超过1500字节,加上DA+SA+TYPE+DATA+PAD, 链路层的以太网帧最小为60字节,最大为1514字节,如果是802.1q,带有vlan tag,会有1518字节。

QinQ的最大包长明显超出了,在大多数网卡驱动中,默认配置下,这种包是会被丢弃掉的。好在交换机会自动处理这种情况,确保包最终到我们的网卡时,是符合Ethernet V2的。

但是直接对交换机端口做Span,网卡便傻掉了。

阅读linux tg3驱动源码发现,丢弃此类包的判断是很简单的:

10188         /* MTU + ethernet header + FCS + optional VLAN tag */
10189         tw32(MAC_RX_MTU_SIZE,
10190              tp->dev->mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN);
10191

http://lxr.free-electrons.com/source/drivers/net/ethernet/broadcom/tg3.c#L88

所以只要把网卡的mtu改改大就可以了:

ifconfig ethx mtu 1600 up

再说说以太网帧的大小

根据rfc894的说明,以太网封装IP数据包的最大长度是1500字节,也就是说以太网最大帧长应该是以太网首部加上1500,再加上7字节的前导同步码和1字节的帧开始定界符,具体就是:7字节前导同步码 + 1字节帧开始定界符 + 6字节的目的MAC + 6字节的源MAC + 2字节的帧类型 + 1500 + 4字节的FCS。

按照上述,最大帧应该是1526字节,但是实际上我们抓包得到的最大帧是1514字节,为什么不是1526字节呢?

原因是当数据帧到达网卡时,在物理层上网卡要先去掉前导同步码和帧开始定界符,然后对帧进行CRC检验,如果帧校验和出错,就丢弃此帧。如果校验和正确,就判断帧的目的硬件地址是否符合自己的接收条件(目的地址是自己的物理硬件地址、广播地址、可接收的多播硬件地址等),如果符合,就将帧交给“设备驱动程序”做进一步处理。这时我们抓包的软件才能抓到数据,因此,抓包软件抓到的是去掉前导同步码、帧开始分界符、FCS之外的数据,其最大值是6 + 6 + 2 + 1500 = 1514。

以太网规定,以太网帧数据域部分最小为46字节,也就是以太网帧最小是 6 + 6 + 2 + 46 + 4 = 64。除去4个字节的FCS,因此,抓包时就是60字节。当数据字段的长度小于46字节时,MAC子层就会在数据字段的后面填充以满足数据帧长不小于64 字节。由于填充数据是由MAC子层负责,也就是设备驱动程序。不同的抓包程序和设备驱动程序所处的优先层次可能不同,抓包程序的优先级可能比设备驱动程序更高,也就是说,我们的抓包程序可能在设备驱动程序还没有填充不到64字节帧的时候,已经捕获了数据。因此不同的抓包工具抓到的数据帧的大小可能不同。(比如,wireshark抓到的可能没有填充数据段,而sniffer抓到的就有填充数据段)

那么以太网帧格式一共有多少种呢

历史上以太网帧格式有五种:

1 Ethernet V1

这是最原始的一种格式,是由Xerox PARC提出的3Mbps CSMA/CD以太网标准的封装格式,后来在1980年由DEC,Intel和Xerox标准化形成Ethernet V1标准

2 Ethernet II即DIX 2.0

Xerox与DEC、Intel在1982年制定的以太网标准帧格式。Cisco名称为:ARPA。

这是最常见的一种以太网帧格式,也是今天以太网的事实标准,由DEC,Intel和Xerox在1982年公布其标准,主要更改了Ethernet V1的电气特性和物理接口,在帧格式上并无变化;

Ethernet V2出现后迅速取代Ethernet V1成为以太网事实标准; Ethernet V2帧头结构为6bytes的源地址+6bytes的目标地址+2Bytes的协议类型字段+数据。 常见协议类型如下:

  • 0800 IP
  • 0806 ARP
  • 0835 RARP
  • 8137 Novell IPX
  • 809b Apple Talk

如果协议类型字段取值为0000-05dc(十进制的0-1500),则该帧就不是Ethernet V2(ARPA)类型了,而是下面讲到的三种802.3帧类型之一;Ethernet可以支持TCP/IP,Novell IPX/SPX,Apple Talk Phase I等协议;RFC 894定义了IP报文在Ethernet V2上的封装格式;

下面给一张图,就对这种帧格式一目了然了:

+-----+-----+------+-----+-------+------+------+-------+
|PR   |SD   |DA    |SA   |TYPE   |DATA  |PAD   |FCS    |
+-----+-----+------+-----+-------+------+------+-------+
|56b  |8b   |48b   |48b  |16b    |<=1500|不够   | 32b   |
|     |     |      |     |       |      |填充   |       |
+-----+-----+------+-----+-------+------+------+-------+

在每种格式的以太网帧的开始处都有64比特(8字节)的前导字符,如图所示。其中,前7个字节称为前同步码(Preamble),内容是16进制数0xAA,最后1字节为帧起始标志符0xAB,它标识着以太网帧的开始。前导字符的作用是使接收节点进行同步并做好接收数据帧的准备。

  • PR:同步位,用于收发双方的时钟同步,同时也指明了传输的速率(10M和100M的时钟频率不一样,所以100M网卡可以兼容10M网卡),是56位的二进制数101010101010…..

  • SD: 分隔位,表示下面跟着的是真正的数据,而不是同步时钟,为8位的10101011,跟同步位不同的是最后2位是11而不是10.

  • DA:目的地址,以太网的地址为48位(6个字节)二进制地址,表明该帧传输给哪个网卡.如果为FFFFFFFFFFFF,则是广播地址,广播地址的数据可以被任何网卡接收到.

  • SA:源地址,48位,表明该帧的数据是哪个网卡发的,即发送端的网卡地址,同样是6个字节.

  • TYPE:类型字段,表明该帧的数据是什么类型的数据,不同的协议的类型字段不同。如:0800H 表示数据为IP包,0806H 表示数据为ARP包,814CH是SNMP包,8137H为IPX/SPX包,(小于0600H的值是用于IEEE802的,表示数据包的长度。)

  • DATA:数据段 ,该段数据不能超过1500字节。因为以太网规定整个传输包的最大长度不能超过1514字节。(14字节为DA,SA,TYPE)

  • PAD:填充位。由于以太网帧传输的数据包最小不能小于60字节, 除去(DA,SA,TYPE 14字节),还必须传输46字节的数据,当数据段的数据不足46字节时,后面补000000…..(当然也可以补其它值)

  • FCS:32位数据校验位.为32位的CRC校验,该校验由网卡自动计算,自动生成,自动校验,自动在数据段后面填入.对于数据的校验算法,我们无需了解.

事实上,PR,SD,PAD,FCS这几个数据段我们不用理它 ,它是由网卡自动产生的,我们要理的是DA,SA,TYPE,DATA四个段的内容.

所有数据位的传输由低位开始(但传输的位流是用曼彻斯特编码的)

以太网的冲突退避算法就不介绍了,它是由硬件自动执行的.

DA+SA+TYPE+DATA+PAD最小为60字节,最大为1514字节.

以太网卡可以接收三种地址的数据,一个是广播地位,一个是多播地址(我们用不上),一个是它自已的地址.但网卡也可以设置为接收任何数据包(用于网络分析和监控).

任何两个网卡的物理地址都是不一样的,是世界上唯一的,网卡地址由专门机构分配.不同厂家使用不同地址段,同一厂家的任何两个网卡的地址也是唯一的.根据网卡的地址段(网卡地址的前三个字节),可以知道网卡的生产厂家.有些网卡的地址也可以由用户去设定,但一般不需要.

3 Ethernet 802.3 raw帧格式

在Ethernet 802.3 raw类型以太网帧中,原来Ethernet II类型以太网帧中的类型字段被”总长度”字段所取代,它指明其后数据域的长度,其取值范围为:46-1500。

接下来的2个字节是固定不变的16进制数0xFFFF,它标识此帧为Novell以太类型数据帧。

这种格式的来源历史非常晦涩,这是1983年Novell发布其划时代的Netware/86网络套件时采用的私有以太网帧格式,该格式以当时尚未正式发布的802.3标准为基础;但是当两年以后IEEE正式发布802.3标准时情况发生了变化—IEEE在802.3帧头中又加入了802.2 LLC(Logical Link Control)头,这使得Novell的RAW 802.3格式跟正式的IEEE 802.3标准互不兼容;可以看到在Novell的RAW 802.3帧结构中并没有标志协议类型的字段,而只有Length 字段(2bytes,取值为0000-05dc,即十进制的0-1500),因为RAW 802.3帧只支持IPX/SPX一种协议;

4 Ethernet 802.3 SAP帧格式

这种帧格式属于 IEEE 802.3/802.2 LLC 标准。

在Ethernet 802.3 SAP帧中,将原Ethernet 802.3 raw帧中2个字节的0xFFFF变为各1个字节的DSAP和SSAP,同时增加了1个字节的”控制”字段,构成了802.2逻辑链路控制(LLC)的首部。LLC提供了无连接(LLC类型1)和面向连接(LLC类型2)的网络服务。LLC1是应用于以太网中,而LLC2应用在IBM SNA网络环境中。

新增的802.2 LLC首部包括两个服务访问点:源服务访问点(SSAP)和目标服务访问点(DSAP)。它们用于标识以太网帧所携带的上层数据类型,如16进制数0x06代表IP协议数据,16进制数0xE0代表Novell类型协议数据,16进制数0xF0代表IBM NetBIOS类型协议数据等。

常见SAP值:

  • 0 Null LSAP

  • 4 SNA Path Control

  • 6 DOD IP

  • AA: SNAP

  • FE: ISO DIS

  • FF: Global DSAP

……

SAP值用以标志上层应用,但是每个SAP字段只有8bits长,而且其中仅保留了6比特用于标识上层协议,因此所能标识的协议数有限(不超过32种);并且IEEE拒绝为某些重要的协议比如ARP协议定义SAP值(奇怪的是同时他们却定义了IP的SAP值);因此802.3/802.2 LLC的使用有很大局限性;

至于1个字节的”控制”字段,则基本不使用(一般被设为0x03,指明采用无连接服务的802.2无编号数据格式)。

5 Ethernet 802.3 SNAP帧格式

Ethernet 802.3 SNAP类型以太网帧格式和Ethernet 802.3 SAP类型以太网帧格式的主要区别在于:

  • 2个字节的DSAP和SSAP字段内容被固定下来,其值为16进制数0xAA。

  • 1个字节的”控制”字段内容被固定下来,其值为16进制数0x03。

  • 增加了SNAP字段,由下面两项组成

    • 新增了3个字节的组织唯一标识符(Organizationally Unique Identifier,OUI ID)字段,其值通常等于MAC地址的前3字节

    • 增加了表示上层协议的类型

这是IEEE为保证在802.2 LLC上支持更多的上层协议同时更好的支持IP协议而发布的标准,与802.3/802.2 LLC一样,802.3/802.2 SNAP也带有LLC头,但是扩展了LLC属性,新添加了一个2Bytes的协议类型域(同时将SAP的值置为AA),从而使其可以标识更多的上层协议类型;另外添加了一个3Bytes的OUI字段用于代表不同的组织,RFC 1042定义了IP报文在802.2网络中的封装方法和ARP协议在802.2 SANP中的实现;

一点资料

关于802.3 的标准,历史真是晦暗不明,看wiki都看不出个所以然来,我只能简单列举一下资料:

https://en.wikipedia.org/wiki/Ethernet_frame#Novell_raw_IEEE_802.3

http://lostintransit.se/2012/06/06/the-history-of-ethernet-dix-vs-802-3/

一点小tip

Q: MTU最大可以设置为多大?

A: 9000,这是由CRC校验的能力决定的。参考:

https://en.wikipedia.org/wiki/Jumbo_frame

PS:早期的一些网络,比如超通道,可以支持65535的mtu,但是已经湮没于历史风尘中了。

参考:

https://zh.wikipedia.org/wiki/IEEE_802.1ad

https://en.wikipedia.org/wiki/Ethernet_frame

Netcat Command

| Comments

Netcat能做到的事情太多了,但和tcpdump一个流派,参数多的令人发指,拣常用的几个命令记录一下

场景

Server A: 192.168.100.100

Server B: 192.168.100.101

端口扫描

1
nc -z -v -n 192.168.100.100 21-25
  • 可以运行在TCP或者UDP模式,默认是TCP,-u参数调整为udp.
  • z 参数告诉Netcat使用Zero IO,指的是一旦连接关闭,不进行数据交换
  • v 参数指使用冗余选项
  • n 参数告诉Netcat 不要使用DNS反向查询IP地址的域名

一旦你发现开放的端口,你可以容易的使用Netcat 连接服务抓取他们的banner。

1
nc -v 192.168.100.100 21

消息传送

两台机器间消息传输

SERVER A:

1
nc -l 1234

Netcat 命令在1567端口启动了一个tcp 服务器,所有的标准输出和输入会输出到该端口。输出和输入都在此shell中展示。

SERVER B:

1
nc 192.168.100.100 1234

不管你在机器B上键入什么都会出现在机器A上

文件传输

大部分时间中,我们都在试图通过网络或者其他工具传输文件。有很多种方法,比如FTP,SCP,SMB等等,但是当你只是需要临时或者一次传输文件,真的值得浪费时间来安装配置一个软件到你的机器上嘛。假设,你想要传一个文件file.txt 从A 到B。A或者B都可以作为服务器或者客户端,以下,让A作为服务器,B为客户端。

SERVER A:

1
nc -l 1234 < file.txt

SERVER B:

1
nc -n 192.168.100.100 1234 > file.txt

这里我们创建了一个服务器在A上并且重定向Netcat的输入为文件file.txt,那么当任何成功连接到该端口,Netcat会发送file的文件内容。

在客户端我们重定向输出到file.txt,当B连接到A,A发送文件内容,B保存文件内容到file.txt.

没有必要创建文件源作为Server,我们也可以相反的方法使用。像下面的我们发送文件从B到A,但是服务器创建在A上,这次我们仅需要重定向Netcat的输出并且重定向B的输入文件。

B作为Server

SERVER B:

1
nc -l 1234 > file.txt

SERVER A:

1
nc 192.168.100.101 1234 < file.txt

目录传输

发送一个文件很简单,但是如果我们想要发送多个文件,或者整个目录,一样很简单,只需要使用压缩工具tar,压缩后发送压缩包。

如果你想要通过网络传输一个目录从A到B。

SERVER A:

1
tar -cvf – dir_name | nc -l 1234

SERVER B:

1
nc -n 192.168.159.100 1234 | tar -xvf -

这里在A服务器上,我们创建一个tar归档包并且通过-在控制台重定向它,然后使用管道,重定向给Netcat,Netcat可以通过网络发送它。

在客户端我们下载该压缩包通过Netcat 管道然后打开文件。

如果想要节省带宽传输压缩包,我们可以使用bzip2或者其他工具压缩。

SERVER A:

1
tar -cvf – dir_name| bzip2 -z | nc -l 1234

通过bzip2压缩

SERVER B:

1
nc -n 192.168.100.100 1234 | bzip2 -d |tar -xvf -

使用bzip2解压

加密你通过网络发送的数据

如果你担心你在网络上发送数据的安全,你可以在发送你的数据之前用如mcrypt的工具加密。

SERVER A:

1
nc 192.168.100.101 1234 | mcrypt –flush –bare -F -q -d -m ecb > file.txt

使用mcrypt工具加密数据。

SERVER B:

1
mcrypt –flush –bare -F -q -m ecb < file.txt | nc -l 1234

使用mcrypt工具解密数据。

以上两个命令会提示需要密码,确保两端使用相同的密码。

这里我们是使用mcrypt用来加密,使用其它任意加密工具都可以。

克隆一个设备

如果你已经安装配置一台Linux机器并且需要重复同样的操作对其他的机器,而你不想在重复配置一遍。不在需要重复配置安装的过程,只启动另一台机器的一些引导可以随身碟和克隆你的机器。

克隆Linux PC很简单,假如你的系统在磁盘/dev/sda上

SERVER A:

1
$dd if=/dev/sda | nc -l 1567

SERVER B:

1
$nc -n 192.168.100.100 1567 | dd of=/dev/sda

打开一个shell

没有telnet和ssh的时候,可以使用Netcat创建远程shell。

假设你的Netcat支持 -c -e 参数(默认 Netcat)

SERVER A:

1
$nc -l 1567 -e /bin/bash -i

SERVER B:

1
$nc 192.168.100.100 1567

这里我们已经创建了一个Netcat服务器并且表示当它连接成功时执行/bin/bash

假如Netcat 不支持-c 或者 -e 参数(openbsd Netcat),我们仍然能够创建远程shell

SERVER A:

1
$mkfifo /tmp/tmp_fifo$cat /tmp/tmp_fifo | /bin/sh -i 2>&1 | nc -l 1567 > /tmp/tmp_fifo

这里我们创建了一个fifo文件,然后使用管道命令把这个fifo文件内容定向到shell 2>&1中。是用来重定向标准错误输出和标准输出,然后管道到Netcat 运行的端口1567上。至此,我们已经把Netcat的输出重定向到fifo文件中。

说明:从网络收到的输入写到fifo文件中

  • cat 命令读取fifo文件并且其内容发送给sh命令

  • sh命令进程收到输入并把它写回到Netcat。

  • Netcat 通过网络发送输出到client

至于为什么会成功是因为管道使命令平行执行,fifo文件用来替代正常文件,因为fifo使读取等待而如果是一个普通文件,cat命令会尽快结束并开始读取空文件。

反向shell

反向shell是人曾经在客户端打开的shell。反向shell这样命名是因为不同于其他配置,这里服务器使用的是由客户提供的服务。

服务端

1
$nc -l 1567

在客户端,简单地告诉Netcat在连接完成后,执行shell。

客户端

1
$nc 192.168.100.100 -e /bin/bash

现在,什么是反向shell的特别之处呢

反向shell经常被用来绕过防火墙的限制,如阻止入站连接。例如,我有一个专用IP地址为192.168.100.100,我使用代理服务器连接到外部网络。如果我想从网络外部访问 这台机器如1.2.3.4的shell,那么我会用反向shell用于这一目的。

指定源端口

假设你的防火墙过滤除25端口外其它所有端口,你需要使用-p选项指定源端口。

服务器端

1
$nc -l 1567

客户端

1
$nc 172.31.100.7 1567 -p 25

使用1024以内的端口需要root权限。

该命令将在客户端开启25端口用于通讯,否则将使用随机端口。

指定源地址

假设你的机器有多个地址,希望明确指定使用哪个地址用于外部数据通讯。我们可以在Netcat中使用-s选项指定ip地址。

服务器端

1
$nc -u -l 1567 < file.txt

客户端

1
$nc -u 172.31.100.7 1567 -s 172.31.100.5 > file.txt

该命令将绑定地址172.31.100.5。

参考:

http://os.51cto.com/art/201304/388721.htm