Linuxカーネルでinet_add_protocol()という関数を使うとオレオレプロトコルを簡単に追加できるので遊んでみました。
以下が作ったカーネルモジュールです。
#include <linux/module.h> #include <linux/kernel.h> #include <linux/kmod.h> #include <net/protocol.h> MODULE_DESCRIPTION("simple Eject protocol"); MODULE_AUTHOR("masami256"); MODULE_LICENSE("GPL"); #define IPPROTO_NET_EJECT 123 int eject_handler(struct sk_buff *skb) { if (skb->data && !strncmp(skb->data, "eject", 5)) { char *argv[5] = {"/bin/sh", "-c", "/usr/bin/eject", "cdrom", NULL}; char *envp[1] = {NULL}; printk(KERN_INFO "Execute /usr/bin/eject cdrom\n"); call_usermodehelper("/bin/sh", argv, envp, UMH_NO_WAIT); } else { printk(KERN_INFO "protocol receve unknown data\n"); } kfree_skb(skb); return 0; } const struct net_protocol net_eject_protocol = { .handler = eject_handler, .no_policy = 1, .netns_ok = 1 }; static int net_eject_init(void) { int ret = inet_add_protocol(&net_eject_protocol, IPPROTO_NET_EJECT); if (!ret) printk(KERN_INFO "Add protocol success\n"); return ret; } static void net_eject_cleanup(void) { inet_del_protocol(&net_eject_protocol, IPPROTO_NET_EJECT); printk(KERN_INFO "module unloaded\n"); } module_init(net_eject_init); module_exit(net_eject_cleanup);
あとはデータファイルを適当な名前で作って以下の内容にしておきます。
eject
ここではpayloadとしておきます。
そして、sendipコマンドで実行します。
sudo sendip -p ipv4 -is 0 -f payload -ip 123 192.168.1.21
すると192.168.1.21のCDドライブが開きます。
inet_add_protocol()はipv4ならnet/ipv4/protocol.cに定義されています。これを見るとプロトコルは最大256要素のハッシュテーブルみたいです。
ファイルを見るとこんな感じになっています。
31 const struct net_protocol __rcu *inet_protos[MAX_INET_PROTOS] __read_mostly; 32 const struct net_offload __rcu *inet_offloads[MAX_INET_PROTOS] __read_mostly; 33 34 /* 35 * Add a protocol handler to the hash tables 36 */ 37 38 int inet_add_protocol(const struct net_protocol *prot, unsigned char protocol) 39 { 40 if (!prot->netns_ok) { 41 pr_err("Protocol %u is not namespace aware, cannot register.\n", 42 protocol); 43 return -EINVAL; 44 } 45 46 return !cmpxchg((const struct net_protocol **)&inet_protos[protocol], 47 NULL, prot) ? 0 : -1; 48 }
Ejectはプロトコルの番号は123にしました。この数値はどっから見つけたかというとuapi/linux/in.hにあった定義を見て123が空いてたのでそれにしてますw
25 enum { 26 IPPROTO_IP = 0, /* Dummy protocol for TCP */ 27 #define IPPROTO_IP IPPROTO_IP 28 IPPROTO_ICMP = 1, /* Internet Control Message Protocol */ 29 #define IPPROTO_ICMP IPPROTO_ICMP 30 IPPROTO_IGMP = 2, /* Internet Group Management Protocol */ 31 #define IPPROTO_IGMP IPPROTO_IGMP 32 IPPROTO_IPIP = 4, /* IPIP tunnels (older KA9Q tunnels use 94) */ 33 #define IPPROTO_IPIP IPPROTO_IPIP 34 IPPROTO_TCP = 6, /* Transmission Control Protocol */ 35 #define IPPROTO_TCP IPPROTO_TCP 36 IPPROTO_EGP = 8, /* Exterior Gateway Protocol */ 37 #define IPPROTO_EGP IPPROTO_EGP 38 IPPROTO_PUP = 12, /* PUP protocol */ 39 #define IPPROTO_PUP IPPROTO_PUP 40 IPPROTO_UDP = 17, /* User Datagram Protocol */ 41 #define IPPROTO_UDP IPPROTO_UDP 42 IPPROTO_IDP = 22, /* XNS IDP protocol */ 43 #define IPPROTO_IDP IPPROTO_IDP 44 IPPROTO_TP = 29, /* SO Transport Protocol Class 4 */ 45 #define IPPROTO_TP IPPROTO_TP 46 IPPROTO_DCCP = 33, /* Datagram Congestion Control Protocol */ 47 #define IPPROTO_DCCP IPPROTO_DCCP 48 IPPROTO_IPV6 = 41, /* IPv6-in-IPv4 tunnelling */ 49 #define IPPROTO_IPV6 IPPROTO_IPV6 50 IPPROTO_RSVP = 46, /* RSVP Protocol */ 51 #define IPPROTO_RSVP IPPROTO_RSVP 52 IPPROTO_GRE = 47, /* Cisco GRE tunnels (rfc 1701,1702) */ 53 #define IPPROTO_GRE IPPROTO_GRE 54 IPPROTO_ESP = 50, /* Encapsulation Security Payload protocol */ 55 #define IPPROTO_ESP IPPROTO_ESP 56 IPPROTO_AH = 51, /* Authentication Header protocol */ 57 #define IPPROTO_AH IPPROTO_AH 58 IPPROTO_MTP = 92, /* Multicast Transport Protocol */ 59 #define IPPROTO_MTP IPPROTO_MTP 60 IPPROTO_BEETPH = 94, /* IP option pseudo header for BEET */ 61 #define IPPROTO_BEETPH IPPROTO_BEETPH 62 IPPROTO_ENCAP = 98, /* Encapsulation Header */ 63 #define IPPROTO_ENCAP IPPROTO_ENCAP 64 IPPROTO_PIM = 103, /* Protocol Independent Multicast */ 65 #define IPPROTO_PIM IPPROTO_PIM 66 IPPROTO_COMP = 108, /* Compression Header Protocol */ 67 #define IPPROTO_COMP IPPROTO_COMP 68 IPPROTO_SCTP = 132, /* Stream Control Transport Protocol */ 69 #define IPPROTO_SCTP IPPROTO_SCTP 70 IPPROTO_UDPLITE = 136, /* UDP-Lite (RFC 3828) */ 71 #define IPPROTO_UDPLITE IPPROTO_UDPLITE 72 IPPROTO_RAW = 255, /* Raw IP packets */ 73 #define IPPROTO_RAW IPPROTO_RAW 74 IPPROTO_MAX 75 };
Ejectの実行にcall_usermodehelper()でユーザランドのコマンドを使っていて、カーネル内で完結していないのがスタイリッシュじゃないですね(´・ω・`)
リモートのPCで実行する場合はiptablesの設定も忘れずに。
プロのための Linuxシステム構築・運用技術 (Software Design plus)
- 作者: 中井悦司
- 出版社/メーカー: 技術評論社
- 発売日: 2010/12/22
- メディア: 大型本
- 購入: 21人 クリック: 411回
- この商品を含むブログ (38件) を見る