|
|
1.1 root 1: //
2: // nono
1.1.1.2 root 3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
1.1 root 5: //
6:
7: #include "netdriver_tap.h"
1.1.1.3 root 8: #include "autofd.h"
1.1 root 9: #include <fcntl.h>
10: #include <poll.h>
11: #include <sys/ioctl.h>
12: #include <sys/socket.h>
13: #if defined(__linux__)
14: #include <linux/if.h>
15: #include <linux/if_tun.h>
1.1.1.3 root 16: #elif defined(__OpenBSD__)
17: #include <net/if_tun.h>
1.1 root 18: #else
19: #include <ifaddrs.h>
20: #include <net/if.h>
21: #include <net/if_dl.h>
22: #include <net/if_tap.h>
23: #endif
24:
1.1.1.3 root 25: // Linux
26: // /dev/net/tun をオープンし、ioctl(TUNSETIFF) を発行すると tap
27: // インタフェースが生えて、そのインタフェース名が返ってくる。
28: //
29: // OpenBSD
30: // /dev/tapN をオープンする。インタフェース名は対応する tapN のはず。
31: //
32: // NetBSD (dynamic)
33: // /dev/tap をオープンすると tap インタフェースが生えるので
34: // ioctl(TAPGIFNAME) でインタフェース名を取得する。
35: // /dev/tapN をオープンする方式も使える。
36:
1.1 root 37: // コンストラクタ
1.1.1.5 ! root 38: NetDriverTap::NetDriverTap(EthernetDevice *parent_, int loglevel_,
1.1.1.3 root 39: const std::string& devpath_)
1.1.1.5 ! root 40: : inherited("Tap", parent_, loglevel_)
1.1 root 41: {
1.1.1.3 root 42: devpath = devpath_;
1.1.1.5 ! root 43: if (devpath.empty()) {
! 44: devpath = "auto";
! 45: }
1.1 root 46: }
47:
48: // デストラクタ
49: NetDriverTap::~NetDriverTap()
50: {
51: Close();
52: }
53:
1.1.1.5 ! root 54: // ドライバ初期化 & オープン
1.1 root 55: bool
1.1.1.5 ! root 56: NetDriverTap::InitDriver()
1.1 root 57: {
1.1.1.3 root 58: bool r;
59:
1.1.1.5 ! root 60: putmsg(1, "trying tap...");
! 61: putmsg(1, "argument: devpath=\"%s\"", devpath.c_str());
1.1.1.3 root 62:
63: // デバイス名や tap の作り方は OS ごとに異なる。
64: // もっと言えば、なんか適当にオープンしてほしいデフォルト挙動も全部違う。
65: //
66: // いずれの Open*() 関数も (必要なら) devpath に応じてデバイスをオープンし
67: // 成功すれば fd にデバイスのディスクリプタ、ifname に作成した
68: // インタフェース名をセットして true を返すこと。
1.1.1.5 ! root 69: // 失敗すればデバイスをクローズして putmsg() を出力し false を返すこと。
! 70: // warnx() での出力は行わない(この後他ドライバで成功するかも知れないので)。
! 71: // その場合の ifname は不問。
1.1.1.3 root 72: #if defined(__linux__)
73: // Linux はたぶん固定
74: r = OpenLinux();
1.1.1.5 ! root 75: if (r == false) {
! 76: // 単独試行なのでここで終了
! 77: return false;
! 78: }
1.1.1.3 root 79:
80: #elif defined(__OpenBSD__)
81: if (devpath == "auto") {
82: // 指定されてなければ、tapN を順に試す
83: r = OpenNumbered();
1.1.1.5 ! root 84: // FALLTHROUGH
1.1.1.3 root 85: } else {
86: // ご指名の場合
87: r = OpenDirect();
1.1.1.5 ! root 88: if (r == false) {
! 89: // 単独試行なのでここで終了
! 90: return false;
! 91: }
1.1.1.3 root 92: }
93:
94: #else
95: if (devpath == "auto") {
96: // 指定されてなければ、tap、tapN の順で試すか
97: r = OpenCloning();
98: if (r == false) {
99: r = OpenNumbered();
100: }
1.1.1.5 ! root 101: // FALLTHROUGH
1.1.1.3 root 102: } else {
103: // 指定されている場合 tap か tapN かで対応が違う
104: if (devpath == "/dev/tap") {
105: // tap ご指名の場合
106: r = OpenCloning();
107: } else {
108: // それ以外でご指名の場合
109: r = OpenDirect();
1.1.1.5 ! root 110: }
! 111: if (r == false) {
! 112: // 単独試行なのでここで終了
! 113: return false;
1.1.1.3 root 114: }
115: }
116:
117: #endif
118: if (r == false) {
1.1.1.5 ! root 119: // 複数試した結果見付からない時だけこのメッセージを出したい
! 120: errmsg = "no tap devices available";
! 121: putmsg(1, "%s", errmsg.c_str());
1.1.1.3 root 122: return false;
123: }
124: // ここで ifname に作成したインタフェース名が入っているはず
1.1.1.5 ! root 125: putmsg(1, "opened %s for %s", devpath.c_str(), ifname.c_str());
1.1.1.3 root 126:
127: // 最後に ifup スクリプトがあれば実行
128: if (!Run_ifup()) {
129: // どこまで実行できたか分からないので念のため ifdown も呼ぶ
130: Close();
131: return false;
132: }
133:
134: return true;
135: }
136:
137: #if defined(__linux__)
138: // tap インタフェースを作成する。Linux の場合。
1.1.1.5 ! root 139: // エラーの場合は putmsg ログを出力し、errmsg をセットして false を返す。
1.1.1.3 root 140: bool
141: NetDriverTap::OpenLinux()
142: {
1.1 root 143: struct ifreq ifr;
144: int r;
145:
1.1.1.3 root 146: // 指定がなければデフォルトパス
1.1.1.4 root 147: if (devpath == "auto") {
1.1.1.3 root 148: devpath = "/dev/net/tun";
1.1.1.5 ! root 149: putmsg(1, "auto-selected devpath: \"%s\"", devpath.c_str());
1.1.1.3 root 150: }
151:
152: // デバイスオープン
1.1 root 153: fd = open(devpath.c_str(), O_RDWR);
1.1.1.3 root 154: if (fd < 0) {
1.1.1.5 ! root 155: errmsg = string_format("%s: %s", devpath.c_str(), strerror(errno));
! 156: putmsg(1, "%s: %s", __func__, errmsg.c_str());
1.1 root 157: return false;
158: }
159:
1.1.1.3 root 160: // インタフェース作成。これには CAP_NET_ADMIN 権限が必要
1.1 root 161: ifr.ifr_flags = IFF_TAP | IFF_NO_PI; // tap として使う
162: strlcpy(ifr.ifr_name, "tap%d", sizeof(ifr.ifr_name));
163: r = ioctl(fd, TUNSETIFF, (void *)&ifr);
1.1.1.3 root 164: if (r < 0) {
1.1.1.5 ! root 165: errmsg = string_format("%s: %s: %s",
! 166: devpath.c_str(), "TUNSETIFF", strerror(errno));
! 167: putmsg(1, "%s: %s", __func__, errmsg.c_str());
1.1 root 168: if (errno == EPERM) {
1.1.1.5 ! root 169: // Linux では setcap(8) が必要。分かりづらいのでメッセージを出すが
! 170: // その例示より先に errmsg を表示したい。
! 171: warnx("%s", errmsg.c_str());
! 172: errmsg.clear();
! 173:
1.1 root 174: fprintf(stderr,
1.1.1.4 root 175: " ** Set CAP_NET_ADMIN capability to the nono executable file."
176: "\n"
1.1 root 177: " ** ex) sudo setcap cap_net_admin=ep path/to/%s\n",
178: getprogname());
179: }
1.1.1.3 root 180: CloseFd();
181: return false;
1.1 root 182: }
183:
184: // 作成できたインタフェース名を取得
185: ifname = std::string(ifr.ifr_name);
186:
1.1.1.3 root 187: return true;
188: }
189: #endif // __linux__
190:
191: // tap インタフェースを作成する。BSD で直接指定の場合。
1.1.1.5 ! root 192: // エラーの場合は putmsg ログを出力し、errmsg をセットして false を返す。
1.1.1.3 root 193: // devpath がデバイス名で "/dev/tap1" なら tap1 インタフェースが出来るはず?
194: bool
195: NetDriverTap::OpenDirect()
196: {
197: // devpath は "/dev/tapNN" という書式のはずなので、tapNN のところを
198: // 取り出せばインタフェース名になるはず。それ以外の運用されたらシラン。
199: auto pos = devpath.rfind("tap");
200: if (pos == std::string::npos) {
1.1.1.5 ! root 201: errmsg = string_format("%s: devpath must contain \"tap\"",
1.1.1.3 root 202: devpath.c_str());
1.1.1.5 ! root 203: putmsg(1, "%s: %s", __func__, errmsg.c_str());
1.1.1.3 root 204: return false;
1.1 root 205: }
1.1.1.3 root 206: ifname = devpath.substr(pos);
1.1 root 207:
1.1.1.3 root 208: // tapN デバイスオープン
209: fd = open(devpath.c_str(), O_RDWR);
210: if (fd < 0) {
1.1.1.5 ! root 211: errmsg = string_format("%s: %s", devpath.c_str(), strerror(errno));
! 212: putmsg(1, "%s: %s", __func__, errmsg.c_str());
1.1 root 213: return false;
214: }
215:
216: return true;
1.1.1.3 root 217: }
1.1 root 218:
1.1.1.3 root 219: // tap インタフェースを作成する。BSD で /dev/tapN を順に試す場合。
1.1.1.5 ! root 220: // エラーの場合は putmsg ログを出力し、errmsg をセットして false を返す。
1.1.1.3 root 221: bool
222: NetDriverTap::OpenNumbered()
223: {
224: // 最大値は適当
225: for (int i = 0; i < 10; i++) {
226: ifname = string_format("tap%d", i);
227: devpath = "/dev/" + ifname;
228:
229: fd = open(devpath.c_str(), O_RDWR);
230: if (fd < 0) {
231: // ファイルがないのを表示したら結構うるさいので除く
232: if (errno != ENOENT) {
1.1.1.4 root 233: putmsg(1, "%s: %s: %s",
234: __func__, devpath.c_str(), strerror(errno));
1.1.1.3 root 235: }
236: continue;
237: }
238: // オープンできたら終了
239: return true;
240: }
241:
242: // 見付からなかった
243: if (fd < 0) {
1.1.1.5 ! root 244: // ここでは何も表示しなくてもだいたい分かる
1.1.1.3 root 245: errmsg = "no tap devices available";
246: return false;
247: }
1.1.1.5 ! root 248: return true;
1.1.1.3 root 249: }
250:
251: // tap インタフェースを作成する。NetBSD で /dev/tap による cloning の場合。
1.1.1.5 ! root 252: // エラーの場合は putmsg ログを出力し、errmsg をセットして false を返す。
1.1.1.3 root 253: bool
254: NetDriverTap::OpenCloning()
255: {
256: #if defined(TAPGIFNAME)
257: struct ifreq ifr;
258:
259: // /dev/tap 以外のデバイスファイル名に /dev/tap の major/minor 番号を
260: // 割り当てることは合法だが、ここではデバイスファイル名でどの方式を
261: // 使うかを選択しているので /dev/tap という名前以外の選択肢はない。
262: devpath = "/dev/tap";
1.1.1.5 ! root 263: putmsg(1, "%s: use fixed devpath: %s", __func__, devpath.c_str());
1.1.1.3 root 264:
265: // tap デバイスオープン
266: fd = open(devpath.c_str(), O_RDWR);
267: if (fd < 0) {
268: errmsg = string_format("%s: %s", devpath.c_str(), strerror(errno));
1.1.1.4 root 269: putmsg(1, "%s: %s", __func__, errmsg.c_str());
1.1.1.3 root 270: return false;
271: }
272:
273: // オープンされたこのディスクリプタのインタフェース名を取得。
274: memset(&ifr, 0, sizeof(ifr));
275: if (ioctl(fd, TAPGIFNAME, &ifr) < 0) {
1.1.1.5 ! root 276: errmsg = string_format("%s: %s: %s",
! 277: devpath.c_str(), "TAPGIFNAME", strerror(errno));
1.1.1.4 root 278: putmsg(1, "%s: %s", __func__, errmsg.c_str());
1.1.1.3 root 279: CloseFd();
280: return false;
281: }
282:
283: // 作成できたインタフェース名を取得
284: ifname = std::string(ifr.ifr_name);
285:
286: return true;
287: #else
288: errmsg = "TAPGIFNAME not compiled(?)";
1.1.1.4 root 289: putmsg(1, "%s: %s", __func__, errmsg.c_str());
1.1.1.3 root 290: return false;
291: #endif
292: }
293:
294: // fd のクローズ
295: void
296: NetDriverTap::CloseFd()
297: {
1.1 root 298: close(fd);
299: fd = -1;
300: }
301:
302: // クローズ
303: // (private)
304: void
305: NetDriverTap::Close()
306: {
307: if (IsOpen()) {
308: Run_ifdown();
309:
1.1.1.3 root 310: CloseFd();
1.1 root 311: }
312: }
313:
1.1.1.5 ! root 314: // モニタ (ドライバ依存情報のみ)
! 315: void
! 316: NetDriverTap::MonitorUpdateMD(TextScreen& screen)
! 317: {
! 318: screen.Print(0, 1, "Device : %s", devpath.c_str());
! 319: screen.Print(0, 2, "Interface: %s", ifname.c_str());
! 320: }
! 321:
1.1 root 322: // パケットを送信する
323: bool
324: NetDriverTap::SendPacket(const std::vector<uint8>& data)
325: {
326: int n;
327:
328: assert(IsOpen());
329:
330: putlog(2, "SendPacket %zd bytes", data.size());
331: tx_pkts++;
332: tx_bytes += data.size();
333:
334: n = write(fd, data.data(), data.size());
335: if (n == -1) {
336: warn("SendPacket: write failed: fd=%d datalen=%zu",
337: fd, data.size());
338: return false;
339: }
340:
341: if (n < (int)data.size()) {
342: return false;
343: }
344: return true;
345: }
346:
1.1.1.5 ! root 347: // パケットを受信する
! 348: ssize_t
! 349: NetDriverTap::RecvPacket()
! 350: {
! 351: uint8 buf[10240];
! 352: ssize_t rv;
! 353:
! 354: rv = read(fd, buf, sizeof(buf));
! 355: if (rv > 0) {
! 356: RecvEnqueue(buf, rv);
1.1 root 357: }
1.1.1.5 ! root 358: return rv;
1.1 root 359: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.