IPSEC协议簇安全框架
a.IPSec简介
IPSec(Internet Protocol Security):是一组基于网络层的,应用密码学的安全通信协议族。IPSec不是具体指哪个协议,而是一个开放的协议族。
IPSec协议的设计目标:是在IPV4和IPV6环境中为网络层流量提供灵活的安全服务。
IPSec(Internet Protocol Security):是一组基于网络层的,应用密码学的安全通信协议族。IPSec不是具体指哪个协议,而是一个开放的协议族。
IPSec协议的设计目标:是在IPV4和IPV6环境中为网络层流量提供灵活的安全服务。
IPsec(Internet Protocol Security)是为IP网络提供安全性的协议和服务的集合,它是VPN(Virtual Private Network,虚拟专用网)中常用的一种技术。 由于IP报文本身没有集成任何安全特性,IP数据包在公用网络如Internet中传输可能会面临被伪造、窃取或篡改的风险。通信双方通过IPsec建立一条IPsec隧道,IP数据包通过IPsec隧道进行加密传输,有效保证了数据在不安全的网络环境如Internet中传输的安全性。
# 0 --- 说明 ---
下面例子中的单引号目的是为了避免nftable参数中的星号、花括号、分号等符号被shell展开解释掉了,导致nft命令出错。
# 1 ---- 规则集合操作 ---
nft list ruleset # 列出已有规则集
nft flush ruleset # 清除已有规则集, 这个命令会清理掉所的表、规则链、表。
# 2 ---- 禁止别人ping无线网卡ipv4地址的例子,input钩子 ---
nft add table ip tb0 #创建表(用来容纳多条链)。新建一个family为ip(也就是作用于ipv4地址族)的表, 表名为tb0。
nft list tables #列出所有表,这里可以看见刚刚建立的表tb0,注意tables是复数。
nft add chain ip tb0 ch0_input '{type filter hook input priority 0; policy accept; }' #创建链(用来容纳多条规则)。在tb0表下创建链名为ch0_input的链,这条链的类型是filter(三种基本链中的一种),链的钩子是input,优先级是0,策略为accept;这里"policy accept;"可以省略(因为他是默认的)
nft add rule ip tb0 ch0_input meta iifname 'wlp3s0' icmp type echo-request drop #创建规则(规则包含matches和statements)。在tb0表ch0_input链上创建规则。规则的matches是:在wifi网络接口wlp3s0上的icmp请求。statements是:drop 。这里网络接口可以写成'wlp*'或'enp*',表示所有的wifi网络接口或以太网卡借口。这里statements也可以写成"reject with icmp type net-prohibited"。注意我用matches和statements都是复数,说明matches和statements是支持多个的,本例中的matches就有两个,一个是匹配网卡,一个是匹配协议。关于mathes和statement的用法具体参考后文解释
nft list table ip tb0 -an #列出表tb0详情,注意table是单数。这里地址族为ip,表名tb0, -a表示显示handle号(一种便于操作表、链、规则的序号,比如这里可以通过nft delete table handle 4来删除这个表,假设handle号是4), -n数字形式
nft delete table ip tb0 #删除表, 也可以通过表的handle号删除
# 3 ---- 禁止访问某个外部ipv4/ipv6的某端口号的例子,output钩子 -----
nft add table inet tb1 #创建表。针对inet地址族(inet表示ip地址族和ip6地址族。也就是针对ipv4和ipv6地址的)
nft add chain inet tb1 ch1_output '{type filter hook output priority 0; policy accept; }' #添加链。 链类型为基本链中的filter链,钩子为output,默认策略为accept。
nft add rule inet tb1 ch1_output ip daddr 192.168.43.148 tcp dport 22 reject with tcp reset #添加规则。 matches为两个:1-目标ipv4地址 2-tcp 目标端口22。 statements是:使用tcp重置
nft add rule inet tb1 ch1_output ip6 daddr fe80::fe9c:cc8e:f0b6:ac7e tcp dport '{22,80}' drop #添加规则。 matches有两个:目标ipv6地址和目标端口。statements:是drop。效果是执行ssh root@fe80::fe9c:cc8e:f0b6:ac7e%wlp3s0 无法连上ssh
nft flush ruleset #清理规则集。清理后的效果,ssh root@fe80::fe9c:cc8e:f0b6:ac7e%wlp3s0 和 ssh root@192.168.43.148也提示输入密码了。
表有几个family: ip/ip6/inet/arp/bridge/netdev; inet=ip和ip6的混合
使用下面的 route 命令可以查看 Linux 内核路由表。
# route
Destination Gateway Genmask Flags Metric Ref Use Iface
192.168.0.0 * 255.255.255.0 U 0 0 0 eth0
169.254.0.0 * 255.255.0.0 U 0 0 0 eth0
default 192.168.0.1 0.0.0.0 UG 0 0 0 eth0
route 命令的输出项说明
输出项 | 说明 |
---|---|
Destination | 目标网段或者主机 |
Gateway | 网关地址,”*” 表示目标是本主机所属的网络,不需要路由 |
Genmask | 网络掩码 |
Flags | 标记。一些可能的标记如下: |
U — 路由是活动的 | |
H — 目标是一个主机 | |
G — 路由指向网关 | |
R — 恢复动态路由产生的表项 | |
D — 由路由的后台程序动态地安装 | |
M — 由路由的后台程序修改 | |
! — 拒绝路由 | |
Metric | 路由距离,到达指定网络所需的中转数(linux 内核中没有使用) |
Ref | 路由项引用次数(linux 内核中没有使用) |
Use | 此路由项被路由软件查找的次数 |
Iface | 该路由表项对应的输出接口 |
网关为0.0.0.0的网络通常是直连到网络设备上的,本地的直通路由。因为到自己的直连设备上是不需要网关的,所以0.0.0.0的网关地址是正常的。目的地址是0.0.0.0的路由是你的缺省网关。
package main
import (
"fmt"
"syscall"
"net"
"unsafe"
"sort"
)
type rtInfo struct {
Dst net.IPNet
Gateway, PrefSrc net.IP
OutputIface uint32
Priority uint32
}
type routeSlice []*rtInfo
type router struct {
ifaces []net.Interface
addrs []net.IP
v4 routeSlice
}
func getRouteInfo() (*router, error) {
rtr := &router{}
tab, err := syscall.NetlinkRIB(syscall.RTM_GETROUTE, syscall.AF_INET)
if err != nil {
return nil, err
}
msgs, err := syscall.ParseNetlinkMessage(tab)
if err != nil {
return nil, err
}
for _, m := range msgs {
switch m.Header.Type {
case syscall.NLMSG_DONE:
break
case syscall.RTM_NEWROUTE:
rtmsg := (*syscall.RtMsg)(unsafe.Pointer(&m.Data[0]))
attrs, err := syscall.ParseNetlinkRouteAttr(&m)
if err != nil {
return nil, err
}
routeInfo := rtInfo{}
rtr.v4 = append(rtr.v4, &routeInfo)
for _, attr:= range attrs {
switch attr.Attr.Type {
case syscall.RTA_DST:
routeInfo.Dst.IP = net.IP(attr.Value)
routeInfo.Dst.Mask = net.CIDRMask(int(rtmsg.Dst_len), len(attr.Value)*8)
case syscall.RTA_GATEWAY:
routeInfo.Gateway = net.IPv4(attr.Value[0], attr.Value[1], attr.Value[2], attr.Value[3])
case syscall.RTA_OIF:
routeInfo.OutputIface = *(*uint32)(unsafe.Pointer(&attr.Value[0]))
case syscall.RTA_PRIORITY:
routeInfo.Priority = *(*uint32)(unsafe.Pointer(&attr.Value[0]))
case syscall.RTA_PREFSRC:
routeInfo.PrefSrc = net.IPv4(attr.Value[0], attr.Value[1], attr.Value[2], attr.Value[3])
}
}
}
}
sort.Slice(rtr.v4, func(i, j int) bool {
return rtr.v4[i].Priority < rtr.v4[j].Priority
})
ifaces, err := net.Interfaces()
if err != nil {
return nil, err
}
for i, iface := range ifaces {
if i != iface.Index - 1 {
break
}
if iface.Flags & net.FlagUp == 0{
continue
}
rtr.ifaces = append(rtr.ifaces, iface)
ifaceAddrs, err := iface.Addrs()
if err != nil {
return nil, err
}
var addrs net.IP
for _, addr := range ifaceAddrs {
if inet, ok := addr.(*net.IPNet); ok {
if v4 := inet.IP.To4(); v4 != nil {
if addrs == nil {
addrs = v4
}
}
}
}
rtr.addrs = append(rtr.addrs, addrs)
}
return rtr, nil
}
func (r *router)getRoute(dst net.IP) {
for _, rt := range r.v4 {
if rt.Dst.IP != nil && !rt.Dst.Contains(dst) {
continue
}
fmt.Printf("%-15v : ", dst.String())
if rt.PrefSrc == nil {
fmt.Println(r.ifaces[rt.OutputIface - 1].Name, rt.Gateway.String(), r.addrs[rt.OutputIface - 1].String())
} else {
fmt.Println(r.ifaces[rt.OutputIface - 1].Name, rt.Gateway.String(), rt.PrefSrc.String())
}
return
}
}
func main() {
newRoute, err := getRouteInfo()
if err != nil {
fmt.Println(err)
return
}
fmt.Println("**************************************")
fmt.Printf("%-15v %-15v %-15v\n", "interfaceName", "gateway", "ip")
for _, rt := range newRoute.v4 {
if rt.Gateway != nil {
fmt.Printf("%-15v %-15v %-15v\n", newRoute.ifaces[rt.OutputIface - 1].Name, rt.Gateway.String(), newRoute.addrs[rt.OutputIface - 1])
}
}
fmt.Println("**************************************")
newRoute.getRoute(net.ParseIP("192.168.2.100"))
newRoute.getRoute(net.ParseIP("10.10.100.100"))
newRoute.getRoute(net.ParseIP("172.1.2.100"))
}
etcd 是一个分布式的k/V存储系统。核心使用了RAFT分布式一致性协议。一致性这个概念,它是指多个服务器在状态达成一致,但是在一个分布式系统中,因为各种意外可能,有的服务器可能会崩溃或变得不可靠,它就不能和其他服务器达成一致状态。这样就需要一种Consensus协议,一致性协议是为了确保容错性,也就是即使系统中有一两个服务器当机,也不会影响其处理过程。
为了以容错方式达成一致,我们不可能要求所有服务器100%都达成一致状态,只要超过半数的大多数服务器达成一致就可以了,假设有N台服务器,N/2 +1 就超过半数,代表大多数了。
Bloom Filter是由Bloom在1970年提出的一种多哈希函数映射的快速查找算法。通常应用在一些需要快速判断某个元素是否属于集合,但是并不严格要求100%正确的场合。
介绍
使用GNU的工具我们如何在Linux下创建自己的程序函数库?一个“程序函数库”简单的说就是一个文件包含了一些编译好的代码和数据,这些编译好的代码和数据可以在事后供其他的程序使用。程序函数库可以使整个程序更加模块化,更容易重新编译,而且更方便升级。