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));// 出事的时候,间接结构曾经调配的skbeskb[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;// 当时调配skbfor (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,ICMPret = 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跟单网gendan5.com套接字发送一个“申请”,它的传输层协定是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 one = 1;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 delayip->tot_len = sizeof(struct iphdr) + sizeof(struct udphdr) + dlen;ip->id = htons(54321);ip->ttl = 64; // hopsip->protocol = 123; // UDPip->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;}