交换高级特性 —— DHCP snooping(DHCP欺骗泛红攻击

一、DHCP欺骗泛洪攻击
(1)钓鱼网站简介:
“钓鱼网站”的页面与真实网站界面基本一致,欺骗消费者或者窃取访问者提交的账号和密码信息。钓鱼网站一般只有一个或几个页面,和真实网站差别细微 。通常伪装成银行及电子商务、窃取用户提交的银行账号、密码等私密信息的网站。
(2)DHCP中继技术简介:
一般情况下,DHCP Server和DCHP Client都必须处于同一个网络中,这是因为DHCP的报文有些是以广播的形式发送,如果不位于同一个网络,则这些广播的报文就无法跨越三层路由设备传输。而在有些情况下,DHCP服务必须跨越不同的网络,这时,我们就可以配置DHCP中继服务。DHCP中继,其实就是在与DHCP Server不同而又需要申请DHCP服务的网络内,设置一个中继器,中继器在该网络中代替DHCP Server服务器接收DHCP Client的请求,并将DHCP Client发给DHCP Server的DCHP报文,以单播的形式发送给DHCP Server。DHCP Server在收到由DHCP发送来的DHCP 报文后,同样会把响应的DHCP报文发送给DHCP 中继。这样,DHCP其实是充当了一个中间人的作用,起到了在不同的网络中运行DHCP的目的。
(2-1)核心交换机DHCP中继配置命令:
interface Vlan 20
ip address 192.168.20.254 255.255.255.0
ip helper-address 192.168.10.1//将广播包变成单播单播包发给DHCP server
exit
(3)dhcp欺骗详解:

正常情况下:PC1通过DHCP Server获取到IP、网关、DNS,当PC1访问www.123.com的时候会首先会把域名朝着DNS发送,然后DNS查询公网IP地址,把公网IP地址发给pc1,然后pc1会朝着100.1.1.1发起页面请求,正常访问Web服务器。
黑客恶意行为目的:当PC1访问外网正常的服务器时,使其访问这个钓鱼网站窃取他人信息。
第一步:pc2作为恶意攻击者会耗尽DHCP Sever的地址池,让DHCP Server不能给pc1分配地址池
首先,DHCP Server 是根据不同的mac地址分配IP地址,基于这一特性,pc2作为恶意攻击者,会创建一个discover报文:

discover报文到达核心交换机以后,经过核心交换机的中继路由,提交给DHCP Server服务器,然后服务器根据这个网关地址从自己众多地址池里,找到对应网段的地址池,给pc2分配IP地址。
每个mac分配一个ip,然而核心交换机关心的是处于discover报文里的mac地址。所以恶意攻击者可以伪造大量的discover报文在极短的时间内耗尽地址池(随机产生discover报文中的mac地址)
第二步:pc2充当DNS和DHCP 欺骗pc1
当全部耗尽以后,pc2可以充当DHCP和DNS(一般是在Linux系统里开启)
所以当pc1再次发送discover报文的话,pc2肯定可以收到,所以现在由pc2给pc1分配
IP:192.168.20.1 网关:192.168.20.4 DNS:192.168.20.4 ,此时pc1发送的,上网流量、DNS请求都发给了pc2(pc2作为DNS会做一个映射:www.123.com对应公网IP地址为200.1.1.1)
所以当pc1访问www.123.com的时候会把域名发给pc2 做一个域名解析,而pc2做出的域名解析结果为200.1.1.1,200.1.1.1对应的是钓鱼网站,所以你在访问www.123.com时,实际访问的是钓鱼网站(你在钓鱼网站上输入的所有用户名、密码……黑客都可以窃取到)
注:当大量产生BPDU报文时,就造成了泛洪攻击

二、防御——DHCP snooping
(1)开启DHCP SNOOPING之后的效果:
3560全局配置:
3560(config)#ip dhcp snooping //全局开启
3560(config)#ipdhcp snooping vlan 100 //VLAN100启用

3550配置:
3550(config)#ipdhcp snooping //全局开启
3550(config)#ipdhcp snooping vlan 100 //VLAN100启用
1、交换机启用DHCP snooping ,所有vlan接口默认为untrust非信任状态,无法接受来自DHCP server的offer报文和ACK报文,除非把此接口置为trust信任接口

sw-3550(config)#int f0/2
sw-3550(config-if)#ip dhcp snooping trust
sw-3550(config-if)#exit
2、检查二层数据帧源MAC地址和discover里面的PC MAC地址是否匹配,如果不匹配则丢弃(但是如果黑客可以设计算法使这两个同步变化,则还可以在接口启用端口安全技术)(DHCP根据discover 里面MAC地址报文分配IP,耗尽地址池主要就是根据discover报文里面的MAC地址)

3、可以在接口下针对DHCP报文进行限速,防御黑客利用DHCP报文进行广播泛洪攻击

针对DHCP报文进行限速:每秒这个接口可以发送DHCP报文10个
sw-3550(config)#int f0/6
sw-3550(config-if)#ipdhcp snooping limit rate 10
sw-3550(config-if)#exit
4、检查从PC收到的DHCP报文,如果PC发送的DHCP报文含有option 82(主要体现pc连接到那台交换机的哪个接口下)的话(违规行为)则丢弃此报文,因为只有交换机采用权限在DHCP报文里面插入option 82选项(交换机还会在discover报文里面插入对应VLAN的gateway ip地址)

5、检查是否有PC替代其他PC恶意退租IP地址(pc2发送恶意退租指令给DHCP server,让server回收pc1 IP地址,所以当DHCP server给其他pc分配IP地址的时候,分配的是pc1的IP,则会形成IP地址冲突,导致不能上网),以及检查从这个接口收到的DHCP报文是否合乎DHCP的报文规矩

6、配置DHCP snooping之后,交换机能够感知到DHCP server给PC分配的IP,于是系统自动一张扩展的CAM(mac)地址表(条件是必须有dhcp server和client及交换机开启dhcp snooping,如果没有dhcp server可以自己写,但是交换机必须开启dhcp snooping)将IP地址和传统的mac地址表及IP地址租期关联起来。当用以其他的高级安全应用;这个IP分配给了那个MAC,这个MAC连接在我的那个接口,这个接口属于那个VLAN,这个IP地址的租期多少时间。

( 扩展mac(CAM)地址表格式:IP — MAC — 接口 — VLAN — 租期)

(2)配置案列

3560全局配置:
3560(config)#ip dhcp snooping //全局开启
3560(config)#ipdhcp snooping vlan 100 //VLAN100启用

3550配置:
3550(config)#ipdhcp snooping //全局开启
3550(config)#ipdhcp snooping vlan 100 //VLAN100启用
观察PC2无法重新获取IP地址 ?

原因是:两台交换启用了DHCP snooping功能,默认启用此功能的交换机所有接口会拒绝接受来自DHCP serve的报文,需要把连接DHCP server的F0/2接口置为trust状态,可以接受offea和ACK报文

sw-3550(config)#int f0/2
sw-3550(config-if)#ip dhcp snooping trust
sw-3550(config-if)#exit
发现打上trust命令,PC2任然无法获取IP地址,为什么?

PC2发出discover报文,在经过3550的时候被插入了option 82选项,带有option82选项的报文传给3560的时候被拒绝接受

解决方案:
1、3550不插入option 82选项
sw-3550(config)#no ip dhcp snooping information option
2、3560允许option82选项从untruste接口进来
3560(config)#ip dhcp snooping information option allow-untrusted
针对DHCP报文进行限速:每秒这个接口可以发送DHCP报文10个

sw-3550(config)#int f0/6
sw-3550(config-if)#ipdhcp snooping limit rate 10
sw-3550(config-if)#exit
手工定义扩展的CAM表(交换机开启必须dhcp snooping):

ip source binding mac地址 VLAN ID IP地址 接口
基于源MAC和源IP地址的过滤

Ip dhcp snooping
Ip dhcp snooping vlan 10
ip source binding 0001.0001.0001 vlan10 192.168.1.101 interface Fa0/7
启用端口安全:

Int f0/7
Switchport port-security(启用端口安全)
Ip verity source port-secuity ————检查源IP
Exit
对从F0/7接口进入的报文,根据源IP地址和源MAC地址进行认证审查,是否满足扩展的CAM表

防御 IP 地址欺骗攻击 ,mac地址欺骗攻击

ARP欺骗攻击(争对PC)防御:

ip dhcp snooping vlan 10
ip arp inspection vlan 10
ip arp inspection limit 15
默认1秒15个包,超过down,

判断ARP广播是否满足扩展的CAM表,满足通过,不满足丢弃


原文链接有图:https://blog.csdn.net/qq_62311779/article/details/126340075

echo命令-Linux简单脚本编写及应用

Echo在windows下的命令的语法很简单。以下是Echo命令的基本语法:

echo string

其中,string是要输出的任意文本。Echo命令可以输出任何纯文本,包括数字、字母、标点符号等。

输出计算机用户名

echo My Name is %username%

输出当前时间

echo The time is %time%

关闭回显,且不显示命令行本身(另存为.bat运行)

@echo off

echo 这是第一行

将输出重定向到文件

echo “Hello World!” > d:\output.txt

如果您想要将输出附加到现有文件的末尾,则可以使用“>>”运算符。

echo “This is a second line!” >> d:\output.txt

echo在liunx下命令类似

命令格式:

echo [参数] [字符串]

常见参数:

-n:不自动换行,输出字符串后不跟随回车符。

-e:允许输出字符串中的转义字符,如“\n”表示换行符、“\t”表示制表符等。还有一些转义符可以用-h查看

-E        明确禁止反斜杠转义

常见用法:

1. 输出字符串:

echo “Hello world”

2. 输出变量值:

name=”Linux”

echo “The operating system is $name”

3. 向文件写入文本:

echo “This is a test” > test.txt

4. 输出多行文本:

echo -e “line1\nline2\nline3”

此处就是用-e参数来使后面的转义字符\n生效了,才会输出多行,

echo -e “line1\nline2\nline3”

[root@server dir]# echo -e 'aaa\bbbb'
aabbb
此处就是用-e参数来使后面的转义字符\b生效了,\b表示退格,也就是向左删除一个字符

还可以设置颜色,命令:echo -e “\e[背景颜色;文字颜色;显示方式m字符串\e[0m” ,也可以\033来代替\e

注意事项:

1. 如果字符串中包含空格或特殊字符,需要使用引号将字符串括起来,以避免被解析为命令参数。

2. 如果需要将命令的执行结果作为字符串输出,在命令前面加上“$”符号即可,如:

echo “The date is $(date)”

下面我们来写一个liunx下的脚本 设定ens33网卡

  • IP:192.168.1.100/24
  • 网关:192.168.1.254
[root@localhost Desktop]# vim fixip.sh ——创建新的文件
 
  1 #!/bin/bash
  2 cd /etc/sysconfig/network-scripts/
  3 echo
  4 echo "DEVICE=ens33" > ifcfg-ens33
  5 echo "TYPE=Ethernet" >> ifcfg-ens33
  6 echo "ONBOOT=yes" >> ifcfg-ens33
  7 echo "BOOTPROTO=static" >> ifcfg-ens33
  8 echo "IPADDR=192.168.1.100" >> ifcfg-ens33
  9 echo "NATMASK=255.255.255.0" >> ifcfg-ens33
 10 echo "GATEWAY=192.168.1.254" >> ifcfg-ens33
 11 ifdown ens33
 12 ifup ens33
 

添加运行权限(+x):

[root@localhost Desktop]# chmod +x fixip.sh

此时ls文件的颜色会由白色变成蓝色

下面来执行命令

[root@localhost Desktop]# ./fixip.sh
./fixip.sh: line 2: cd: etc/sysconfig/network-scripts/: No such file or directory

Device ‘ens33’ successfully disconnected.
Connection successfully activated (D-Bus active path: /org/freedesktop/NetworkManager/ActiveConnection/18)
[root@localhost Desktop]#

此时IP就会设置好,下面再来优化下脚本为交互式脚本,给变量赋值,使其更加人性化

先了解下变量赋值

[root@localhost Desktop]# A="hello" ——为变量A赋值
[root@localhost Desktop]# echo A 
A
[root@localhost Desktop]# echo $A ——通过$A 调出它所表示的值(字符串)
hello
[root@localhost Desktop]# echo "$A world"
hello world
[root@localhost Desktop]# 

再来了解下利用read -p输入

-p参数允许在read命令行中直接指定一个提示如:

read -p “输入网站名:” website

echo “你输入的网站名是 $website”

exit 0

运行并按提示输入 xtaa.cn

结果会是:你输入的网站名是 xtaa.cn

所以上面的配置文件可以优化为:

[root@localhost Desktop]# vim fixip.sh
 
  1 #!/bin/bash
  2 read -p "please input ipddr:" IP
  3 read -p "please input netmask" MASK
  4 read -p "please input gateway:" WAY
  5 cd /etc/sysconfig/network-scripts/
  6 echo
  7 echo "DEVICE=ens33" > ifcfg-ens33
  8 echo "TYPE=Ethernet" >> ifcfg-ens33
  9 echo "ONBOOT=yes" >> ifcfg-ens33
 10 echo "BOOTPROTO=static" >> ifcfg-ens33
 11 echo "IPADDR=$IP" >> ifcfg-ens33
 12 echo "NATMASK=$MASK" >> ifcfg-ens33
 13 echo "GATEWAY=$WAY" >> ifcfg-ens33
 14 ifdown ens33
 15 ifup ens33

下面进一步学习If语句

Linux 中 大于: -gt 小于: -lt 等于: -eq 

————单分支——判断3是否小于5:

[root@localhost Desktop]# vim if.sh
 
  1 #!/bin/bash
  2 if [ 3 -lt 5 ]
  3 then echo "yes"
  4 fi
[root@localhost Desktop]# chmod +x if.sh
[root@localhost Desktop]# ./if.sh
yes

—多分支语句:利用输入变量判断

[root@localhost Desktop]# vim if.sh
 
  1 #!/bin/bash
  2 read -p "please input a num:" NUM
  3 if [ $NUM -lt 5 ]
  4 then echo "lt"
  5 elif [ $NUM -eq 10 ]
  6 then echo "eq" 
  7 else echo "gt"
  8 fi
[root@localhost Desktop]# ./if.sh
please input a num:10
eq
[root@localhost Desktop]# ./if.sh
please input a num:30
gt
[root@localhost Desktop]# ./if.sh
please input a num:5
gt

最后写一个脚本来检测内网主机存活状态(语句:if+for+while)

先来看下ping 操作的修饰:

  • -c 指定其发送几个包
  • -i 发间隔时间
  • -w 等待响应时间
  • &> 文件 将前面的输出结果导入到别的地方(我们要将其输出的结果不显示)

ping -c2 -i0.2 -w2 12.34.56.78 &> /dev/null

好,接下来来ping单个主机

[root@localhost poem]# vim ping.sh ——创建编写文件
  1 #!/bin/bash
  2 if `ping -c2 -i0.2 -w2 192.168.123.124 &> /dev/null`
  3 then echo "yes"
  4 else echo "no"
  5 fi  
[root@localhost poem]# chmod +x ping.sh ——赋权
[root@localhost poem]# ./ping.sh ——执行
no ——输出结果
[root@localhost poem]# 

输出结果为 no ,表示该主机不存在或未开启(未存活)

接下来我想IP由我输入

  1 #!/bin/bash
  2 read -p "please input ipaddr:" IP
  3 if `ping -c2 -i0.2 -w2 $IP &> /dev/null`
  4 then echo "yes"
  5 else echo "no"
  6 fi

接下来我想要扫描整个网段要用到for或者while

  • for 根据循环的次数(取值列表)
  • 循环 while 根据条件循环

for用法为:

for 变量 in 取值列表

do

子语句

done

while用法为:

while 条件

do

子语句

done

下面用for来实现

[root@localhost poem]# vim ping.sh
  1 #!/bin/bash
  2 NET=10.168.1.
  3 for IP in {100..115}
  4 do
  5   if `ping -c2 -i0.2 -w2 $NET$IP &> /dev/null`
  6   then echo -e "$NET$IP is \033[31mup\033[0m" (修改输出颜色)
  7   else echo -e "$NET$IP is \033[32mdown\033[0m" (修改输出颜色)
  8   fi
  9 done

可以用于网络嗅探

用whilt实现

[root@localhost poem]# vim ping.sh
  1 #!/bin/bash
  2 NET=10.168.1.
  3 IP=100
  4 while [ $IP -lt 115 ]
  5 do
  6   let IP++
  7   if `ping -c2 -i0.2 -w2 $NET$IP &> /dev/null`
  8   then echo -e "$NET$IP is \033[31mup\033[0m"
  9   else echo -e "$NET$IP is \033[32mdown\033[0m"
 10   fi
 11 done

电信光猫获取宽带账号密码

进光猫后

找到的密码是星号隐藏的,

需要在浏览器按 F12 进入开发者调试器,对着“密码”框右键选择检查,进行选择 HTML 元素,在开发者调试器内的 HTML 元素内,找到 type=password 代码,双击删除掉 password,或者选择删除 type=password 代码,操作完成就可以看到自己电信光猫的宽带密码了,然后把宽带密码保存下来,电信猫的宽带密码很多都是 32位 小写 MD5 加密的,可以通过MD5解密https://www.cmd5.com获得真正的密码

通过网络唤醒(WOL)实现语音开机-思路

如今大多数电脑、笔记本、NAS、甚至是打印机等设备都支持「网络唤醒」(WOL / Wake On Lan) 功能,直接通过发送网络命令,即可实现远程开机操作,平时自己的电脑做的很隐蔽,每次开机不方便,就利用 OpenWRT 提供的网络唤醒实现手机语音远程开机。

首先把你的电脑在BIOS上设置好网络唤醒(设置时记住mac地址,一般还会有唤醒使用的命令)

使用 SSH 登录到OpenWRT终端,执行以下命令进行安装网络唤醒所需的程序依赖和 luci 界面,提供的 WOL 和 Etherwake 是实现网络唤醒的主要依赖,luci-app-wol 与 luci-i18n-wol-zh-cn 分别为主程序和汉化包

opkg update
opkg install wol etherwake
opkg install luci-app-wol luci-i18n-wol-zh-cn

进入LUCI管理界面找到网络唤醒,在网络唤醒插件处选择网络接口是指设备连接路由的 LAN 口,接着根据 MAC 地址选择要唤醒的设备,选择完成点击“唤醒主机”,成功提示 Sendto worked ! 116

设置好后尝试唤醒没有问题后,再设置手机上语音唤醒

苹果手机 上设置 Siri 语音唤醒,打开快捷指令,新建通过 SSH 运行脚本(SSH连接openwrt),设置快捷指令名称,比如:打开电脑,并将 /usr/bin/etherwake 整句命令复制粘贴到第一行,主机地址设置路由地址,端口默认,填写用户和密码,然后点击右下角的三角形运行测试,正常也会提示:Sendto worked ! 116

唤醒命令:/usr/bin/etherwake -D -i "br-lan" "你设备的MAC地址"
主机地址:路由器地址
端口默认:22
用户默认:root
密码:你路由器的密码,没有设置,去设置一个

现在你可以在手机上语音说上面设置的指令名称“打开电脑”来开机了。

机顶盒到ubuntu-nas

论坛https://bbs.histb.com/官网https://www.ecoo.top/

支持的机顶盒列表https://www.ecoo.top/histb.html

装socket5: 需要自行准备节点!没有正确的节点配置文件是无法联通的。
安装下面的脚本后盒子打开了 Socks5 的代理服务功能, 端口号10808
你在浏览器或者系统自行设置通过盒子的IP192.168.12.106代理 Socks5 上网即可

1234567install-v2ray.sh --version v5.1.0       # 终端输入这句命令自行安装systemctl status v2ray      # 查看运行状态是否正常curl --socks5 127.0.0.1:10808 google.com  # 返回 301 字样则成功install-v2ray.sh --remove   # 终端输入命令即可卸载 v2ray# 节点配置文件在 /usr/local/etc/v2ray/config.json# 注意:需要自行准备节点!没有正确的节点配置文件是无法联通的。

装好系统后里面有alist等

装docker部署OpenWRT-(装上后旁路由实测无法科学上网)

hi3798mv100型号,其它型号自行测试。

  • 设置网络
    把网卡混杂模式打开
  • sudo ip link set 你自己的网卡名称 promisc on
    ifconfig
    ##以下是我的网卡名称,每台设备可能不一样,要注意!!!!
    sudo ip link set eth0 promisc on
    打开后为eth0: flags=4419<UP,BROADCAST,RUNNING,PROMISC,MULTICAST> mtu 1500
  • 创建 docker 网卡
    IP地址和网关根据自己的情况设置
    docker network create -d macvlan --subnet=192.168.1.67/24 --gateway=192.168.1.1 -o parent=eth0 macnet

-OpenWrt 标准镜像
原项目地址:https://github.com/SuLingGG/OpenWrt-Docker
一般情况下阿里云镜像仓库比较快
armv7
DockerHub———sulinggg/openwrt:rpi1
阿里云镜像仓库—–registry.cn-shanghai.aliyuncs.com/suling/openwrt:rpi1

arm8/aarch64
DockerHub———sulinggg/openwrt:armv8
阿里云镜像仓库—–registry.cn-shanghai.aliyuncs.com/suling/openwrt:armv8

x86_64/amd64
DockerHub———sulinggg/openwrt:x86_64
阿里云镜像仓库—–registry.cn-shanghai.aliyuncs.com/suling/openwrt:x86_64

查看系统架构 uname -a

##以下是hi3798mv100系统架构是armv7

创建并启动docker 镜像
docker run --restart always --name openwrt -d --network macnet --privileged registry.cn-shanghai.aliyuncs.com/suling/openwrt:armv7 /sbin/init
其它系统架构只需更改registry.cn-shanghai.aliyuncs.com/suling/openwrt:rpi1

  • 设置Openwrt容器 ip


点击进入bash命令控制台
输入 vim /etc/config/network
其它设置不用改,自行设置config interface ‘lan’下边 option ipaddr为OpenWRT的IP,geteway是主路由IP(网关)
如果报错重启容器再试。

  • 重启网络
    /etc/init.d/network restart

重启网络, 重启完成后便可以通过浏览器访问了

网心云
docker run -d \
–name=wxedge \
–restart=always \
–privileged \
–net=host \
–tmpfs /run \
–tmpfs /tmp \
-v /mnt/sda1:/storage:rw \
onething1/wxedge
1.-v 冒号前半部分改成自己本地路径,该路径重装时保持不变,则节点不变
2.安装完成后,使用IP:18888,登录后管界面,使用网心云APP扫描页面下方的二维码绑定

下面是在海纳斯上面装上tailscale

#停止固件自带的tailscale
systemctl stop tailscaled
#关闭固件自带的tailscale的开机自启
systemctl disable tailscaled
#删除执行文件和服务文件
rm -rf /usr/bin/tailscaled
rm -rf /etc/systemd/system/tailscaled.service
#执行官方的安装脚本
curl -fsSL https://tailscale.com/install.sh | sh
#启动软件并设为自启
systemctl start tailscaled
systemctl enable tailscaled
#启动软件,并在链接中登录账号
tailscale up

另外说下服务器做流量出口节点设置

在服务器上打开forword

 echo 'net.ipv4.ip_forward = 1' | sudo tee -a /etc/sysctl.d/99-tailscale.conf
echo 'net.ipv6.conf.all.forwarding = 1' | sudo tee -a /etc/sysctl.d/99-tailscale.conf
sudo sysctl -p /etc/sysctl.d/99-tailscale.conf

再设置可以做出口节点sudo tailscale up -advertise-exit-node

最后在https://login.tailscale.com/admin/machines的节点最右边编辑路由设置里打开Use as exit node,

其它的节点设置exit node为这个服务器,就可以这个服务器为出口代理来上网了。

视频在线下载部署记录

首先,安装you-get $ pip3 install you-get

Youtube-dl

再部署python代码,一般如果you-get下载不来的再用Youtube-dl来下,

最后如果离线下载要用就用clouddrive加个云盘到系统。

参考文章

https://github.com/soimort/you-get

视频专业下载工具,Youtube-dl 详细使用教程与初学上手示例

https://blog.csdn.net/Kim_Linshuo/article/details/109630654

https://zhuanlan.zhihu.com/p/344090839

https://blog.csdn.net/weixin_44578029/article/details/120676879

另外考虑加入下面这个,但是用go写的

https://github.com/iawia002/lux

还考虑加入代理池

https://github.com/ydf0509/proxypool_framework/tree/master

网络测试 iperf3

网上的在线宽带测试常因为网络环境的变动不太准确。

介绍
Iperf3 是一个网络性能测试工具。Iperf可以测试最大TCP和UDP带宽性能,具有多种参数和UDP特性,可以根据需要调整,可以报告带宽、延迟抖动和数据包丢失.对于每个测试,它都会报告带宽,丢包和其他参数,可在Windows、Mac OS X、Linux、FreeBSD等各种平台使用,是一个简单又实用的小工具。

    Iperf3也是C/S(客户端/服务器端)架构模式,在使用iperf3测试时,要同时在server端与client端都各执行一个程序,让它们互相传送报文进行测试。

    iperf3.0之前的版本只能用来测试千兆速率,但是万兆网络强烈建议使用iperf3测试。

下载
iperf下载链接

安装
在CentOS 7上使用下列命令即可安装:

yum install iperf3

在ubuntu 上使用下列命令安装:

apt-get install iperf3

测试:

iperf3 -h来查看中文帮助

服务器端直接运行

iperf3 -s

然后客户端按不同参数来测试,如设置多个并行数据流-P

iperf3 -c serverIP -P streams

例:iperf3 -c 192.168.1.1 -P 3

运行iperf3在客户端,反向测试(服务器端发送数据到客户端)iperf3 -c serverIP -R

例:iperf3 -c 192.168.1.1 -R

运行iperf3在客户端,使用UDP协议,并设置使用的测试带宽

iperf3 -c serverIP -b 1000M -t 60 -d

-c 为客户端运行并要指定服务端的IP地址

-b 表示使用的测试带宽

-t 表示以时间为测试结束条件进行测试,默认为 10 秒;

-d 打印出更详细的debug调试信息

例:iperf3 -c 192.168.1.1 -b 1000M -t 60 -d

参考https://blog.csdn.net/hhd1988/article/details/123918481

flask之REDIS+Dplayer消息队列实现电影弹幕

一、安装Redis

官网下载地址:https://redis.io/download

Redis  centos安装过程:

yum -y install gcc gcc-c++
wget http://download.redis.io/releases/redis-4.0.10.tar.gz
tar -zxvf redis-4.0.10.tar.gz
cd redis-4.0.10
make && make install
./utils/install_server.sh
#测试redis是否运行
redis-cli
> ping #返回pong表示成功

安装flask-redis

#清华源
pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple flask-redis

二、安装开源插件Dplayer

Dplayer官网地址:http://dplayer.js.org/#/    (有时候会打不开哦)

Dplayer github地址:https://github.com/MoePlayer/DPlayer

#html引入css/js
<link rel="stylesheet" href="{{ url_for('static',filename='dplayer/dist/Dplayer.min.css') }}" >
<script src="{{ url_for('static',filename='dplayer/dist/DPlayer.min.js') }}"></script>
#引用到页面
<div id="dplayer" style="height: 500px;width: 774px"></div>
#弹幕和视频接口
 <script>
        var dp1 = new DPlayer({
            container: document.getElementById('dplayer'),
            video: {
                url: "{{ url_for('static',filename='uploads/'+movie.url) }}"
            },
            danmaku: {
                id: '{{ movie.id }}',
                api: "/tm/"
            }
        });
 </script>
 
#Python返回弹幕的处理方法
@home.route("/tm/v3/",methods=["GET","POST"])
def tm():
    import json
    if request.method=="GET":
        #获取弹幕消息队列
        mid = request.args.get("id")
        key="movie"+str(mid)
        if rd.llen(key):
            msgs=rd.lrange(key,0,2999)
            res={
                "code":0,
                "data":[json.loads(v) for v in msgs]
            }
        else:
            res={
                "code":1,
                "danmaku":[]
            }
        resp=json.dumps(res)
    if request.method=="POST":
        #添加弹幕
        data=json.loads(request.get_data())
        msg= {
        "__v": 0,
        "_id": datetime.datetime.now().strftime("%Y%m%d%H%M%S") + uuid.uuid4().hex,
        "author": data["author"],
        "time": data["time"],
        "text": data["text"],
        "color": data["color"],
        "type": data["type"],
        "ip": request.remote_addr,
        "player": data["id"]
        }
        res = {
            "code": 0,
            "danmaku":msg
        }
        resp=json.dumps(res)
        msg=[data["time"],data["type"],data["color"],data["author"],data["text"]]
        rd.lpush("movie"+str(data["id"]),json.dumps(msg))
    return Response(resp,mimetype="application/json")

python日志:logging模块使用

何时使用logging

想要执行的任务工具
对于命令行或程序的应用,结果显示在控制台。print()
在对程序的普通操作发生时提交事件报告 (比如:状态监控和错误调查)http://logging.info() 函数 (当有诊断目的需要详细输出信息时使用
logging.debug() 函数)
提出一个警告信息基于一个特殊的运行时事件warnings.warn() 位于代码库中,该事件是可以避免的,需要修改
客户端应用以消除告警logging.warning() 不需要修改客户端应用,但是该事件还是需要引起关注
报告错误而不引发异常 (如在长时间运行中的服务端进程的错误处理)logging.error(),
logging.exception() 或 logging.critical() 分别适用于特定的错误及应用领域

日志事件级别

级别何时使用
DEBUG细节信息,仅当诊断问题时适用。
INFO确认程序按预期运行
WARNING表明有已经或即将发生的意外(例如:磁盘空间不足)。程序仍按预期进行
ERROR由于严重的问题,程序的某些功能已经不能正常执行
CRITICAL严重的错误,表明程序已不能继续执行

默认的级别是 “WARNING“,意味着只会追踪该级别及以上的事件,除非更改日志配置。所追踪事件可以以不同形式处理。最简单的方式是输出到控制台。另一种常用的方式是写入磁盘文件。


basicConfig()设置

# -*- coding:utf-8 -*-

import logging

#默认的warning级别,只输出warning以上的
#使用basicConfig()来指定日志级别和相关信息

logging.basicConfig(level=logging.DEBUG #设置日志输出格式
                    ,filename="demo.log" #log日志输出的文件位置和文件名
                    ,filemode="w" #文件的写入格式,w为重新写入文件,默认是追加
                    ,format="%(asctime)s - %(name)s - %(levelname)-9s - %(filename)-8s : %(lineno)s line - %(message)s" #日志输出的格式
                    # -8表示占位符,让输出左对齐,输出长度都为8位
                    ,datefmt="%Y-%m-%d %H:%M:%S" #时间输出的格式
                    )

logging.debug("This is  DEBUG !!")
logging.info("This is  INFO !!")
logging.warning("This is  WARNING !!")
logging.error("This is  ERROR !!")
logging.critical("This is  CRITICAL !!")

#在实际项目中,捕获异常的时候,如果使用logging.error(e),只提示指定的logging信息,不会出现
#为什么会错的信息,所以要使用logging.exception(e)去记录。

try:
    3/0
except Exception as e:
    # logging.error(e)
    logging.exception(e)

输出日志如下:

2021-03-26 02:03:01 - root - DEBUG     - basiclogging : 16 line - This is  DEBUG !!
2021-03-26 02:03:01 - root - INFO      - basiclogging : 17 line - This is  INFO !!
2021-03-26 02:03:01 - root - WARNING   - basiclogging : 18 line - This is  WARNING !!
2021-03-26 02:03:01 - root - ERROR     - basiclogging : 19 line - This is  ERROR !!
2021-03-26 02:03:01 - root - CRITICAL  - basiclogging : 20 line - This is  CRITICAL !!

2021-03-26 03:16:47 - root - ERROR     - basiclogging : 27 line - division by zero
Traceback (most recent call last):
  File "E:/pycharm_project/examples-of-web-crawlers-master/logginng/basiclogging", line 24, in <module>
    3/0
ZeroDivisionError: division by zero


logging的高级应用

logging采用了模块化设计,主要包含四种组件:

Loggers:记录器,提供应用程序代码能直接使用的接口。(类似于笔,使用不同的笔记录不同的日志,例如一个项目里有很多功能模块,每个模块可以设置不同的Logger去记录,然后设置每只笔的不同格式)

Handlers:处理器,将记录器产生的日志发送到目的地。(输出到文件或者控制台或者邮件等,一个记录器可以对应多个处理器。)

Filters:过滤器,提供更好的粒度控制,决定哪些日志会被输出。

Formatters:格式化器,设置日志内容的组成结构和消息字段。

Loggers记录器

  1. 提供应用程序的调用接口
logger = logging.getLogger(__name__)
#logger是单例的,也就是__name__不变,获取到的logger都是同一个

2.决定日志记录的级别

logger.setLevel()

3.将日志内容传递到相关联的handlers中

logger.addHandler()
logger.removeHandler()

Handler处理器

将日志发送到不同的地方

#常见的处理器
StreamHandler #屏幕输出
FileHandler #文件记录
BaseRotatingHandler #标准的分割文件日志
RotatingFileHandler #按文件大小记录日志
TimeRotatingFileHandler #按时间记录日志

StreamHandler

标准输出分发器,也就是屏幕显示

sh = logging.StreamHandler(stream=None)

FileHandler

将日志保存到文件中

fh = logging.FileHandler(filename,mode='a',encoding=None,delay=False)

setFormatter()

设置当前Handler对象使用的消息格式

Formatters格式

formatter对象用来最终设置日志信息的顺序,结构和内容

ft = logging.Formatter.__init__(fmt=None,datafmt=None)

logging编程方式代码demo

# -*- coding:utf-8 -*-

import logging

#编程的方式记录日志

#记录器
logger1 = logging.getLogger("logger1")
logger1.setLevel(logging.DEBUG)
print(logger1)
print(type(logger1))

logger2 = logging.getLogger("logger2")
logger2.setLevel(logging.INFO)
print(logger2)
print(type(logger2))


#处理器
#1.标准输出
sh1 = logging.StreamHandler()

sh1.setLevel(logging.WARNING)

sh2 = logging.StreamHandler()


# 2.文件输出
# 没有设置输出级别,将用logger1的输出级别(并且输出级别在设置的时候级别不能比Logger的低!!!),设置了就使用自己的输出级别
fh1 = logging.FileHandler(filename="fh.log",mode='w')

fh2 = logging.FileHandler(filename="fh.log",mode='a')
fh2.setLevel(logging.WARNING)

# 格式器
fmt1 = logging.Formatter(fmt="%(asctime)s - %(levelname)-9s - %(filename)-8s : %(lineno)s line - %(message)s")

fmt2 = logging.Formatter(fmt="%(asctime)s - %(name)s - %(levelname)-9s - %(filename)-8s : %(lineno)s line - %(message)s"
                        ,datefmt="%Y/%m/%d %H:%M:%S")

#给处理器设置格式
sh1.setFormatter(fmt1)
fh1.setFormatter(fmt2)
sh2.setFormatter(fmt2)
fh2.setFormatter(fmt1)

#记录器设置处理器
logger1.addHandler(sh1)
logger1.addHandler(fh1)
logger2.addHandler(sh2)
logger2.addHandler(fh2)

#打印日志代码
logger1.debug("This is  DEBUG of logger1 !!")
logger1.info("This is  INFO of logger1 !!")
logger1.warning("This is  WARNING of logger1 !!")
logger1.error("This is  ERROR of logger1 !!")
logger1.critical("This is  CRITICAL of logger1 !!")

logger2.debug("This is  DEBUG of logger2 !!")
logger2.info("This is  INFO of logger2 !!")
logger2.warning("This is  WARNING of logger2 !!")
logger2.error("This is  ERROR of logger2 !!")
logger2.critical("This is  CRITICAL of logger2 !!")

控制台输出:

2021-03-26 02:38:56,370 - WARNING   - advancelogging : 56 line - This is  WARNING of logger1 !!
2021-03-26 02:38:56,370 - ERROR     - advancelogging : 57 line - This is  ERROR of logger1 !!
2021-03-26 02:38:56,370 - CRITICAL  - advancelogging : 58 line - This is  CRITICAL of logger1 !!
2021/03/26 02:38:56 - logger2 - INFO      - advancelogging : 61 line - This is  INFO of logger2 !!
2021/03/26 02:38:56 - logger2 - WARNING   - advancelogging : 62 line - This is  WARNING of logger2 !!
2021/03/26 02:38:56 - logger2 - ERROR     - advancelogging : 63 line - This is  ERROR of logger2 !!
2021/03/26 02:38:56 - logger2 - CRITICAL  - advancelogging : 64 line - This is  CRITICAL of logger2 !!
<Logger logger1 (DEBUG)>
<class 'logging.Logger'>
<Logger logger2 (INFO)>
<class 'logging.Logger'>

文件fh.log输出:

2021/03/26 02:38:56 - logger1 - DEBUG     - advancelogging : 54 line - This is  DEBUG of logger1 !!
2021/03/26 02:38:56 - logger1 - INFO      - advancelogging : 55 line - This is  INFO of logger1 !!
2021/03/26 02:38:56 - logger1 - WARNING   - advancelogging : 56 line - This is  WARNING of logger1 !!
2021/03/26 02:38:56 - logger1 - ERROR     - advancelogging : 57 line - This is  ERROR of logger1 !!
2021/03/26 02:38:56 - logger1 - CRITICAL  - advancelogging : 58 line - This is  CRITICAL of logger1 !!
2021-03-26 02:38:56,370 - WARNING   - advancelogging : 62 line - This is  WARNING of logger2 !!
2021-03-26 02:38:56,370 - ERROR     - advancelogging : 63 line - This is  ERROR of logger2 !!
2021-03-26 02:38:56,370 - CRITICAL  - advancelogging : 64 line - This is  CRITICAL of logger2 !!

过滤器在代码里的应用

#定义一个过滤器
flt1 = logging.Filter("logger1") #名字就是logger记录器的名字

#关联过滤器
#1.logger关联过滤器
logger.addFilter(flt1)

#2.处理器关联过滤器
sh1.addFilter(flt1)
#fh1.addFilter(flt1)

#过滤器定义在记录器上的时候,不管你设置了任何关于这个过滤器的任何设置,都不起作用。
#过滤器定义在哪个处理器上,哪个处理器就不起作用,也就可以控制日志的输出,想要还是不想要。
#特别是在项目调试的时候,不想让日志记录到文件里去,直接在屏幕显示,就过滤到fh
#代码上线后,日志记录到文件,不用在屏幕显示,就过滤掉sh

文件配置logging编程

上述的方法都写的很死板,在小工程或者单个文件还可以,但是当项目大了,我们就必须使用配置文件的方式配置logging的信息,从而来灵活使用,主要有两种方式去配置,一种是conf文件,一种是字典文件。

import logging.config
logging.config.fileConfig("/path/to/configfile")

logging.config.dictConfig("/path/to/configfile")

yaml配置文件:

version: 1
#是否覆盖掉已经存在的loggers
disable_existing_loggers: True

formatters:

  tostrout:
    format: "%(asctime)s - %(name)s - %(levelname)-9s - %(filename)-8s : %(lineno)s line - %(message)s"
    datefmt: "%Y/%m/%d %H:%M:%S"

  tofile:
    format: "%(asctime)s - %(name)s - %(levelname)-9s - %(filename)-8s : %(lineno)s line - %(message)s"

handlers:
  sh:
    class: logging.StreamHandler
    level: WARNING
    formatter: tostrout
    stream: ext://sys.stdout

  fh:
    class: logging.handlers.TimedRotatingFileHandler
    filename: logconfdd.log
    interval: 1
    backupCount: 2
    when: D
    level: INFO
    formatter: tofile

loggers:
  logger1:
    level: DEBUG
    handlers: [sh]
    #是否往上级Logger传递,如果为yes的话,root选择了两个logger,这里的日志也会在两个logger的配置中输出,会重复。所以选No,自己记录自己的日志。
    propagate: no

  logger2:
    level: INFO
    handlers: [fh]
    propagate: no

root:
  level: DEBUG
  handlers: [sh,fh]
  propagate: no

调用代码:

# -*- coding:utf-8 -*-

import logging
import logging.config
import yaml

with open("logconf.yml", "r") as f:
    dict_conf = yaml.safe_load(f)

logging.config.dictConfig(dict_conf)
root = logging.getLogger()
logger1 = logging.getLogger('logger1')
logger2 = logging.getLogger('logger2')

#打印日志代码

root.debug("This is  DEBUG of root !!")
root.info("This is  INFO of root !!")
root.warning("This is  WARNING of root !!")
root.error("This is  ERROR of root !!")
root.critical("This is  CRITICAL of root !!")

logger1.debug("This is  DEBUG of logger1 !!")
logger1.info("This is  INFO of logger1 !!")
logger1.warning("This is  WARNING of logger1 !!")
logger1.error("This is  ERROR of logger1 !!")
logger1.critical("This is  CRITICAL of logger1 !!")

logger2.debug("This is  DEBUG of logger2 !!")
logger2.info("This is  INFO of logger2 !!")
logger2.warning("This is  WARNING of logger2 !!")
logger2.error("This is  ERROR of logger2 !!")
logger2.critical("This is  CRITICAL of logger2 !!")

标准输出:

021/03/27 12:18:58 - root - WARNING   - loggingofconfing : 19 line - This is  WARNING of root !!
2021/03/27 12:18:58 - root - ERROR     - loggingofconfing : 20 line - This is  ERROR of root !!
2021/03/27 12:18:58 - root - CRITICAL  - loggingofconfing : 21 line - This is  CRITICAL of root !!
2021/03/27 12:18:58 - logger1 - WARNING   - loggingofconfing : 25 line - This is  WARNING of logger1 !!
2021/03/27 12:18:58 - logger1 - ERROR     - loggingofconfing : 26 line - This is  ERROR of logger1 !!
2021/03/27 12:18:58 - logger1 - CRITICAL  - loggingofconfing : 27 line - This is  CRITICAL of logger1 !!

文件输出(logconfdd.log):

2021-03-27 12:18:58,301 - root - INFO      - loggingofconfing : 18 line - This is  INFO of root !!
2021-03-27 12:18:58,301 - root - WARNING   - loggingofconfing : 19 line - This is  WARNING of root !!
2021-03-27 12:18:58,301 - root - ERROR     - loggingofconfing : 20 line - This is  ERROR of root !!
2021-03-27 12:18:58,301 - root - CRITICAL  - loggingofconfing : 21 line - This is  CRITICAL of root !!
2021-03-27 12:18:58,301 - logger2 - INFO      - loggingofconfing : 30 line - This is  INFO of logger2 !!
2021-03-27 12:18:58,301 - logger2 - WARNING   - loggingofconfing : 31 line - This is  WARNING of logger2 !!
2021-03-27 12:18:58,301 - logger2 - ERROR     - loggingofconfing : 32 line - This is  ERROR of logger2 !!
2021-03-27 12:18:58,301 - logger2 - CRITICAL  - loggingofconfing : 33 line - This is  CRITICAL of logger2 !!

本文转自知呼

音乐播放器API

为WordPress网站添加一个音乐播放器,网上大部分的教程都是使用各种插件,有的插件还需要花钱买授权,用着不爽。本文用纯代码为网站添加音乐播放器,安全可靠,可以任意修改。

1、Aplayer

其实很简单,Github有很多大神开源了相关的内容。用着最舒服的,当属Aplayer了,可以去官网体验一下:

​ ​https://aplayer.js.org/​​

文档手册也很详细:

​ ​https://github.com/MoePlayer/APlayer​​

方法很简单,加载Aplayer的js和css,在想要展先的位置调用即可。Aplayer支持很多模式,上图展示的效果为吸底模式,就是在网页的页面最左下角展示。本文以吸底模式为例进行说明,如果想采用其它模式,可以根据文档手册修改代码。

2、Meting

如果只使用Aplayer,那么需要指定音乐的图片地址,mp4地址,歌词等,用着不是很方便,这时就可以使用Meting作为辅助:

​ ​https://github.com/metowolf/MetingJS​​

Meting为Aplayer提供了网易云音乐的API接口,只要获得网易云音乐歌单的ID,就可以自动加载歌单里所有的歌曲,直接调用,方便很多,当然除了网易云音乐的API,还有其他的接口。

3、开工

如果上述这些说了都不懂,没关系,跟着接下来的步骤走即可。

首先下载为各位打包好的js和css文件(下载地址)

解压后,会看到三个文件APlayer.min.css、APlayer.min.js、Meting.min.js,将两个js文件放到主题的js文件夹中,将css文件放到主题的css文件夹中。

在主题目录下的footer.php中,添加如下代码:


将代码中的wp-content/themes/construction-base改为你的WordPress主题的根目录。保存好后,刷新网页就可以看到播放器了。

1. <link rel="stylesheet" href="wp-content/themes/construction-
2. base/css/APlayer.min.css"><script src="wp-content/themes/construction-base/js/APlayer.min.js">
3. </script>
4. <div class="aplayer"
5. data-id="969649908"
6. data-fixed="true" data-
7. server="netease"
8. data-volume="0.8"
9. data-type="playlist">
10. </div>
11. <script src="wp-content/themes/construction-base/js/Meting.min.js">
12. </script>

但是这个播放器的歌单是我指定的歌单,如果想用自己的网易云音乐歌单,可以修改data-id的值,这个值的获取方法也很简单:

打开浏览器访问网页版的网易云音乐,地址栏的id参数就是对应的data-id值,自己创建一个歌单,想放什么音乐就放什么音乐。

PS:歌单更新歌曲实时更新