AF_PACKET套接字解密 --- 01

本文深入探讨了AF_PACKET套接字的工作原理,包括其在Linux内核中的创建过程、如何绑定到网络设备以及如何注册接收回调函数。通过跟踪源码,揭示了AF_PACKET与其他套接字的不同之处。
AF_PACKET套接字解密 --- 01  2012-05-23 22:08:23

分类: LINUX

使用socket(AF_PACKET, SOCK_RAW, ETH_P_ALL)创建的套接字到底为何于众不同,今日追踪了一下。使用Linux 3.2.5版内核

net/socket.c

点击(此处)折叠或打开

  1. SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol)
  2. {
  3. ......
  4.     retval = sock_create(family,  type, protocol, &sock);
  5. ......
  6. }

点击(此处)折叠或打开

  1. int sock_create(int family, int type, int protocol, struct socket **res)
  2. {
  3.     return __sock_create(current->nsproxy->net_ns, family, type, protocol, res, 0);
  4. }

点击(此处)折叠或打开

  1. int __sock_create(struct net *net, int family, int type, int protocol,
  2. struct socket **res, int kern)
  3. {
  4. ......
  5.     pf = rcu_dereference(net_families[family]);
  6. ......
  7.     err = pf->create(net, sock, protocol, kern);
  8. ......
  9. }

点击(此处)折叠或打开

  1. static const struct net_proto_family __rcu *net_families[NPROTO] __read_mostly;

  2. int sock_register(const struct net_proto_family *ops)
  3. {
  4. ......
  5.     if (rcu_dereference_protected(net_families[ops->family],
  6.                  lockdep_is_held(&net_family_lock)))
  7.         err = -EEXIST;
  8.     else {
  9.         rcu_assign_pointer(net_families[ops->family], ops);
  10.         err = 0;
  11.     }
  12. ......
  13. }

net/packet/af_packet.c

点击(此处)折叠或打开

  1. static const struct net_proto_family packet_family_ops = {
  2.     .family =    PF_PACKET,
  3.     .create =    packet_create,
  4.     .owner    =    THIS_MODULE,
  5. };

  6. static int __init packet_init(void)
  7. {
  8. ......
  9.     sock_register(&packet_family_ops);
  10. ......
  11. }

  12. module_init(packet_init);

点击(此处)折叠或打开

  1. static int packet_create(struct net *net, struct socket *sock, int protocol,
  2.              int kern)
  3. {
  4.     struct sock *sk;
  5.     struct packet_sock *po;
  6.     __be16 proto = (__force __be16)protocol; /* weird, but documented */
  7. ......
  8.     sk = sk_alloc(net, PF_PACKET, GFP_KERNEL, &packet_proto);
  9. ......
  10.     sock->ops = &packet_ops;
  11. ......
  12.     po = pkt_sk(sk);
        sk->sk_family = PF_PACKET;
  13.     po->num = proto;
  14. ......
  15.     po->prot_hook.func = packet_rcv;
  16. ......
  17.     po->prot_hook.af_packet_priv = sk;
  18.     if (proto) {
  19.         po->prot_hook.type = proto;
  20.         register_prot_hook(sk);
  21.     }
  22. ......
  23. }

AF_PACKET套接字的功能来源于prot_hook,其本身是struct packet_type类型:
1:type成员设定为了socket()传递的参数(这里是ETH_P_ALL)
2:过滤得到的包的处理函数保存于func成员,这里被设定为 packet_rcv()
3:dev成员用于对net_device的过滤,可以在bind()中指定


点击(此处)折叠或打开

  1. static int packet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
  2. {
  3. ......
  4.     if (sll->sll_ifindex) {
  5.         err = -ENODEV;
  6.         dev = dev_get_by_index(sock_net(sk), sll->sll_ifindex);
  7.         if (dev == NULL)
  8.             goto out;
  9.     }
  10.     err = packet_do_bind(sk, dev, sll->sll_protocol ? : pkt_sk(sk)->num);
  11. ......
  12. }

