|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2021 nono project
4: // Licensed under nono-license.txt
5: //
6:
7: // AF_PACKET を用いたドライバ
8: // Linux 2.2 以降専用
9:
10: #include "netdriver_afpacket.h"
11: #include "autofd.h"
12: #include <ifaddrs.h>
13: #include <sys/socket.h>
14: #include <sys/ioctl.h>
15: #include <net/if.h>
16: #include <net/if_arp.h>
17:
18: // コンストラクタ
19: NetDriverAFPacket::NetDriverAFPacket(EthernetDevice *parent_, int loglevel_,
20: const std::string& ifname_)
21: : inherited("AFPacket", parent_, loglevel_)
22: {
23: ifname = ifname_;
24: if (ifname.empty()) {
25: ifname = "auto";
26: }
27: }
28:
29: // デストラクタ
30: NetDriverAFPacket::~NetDriverAFPacket()
31: {
32: Close();
33: }
34:
35: // ドライバ初期化 & オープン
36: bool
37: NetDriverAFPacket::InitDriver()
38: {
39: packet_mreq mreq {};
40: int len;
41: socklen_t so_len;
42:
43: putmsg(1, "trying afpacket...");
44: putmsg(1, "argument: ifname=\"%s\"", ifname.c_str());
45:
46: sll.sll_family = AF_PACKET;
47: sll.sll_protocol = htons(ETH_P_ALL);
48: sll.sll_ifindex = SelectInterface();
49: if (sll.sll_ifindex == 0) {
50: goto abort;
51: }
52:
53: // bind するまでの期間、このソケットにはシステムのすべての
54: // インタフェースからのパケットが着信することに注意。
55: fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
56: if (fd < 0) {
57: errmsg = string_format("%s: %s", "socket(AF_PACKET)", strerror(errno));
58: putmsg(1, "%s", errmsg.c_str());
59: if (errno == EPERM) {
60: // Linux では setcap(8) が必要。分かりづらいのでメッセージを出すが
61: // その例示より先に errmsg を表示したい。
62: warnx("%s", errmsg.c_str());
63: errmsg.clear();
64:
65: fprintf(stderr,
66: " ** Set CAP_NET_RAW capability to the nono executable file.\n"
67: " ** ex) sudo setcap cap_net_raw=ep path/to/%s\n",
68: getprogname());
69: }
70: return false;
71: }
72:
73: if (bind(fd, (const sockaddr *)&sll, sizeof(sll)) != 0) {
74: errmsg = string_format("bind(%s): %s", ifname.c_str(), strerror(errno));
75: goto abort;
76: }
77:
78: // PROMISC セット
79: mreq.mr_ifindex = sll.sll_ifindex;
80: mreq.mr_type = PACKET_MR_PROMISC;
81: if (setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP,
82: &mreq, sizeof(mreq)) != 0) {
83: errmsg = string_format("%s: %s", "set PROMISC", strerror(errno));
84: goto abort;
85: }
86:
87: so_len = sizeof(len);
88: if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &len, &so_len) != 0) {
89: errmsg = string_format("%s: %s",
90: "getsockopt(SO_RCVBUF)", strerror(errno));
91: goto abort;
92: }
93:
94: putmsg(1, "opened for %s", ifname.c_str());
95: putmsg(1, "warning: communicating with the localhost is not possible");
96:
97: // AFPacket では ifup スクリプトは実行しない
98:
99: return true;
100:
101: abort:
102: putmsg(1, "%s", errmsg.c_str());
103: Close();
104: return false;
105: }
106:
107: // クローズ
108: // (private)
109: void
110: NetDriverAFPacket::Close()
111: {
112: if (IsOpen()) {
113: close(fd);
114: fd = -1;
115: }
116: }
117:
118: // モニタ (ドライバ依存情報のみ)
119: void
120: NetDriverAFPacket::MonitorUpdateMD(TextScreen& screen)
121: {
122: screen.Print(0, 1, "Interface: %s", ifname.c_str());
123: }
124:
125: // パケットを送信する
126: bool
127: NetDriverAFPacket::SendPacket(const std::vector<uint8>& data)
128: {
129: int n;
130:
131: assert(IsOpen());
132:
133: putlog(2, "SendPacket %zu bytes", data.size());
134: tx_pkts++;
135: tx_bytes += data.size();
136:
137: n = sendto(fd, data.data(), data.size(), 0,
138: (const sockaddr *)&sll, sizeof(sll));
139: if (n == -1) {
140: warn("NetDriverAFPacket.SendPacket: sendto failed: fd=%d datalen=%zu",
141: fd, data.size());
142: return false;
143: }
144:
145: if (n < (int)data.size()) {
146: return false;
147: }
148: return true;
149: }
150:
151: // パケットを受信する
152: ssize_t
153: NetDriverAFPacket::RecvPacket()
154: {
155: uint8 buf[10240];
156: ssize_t rv;
157:
158: rv = recv(fd, buf, sizeof(buf), 0);
159: if (rv > 0) {
160: RecvEnqueue(buf, rv);
161: }
162: return rv;
163: }
164:
165: // インタフェース番号を返す。
166: // auto のときは選択したインタフェース名を ifname にセットする。
167: // インタフェースが決定できないときは errmsg をセットして 0 を返す。
168: int
169: NetDriverAFPacket::SelectInterface()
170: {
171: int ifindex = 0;
172: struct ifaddrs *ifa_list, *ifa;
173:
174: if (ifname == "auto") {
175: // インタフェースを探す
176: int level = 1;
177:
178: if (getifaddrs(&ifa_list) == -1) {
179: errmsg = "getifaddrs";
180: return 0;
181: }
182:
183: for (ifa = ifa_list; ifa; ifa = ifa->ifa_next) {
184: if ((ifa->ifa_flags & IFF_UP) == 0) {
185: continue;
186: }
187: if (ifa->ifa_addr == NULL) {
188: continue;
189: }
190: // AF_PACKET をサポートするインタフェースを探す
191: if (ifa->ifa_addr->sa_family != AF_PACKET) {
192: continue;
193: }
194:
195: // ETHERNET を探す
196: sockaddr_ll *sa = (sockaddr_ll *)ifa->ifa_addr;
197: if (sa->sll_hatype != ARPHRD_ETHER) {
198: continue;
199: }
200:
201: if (ifindex == 0) {
202: // 最初に見つかったものを採用
203: ifname = ifa->ifa_name;
204: ifindex = sa->sll_ifindex;
205: } else {
206: // インタフェース候補が 2個以上ある場合はログレベル 0 にしたい
207: level = 0;
208: break;
209: }
210: }
211: freeifaddrs(ifa_list);
212:
213: if (ifindex == 0) {
214: errmsg = "auto could not find a suitable interface";
215: return ifindex;
216: }
217:
218: putmsg(level, "auto-selected ifname \"%s\"", ifname.c_str());
219:
220: } else {
221: ifindex = if_nametoindex(ifname.c_str());
222: if (ifindex == 0) {
223: errmsg = string_format("interface %s not found", ifname.c_str());
224: }
225: }
226: return ifindex;
227: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.