Linux soft lockup時遠端除錯的可能性
SSH 已經不能指望了,怎麼辦?
想法簡單,不足道,僅僅是個POC ,也希望能有人一起討論:
註冊一個新的四層協議,除了TCP/UDP/ICMP 等熟知協議之外的新協議,這是為了避免每一個資料包都要經過過濾,避免影響效能。
事先分配skb ,避免當事故發生時回送資訊時分配 skb 失敗。
好了,看程式碼,先給出載入核心的程式碼,這個程式碼的大部分都是我從網上抄來的,並不是自己寫的,我只是重組了邏輯:
# include <net/protocol.h>#include <linux/if_ether.h>#include <linux/ip.h>#include <linux/udp.h>
#define IPPROTO_MYPROTO 123#define QUOTA 30
struct sk_buff *eskb[QUOTA];
static int quota = QUOTA - 1;//module_param(quota, int, 0644);//MODULE_PARM_DESC(quota, "soft_lockup");
unsigned short _csum(unsigned short* data, int len){
int pad = 0;
int i = 0;
unsigned short ret = 0;
unsigned int sum = 0;
if (len % 2 != 0)
pad = 1;
len /= 2;
for ( i = 0; i < len; i++) {
sum += data[i];
}
if (pad == 1)
sum += ((unsigned char*)(data + len))[0] ;
sum = (sum & 0xffff) + (sum >> 16);
sum += (sum >> 16);
ret = ~sum;
return ret;}
int myproto_rcv(struct sk_buff *skb){
struct udphdr *uh, *euh;
struct iphdr *iph, *eiph;
struct ethhdr *eh, *ethh;
char esaddr[6];
unsigned char *pos;
if (quota < 0) {
goto end;
}
iph = ip_hdr(skb);
uh = udp_hdr(skb);
eh = (struct ethhdr *)(((unsigned char *)iph) - sizeof(struct ethhdr));
// 出事的時候,直接構造已經分配的 skb
eskb[quota]->ip_summed = CHECKSUM_NONE;
eskb[quota]->protocol = htons(ETH_P_IP);
eskb[quota]->priority = 0;
eskb[quota]->dev = skb->dev;
eskb[quota]->pkt_type = PACKET_OTHERHOST;
skb_reserve(eskb[quota], 1300 + sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr));
pos = skb_push(eskb[quota], 1300);
strcpy(pos, "abcdefghijk123456789");
pos = skb_push(eskb[quota], sizeof(struct udphdr));
skb_reset_transport_header(eskb[quota]);
euh = (struct udphdr *)pos;
euh->source = uh->dest;
euh->dest = uh->source;
euh->len = htons(1300 + sizeof(struct udphdr));
euh->check = 0;
memcpy(pos - 12, &iph->daddr, 4);
memcpy(pos - 8, &iph->saddr, 4);
((unsigned short *)(pos - 4))[0] = 0x1100;
memcpy(pos - 2, &euh->len, sizeof(euh->len));
euh->check = _csum((unsigned short*)(pos - 12), 12 + 1300 + sizeof(struct udphdr));
pos = skb_push(eskb[quota], sizeof(struct iphdr));
skb_reset_network_header(eskb[quota]);
eiph = (struct iphdr *)pos;
eiph->version = 4;
eiph->ihl = 5;
eiph->tos = 0;
eiph->tot_len = htons(1300 + sizeof(struct udphdr) + sizeof(struct iphdr));
eiph->id = 0x1122;
eiph->frag_off = 0;
eiph->ttl = 64;
eiph->protocol = 0x11;
eiph->check = 0;
eiph->saddr = iph->daddr;
eiph->daddr = iph->saddr;
eiph->check = _csum((unsigned short*)pos, sizeof(struct iphdr));
pos = skb_push(eskb[quota], sizeof(struct ethhdr));
skb_reset_mac_header(eskb[quota]);
ethh = (struct ethhdr *)pos;
memcpy(esaddr, eh->h_dest, 6);
memcpy(ethh->h_dest, eh->h_source, ETH_ALEN);
memcpy(ethh->h_source, eh->h_dest, ETH_ALEN);
ethh->h_proto = htons(ETH_P_IP);
printk("myproto_rcv is called, length:%d %x %x\n", skb->len, esaddr[2], esaddr[3]);
dev_queue_xmit(eskb[quota]);
quota --;
end:
kfree_skb(skb);
return 0;}
int myproto_rcv_err(struct sk_buff *skb, unsigned int err){
printk("myproto_rcv is called:%d\n", err);
kfree_skb(skb);
return 0;}
static const struct net_protocol myproto_protocol = {
.handler = myproto_rcv,
.err_handler = myproto_rcv_err,
.no_policy = 1,
.netns_ok = 1,};
int init_module(void){
int ret = 0, i;
// 事先分配 skb
for (i = 0; i < QUOTA; i++) {
eskb[i] = alloc_skb(1300 + sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr), GFP_ATOMIC);
if (eskb[i] == NULL) {
//int j;
//for () {
//}
printk("alloc failed\n");
return -1;
// 註冊 123 協議,它不是 TCP,UDP,ICMP
ret = inet_add_protocol(&myproto_protocol, IPPROTO_MYPROTO);
if (ret) {
printk("failed\n");
return ret;
printk("successful\n");
return 0;}
void cleanup_module(void){
int rc = 0;
inet_del_protocol(&myproto_protocol, IPPROTO_MYPROTO);
//for (i = quota; i >=0; i--) {
//kfree_skb(eskb[i]);
//}
return;}
int init_module(void);void cleanup_module(void);MODULE_LICENSE("GPL");
來來來,看一下客戶端的程式碼。
客戶端需要透過raw 套接字傳送一個 “ 請求 ” ,跟單網它的傳輸層協議是 123 ,然而回復的卻是一個標準的 UDP 報文,所以客戶端需要在該 UDP 上接收。
程式碼如下:
#include <stdlib.h>#include <unistd.h>#include <stdio.h>#include <string.h>#include <sys/socket.h>#include <netinet/in.h>#include <linux/ip.h>#include <linux/udp.h>
#define PCKT_LEN 8192
unsigned short csum(unsigned short *buf, int nwords){
unsigned long sum;
for(sum=0; nwords>0; nwords--)
sum += *buf++;
sum = (sum >> 16) + (sum &0xffff);
sum += (sum >> 16);
return (unsigned short)(~sum);}
int main(int argc, char const *argv[]){
int sd, usd;
struct iphdr *ip;
struct udphdr *udp;
struct sockaddr_in sin, usin, csin;
u_int16_t src_port, dst_port;
u_int32_t src_addr, dst_addr;
int >
const int *val = &one;
int dlen, rlen, clen = sizeof(csin);
char *data;
char buf[1300];
if (argc != 6) {
printf("Usage: %s <source hostname/IP> <source port> <target hostname/IP> <target port>\n", argv[0]);
exit(1);
src_addr = inet_addr(argv[1]);
dst_addr = inet_addr(argv[3]);
src_port = atoi(argv[2]);
dst_port = atoi(argv[4]);
dlen = atoi(argv[5]);
data = malloc(sizeof(struct iphdr) + sizeof(struct udphdr) + dlen);
ip = (struct iphdr *)data;
udp = (struct udphdr *)(data + sizeof(struct iphdr));
sd = socket(PF_INET, SOCK_RAW, IPPROTO_UDP);
if (sd < 0) {
perror("raw error");
exit(2);
if(setsockopt(sd, IPPROTO_IP, IP_HDRINCL, val, sizeof(one)) < 0) {
perror("setsockopt() error");
exit(2);
sin.sin_family = AF_INET;
sin.sin_port = htons(dst_port);
sin.sin_addr.s_addr = inet_addr(argv[3]);
ip->ihl = 5;
ip->version = 4;
ip->tos = 16; // low delay
ip->tot_len = sizeof(struct iphdr) + sizeof(struct udphdr) + dlen;
ip->id = htons(54321);
ip->ttl = 64; // hops
ip->protocol = 123; // UDP
ip->saddr = src_addr;
ip->daddr = dst_addr;
udp->source = htons(src_port);
udp->dest = htons(dst_port);
udp->len = htons(sizeof(struct udphdr) + dlen);
ip->check = csum((unsigned short *)data, sizeof(struct iphdr) + sizeof(struct udphdr) + dlen);
usd = socket(AF_INET, SOCK_DGRAM, 0);
if (usd < 0) {
perror("usd error");
bzero(&usin, sizeof(usin));
usin.sin_family = AF_INET;
usin.sin_port = htons(src_port);
usin.sin_addr.s_addr = inet_addr(argv[1]);
if (bind(usd, (struct sockaddr *)&usin, sizeof(usin))) {
perror("bind error");
exit(2);
if (sendto(sd, data, ip->tot_len, 0, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
perror("sendto()");
exit(3);
rlen = recvfrom(usd, buf, sizeof(buf), 0, (struct sockaddr*)&csin, &clen);
printf("recv:%s\n", buf);
close(sd);
return 0;}
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69946337/viewspace-2744291/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- vscode配置遠端linux系統除錯VSCodeLinux除錯
- Pycharm遠端除錯PyCharm除錯
- PHPSTROM遠端除錯PHP除錯
- 遠端除錯在Linux車機中的應用除錯Linux
- windows上通過IDA遠端除錯linux程式Windows除錯Linux
- IDEA、ECLIPSE遠端除錯IdeaEclipse除錯
- VisualStudio 如何 SSH 遠端除錯 Linux 的 dotnet 應用的啟動除錯Linux
- pycharm 遠端除錯之二PyCharm除錯
- Xdebug+PhpStorm 遠端除錯PHPORM除錯
- debug技巧之遠端除錯除錯
- 本地除錯遠端服務除錯
- vscode遠端除錯c++VSCode除錯C++
- 使用IDEA遠端debug除錯Idea除錯
- Dapr 遠端除錯之 Nocalhost除錯
- 基於 Scrcpy 的遠端除錯方案除錯
- VS - 打斷點/本地除錯/遠端除錯 問題斷點除錯
- phpstorm 遠端除錯 homstead 程式碼PHPORM除錯
- WebStorm遠端除錯Node.jsWebORM除錯Node.js
- Homestead+PhpStorm+Xdebug 遠端除錯PHPORM除錯
- 使用IDEA進行遠端除錯Idea除錯
- 使用Xdebug進行遠端除錯除錯
- vs搭建遠端除錯環境除錯
- windows 遠端連線Linux進行開發與除錯MySQLWindowsLinux除錯MySql
- Windows 使用VSCode遠端連線到Linux開發除錯MySQLWindowsVSCodeLinux除錯MySql
- 使用Intellij IDEA遠端除錯Spark程式IntelliJIdea除錯Spark
- vsc 如何除錯遠端python程式碼除錯Python
- Pycharm同步遠端伺服器除錯PyCharm伺服器除錯
- 遠端除錯 Android 裝置網頁除錯Android網頁
- IntelliJ IDEA遠端除錯Elasticsearch6.1.2IntelliJIdea除錯Elasticsearch
- windows系統vscode遠端除錯MySQLWindowsVSCode除錯MySql
- Pycharm連線遠端伺服器並實現遠端除錯PyCharm伺服器除錯
- 一鍵執行實時的修改,讓Qt遠端除錯更簡單QT除錯
- 使用Clion優雅的完全遠端自動同步和遠端除錯c++除錯C++
- Linux系統下執行Jar包以及idea遠端除錯jar包LinuxJARIdea除錯
- IntelliJ IDEA引入了VsCode的Docker遠端除錯功能IntelliJIdeaVSCodeDocker除錯
- Android Studio怎麼遠端除錯裝置?Android除錯
- 智慧小程式檔案館——遠端除錯除錯
- 原來 Java 遠端除錯如此簡單Java除錯