点击(此处)折叠或打开

  1. static int packet_do_bind(struct sock *sk, struct net_device *dev, __be16 protocol)
  2. {
  3.     struct packet_sock *po = pkt_sk(sk);
  4. ......
  5.     po->prot_hook.dev = dev;

  6.     po->ifindex = dev ? dev->ifindex : 0;
  7. ......
  8.     if (!dev || (dev->flags & IFF_UP)) {
  9.         register_prot_hook(sk);
  10. ......
  11. }

可见在bind()中若指定了绑定的net_device同样会触发prot_hook的注册动作。


点击(此处)折叠或打开

  1. static void register_prot_hook(struct sock *sk)
  2. {
  3.     struct packet_sock *po = pkt_sk(sk);
  4.     if (!po->running) {
  5.         if (po->fanout)
  6.             __fanout_link(sk, po);
  7.         else
  8.             dev_add_pack(&po->prot_hook);
  9.         sock_hold(sk);
  10.         po->running = 1;
  11.     }
  12. }

net/core/dev.c

点击(此处)折叠或打开

  1. void dev_add_pack(struct packet_type *pt)
  2. {
  3.     struct list_head *head = ptype_head(pt);
  4.     spin_lock(&ptype_lock);
  5.     list_add_rcu(&pt->list, head);
  6.     spin_unlock(&ptype_lock);
  7. }

点击(此处)折叠或打开

  1. static struct list_head ptype_all __read_mostly;    /* Taps */

  2. static inline struct list_head *ptype_head(const struct packet_type *pt)
  3. {
  4.     if (pt->type == htons(ETH_P_ALL))
  5.         return &ptype_all;
  6.     else
  7.         return &ptype_base[ntohs(pt->type) & PTYPE_HASH_MASK];
  8. }

历尽千辛万苦,终于知道AF_PACKET套接字把自己的prot_hook挂到了ptype_all链表上或ptype_base链表上。至于prot_hook怎么发挥作用进行监听,请听下回分解!
import cv2 import socket import numpy as np import struct import sqlite3 from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes from cryptography.hazmat.primitives import padding from cryptography.hazmat.backends import default_backend key = b'0123456789abcdef0123456789abcdef' iv = b'0123456789abcdef' # 连接到数据库 conn = sqlite3.connect('video.db') cursor = conn.cursor() # 创建videos表 cursor.execute("CREATE TABLE IF NOT EXISTS videos (id INTEGER PRIMARY KEY, path TEXT)") path = 'M:/img/xinxixitong.avi' fourcc = cv2.VideoWriter_fourcc(*'XVID') out = cv2.VideoWriter(path, fourcc, 30, (640, 480)) # 解密函数 def dt_f(ciphertext, key, iv): # 创建 AES 解密器 dt = Cipher(algorithms.AES(key), modes.CBC(iv), backend=default_backend()).decryptor() # 解密图像 padded_data = dt.update(ciphertext) + dt.finalize() # 移除填充 unpadder = padding.PKCS7(128).unpadder() unpadded_data = unpadder.update(padded_data) + unpadder.finalize() return unpadded_data # 服务端IP和端口号 HOST = '0.0.0.0' # 任意IP地址 PORT = 6666 # 创建套接字对象 with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sk: sk.bind((HOST, PORT)) sk.listen(5) print('等待连接...') # 接受连接请求 client_conn, addr = sk.accept() with client_conn: print('与', addr,'相连接') data_buffer = b'' # 缓存数据 while True: data = client_conn.recv(6) #如果没有数据传输则停止 if not data: break size = struct.unpack('!I', data)[0] # 接收到的帧数据 data = b'' while len(data) < size: packet = client_conn.recv(size - len(data)) if not packet: break data += packet # 解密帧 dted_f = dt_f(data, key, iv) # data_buffer += dt_f # 添加到缓存中 # 将解密后的 bytes 数据转换为图像帧 dted_f = np.frombuffer(dted_f, dtype=np.uint8).reshape(480, 640, 3) # 显示解密后的帧 cv2.imshow("2021218000_dted_Server", dted_f) out.write(dted_f) if cv2.waitKey(1) in [ord('q'),27]: out.release() break cursor.execute('INSERT INTO videos (path) VALUES (?)', (path,)) conn.commit() conn.close() cv2.destroyAllWindows()
06-10
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值