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