|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
5: //
6:
7: //
8: // ネットワークのホストデバイス
9: //
10:
1.1.1.7 root 11: // 送信時のフロー
12: //
13: // VM thread : Host thread
14: //
15: // 各デバイス::送信() :
16: // |
17: // HostNetDevice::Tx() : HostDevice::ThreadRun
18: // |
19: // +-------------->| queue |----+ … 送信キューに追加し
20: // +-------------->| pipe |----+ … パイプでホストスレッドに通知
21: // | |
22: // <-+ : v
23: // --- kevent
24: // : |
25: // HostNetDevice::Write()
26: // : |
27: // NetDriver*::Write()
28: // : |
29: // +-----> Send to the real world
30:
31: // 受信のフロー
32: //
33: // VM thread : Host thread
34: //
35: // : HostDevice::ThreadRun
36: //
37: // : +-----< Recv from the real world
38: // |
39: // : v
40: // --- kevent
41: // : |
42: // HostNetDevice::Read()
43: // |
44: // | queue |<---+ … 受信キューに追加
45: // ‖
46: // ‖ HostNetDevice::*(rx_func)()
47: // |
48: // +-------------| Message |<---+ … メッセージで VM スレッドに通知
49: // v
50: // 各デバイス::RxMessage() ‖ … メッセージコールバック
51: // | ‖
52: // 各デバイス::Rx() ‖ … イベントコールバック
53: // | ‖
54: // HostCOMDevice::Rx() <==++ … ここで queue から読み出す
55:
1.1 root 56: // ログ名
57: // Ethernet HostDevice NetDriver
58: // | | |
59: // v v v
60: // Lance -> HostNetDevice -> NetDriver***
1.1.1.3 root 61: // 表示名 (Lance) (HostNet0) (HostNet0.***)
62: // 識別名 "lance" "hostnet0" "hostnet0"
1.1 root 63: //
1.1.1.3 root 64: // HostNet は、特に NetDriver 派生クラス選択時はフォールバックも含めて
65: // どれが選択されるか複雑なこともあるので、ログ表示名に自分のドライバ名
1.1 root 66: // も表示したい。
67:
68: #include "hostnet.h"
69: #include "config.h"
1.1.1.6 root 70: #include "monitor.h"
1.1 root 71: #include "netdriver_none.h"
72: #if defined(HAVE_HOSTNET_AFPACKET)
73: #include "netdriver_afpacket.h"
74: #endif
75: #if defined(HAVE_HOSTNET_BPF)
76: #include "netdriver_bpf.h"
77: #endif
1.1.1.7 root 78: #if defined(HAVE_HOSTNET_SLIRP)
79: #include "netdriver_slirp.h"
80: #endif
1.1 root 81: #if defined(HAVE_HOSTNET_TAP)
82: #include "netdriver_tap.h"
83: #endif
1.1.1.9 ! root 84: #include "uimessage.h"
1.1.1.7 root 85: #include <sys/socket.h>
86: #include <netdb.h>
87: #include <arpa/inet.h>
88: #include <netinet/in.h>
1.1 root 89:
90: // コンパイル済みのドライバ名一覧を返す (MainApp から呼ばれる)
91: /*static*/ std::vector<std::string>
92: HostNetDevice::GetDrivers()
93: {
94: std::vector<std::string> list;
95:
96: #if defined(HAVE_HOSTNET_AFPACKET)
97: list.emplace_back("afpacket");
98: #endif
99: #if defined(HAVE_HOSTNET_BPF)
100: list.emplace_back("bpf");
101: #endif
1.1.1.7 root 102: #if defined(HAVE_HOSTNET_SLIRP)
103: list.emplace_back("usermode");
104: #endif
1.1 root 105: #if defined(HAVE_HOSTNET_TAP)
106: list.emplace_back("tap");
107: #endif
108:
109: return list;
110: }
111:
112:
113: // コンストラクタ
1.1.1.9 ! root 114: HostNetDevice::HostNetDevice(Device *parent_, uint n,
! 115: const std::string& portname_)
! 116: : inherited(parent_, OBJ_HOSTNET(n), portname_)
1.1 root 117: {
1.1.1.7 root 118: ihwaddrfilter = dynamic_cast<IHWAddrFilter *>(parent);
119: assert(ihwaddrfilter);
120:
1.1.1.6 root 121: monitor = gMonitorManager->Regist(ID_MONITOR_HOSTNET(n), this);
122: monitor->func = ToMonitorCallback(&HostNetDevice::MonitorUpdate);
1.1.1.7 root 123: monitor->SetSize(48, 24);
1.1.1.9 ! root 124:
! 125: #if defined(HAVE_HOSTNET_SLIRP)
! 126: // SLIRP モニタは usermode を使う時のみ必要だが、現状モニタは
! 127: // 起動時に1回登録しなければならない (以後増減できない) という制約が
! 128: // あるのでここで登録だけしておく。うーんこの…。
! 129: // usermode は現状高々1つなので、登録されてない時だけ登録する。
! 130: Monitor *mon = gMonitorManager->Find(ID_MONITOR_SLIRP);
! 131: if (mon == NULL) {
! 132: gMonitorManager->Regist(ID_MONITOR_SLIRP, NULL);
! 133: }
! 134: #endif
1.1 root 135: }
136:
137: // デストラクタ
138: HostNetDevice::~HostNetDevice()
139: {
140: }
141:
142: // ログレベル設定
143: void
144: HostNetDevice::SetLogLevel(int loglevel_)
145: {
146: inherited::SetLogLevel(loglevel_);
147:
1.1.1.9 ! root 148: std::lock_guard<std::mutex> guard(driverlock);
1.1 root 149: if ((bool)driver) {
150: driver->SetLogLevel(loglevel_);
151: }
152: }
153:
1.1.1.7 root 154: // 動的コンストラクションその2
1.1 root 155: bool
1.1.1.7 root 156: HostNetDevice::Create2()
1.1 root 157: {
1.1.1.7 root 158: if (inherited::Create2() == false) {
1.1 root 159: return false;
160: }
161:
1.1.1.9 ! root 162: // hostnet*-fallback は使わなくなったので、
! 163: // 初期値から変更されていれば警告だけ出す。
! 164: std::string key = GetConfigKey();
! 165: const std::string fallback_key = key + "-fallback";
! 166: const ConfigItem& fallback_item = gConfig->Find(fallback_key);
! 167: if (fallback_item.GetFrom() != ConfigItem::FromInitial) {
! 168: warnx("Warning: option '%s' has been obsoleted.",
! 169: fallback_key.c_str());
! 170: }
! 171:
! 172: if (SelectDriver(true) == false) {
1.1 root 173: return false;
174: }
175:
176: return true;
177: }
178:
1.1.1.9 ! root 179: // ドライバ(再)選択。
! 180: // エラーが起きた場合、
! 181: // 起動時なら、warn() 等で表示して false を返す(終了する)。
! 182: // 実行中なら、warn() 等で表示してもいいが、必ず None にフォールバックして
! 183: // true を返すこと。
1.1 root 184: bool
1.1.1.9 ! root 185: HostNetDevice::SelectDriver(bool startup)
1.1 root 186: {
1.1.1.9 ! root 187: std::lock_guard<std::mutex> guard(driverlock);
1.1 root 188:
189: driver.reset();
1.1.1.9 ! root 190: errmsg.clear();
! 191:
! 192: std::string key = GetConfigKey();
! 193: const ConfigItem& item = gConfig->Find(key + "-driver");
! 194: std::string type = item.AsString();
1.1 root 195:
1.1.1.7 root 196: // auto は usermode か none と同義にする。
197: if (type == "auto") {
198: #if defined(HAVE_HOSTNET_SLIRP)
199: type = "usermode";
200: #else
201: type = "none";
202: #endif
203: }
204:
1.1.1.9 ! root 205: enum {
! 206: ERR_CONFIG, // 設定でのエラー
! 207: ERR_INVALID, // 知らないドライバ
! 208: ERR_NOTSUPP, // コンパイルされてない
! 209: } reason = ERR_CONFIG;
! 210:
! 211: if (type == "none") {
! 212: CreateNone();
! 213:
! 214: } else if (type == "usermode") {
1.1.1.7 root 215: #if defined(HAVE_HOSTNET_SLIRP)
1.1.1.9 ! root 216: CreateSlirp(startup);
1.1.1.7 root 217: #else
1.1.1.9 ! root 218: reason = ERR_NOTSUPP;
1.1.1.7 root 219: #endif
220:
1.1.1.9 ! root 221: } else if (type == "tap") {
1.1 root 222: #if defined(HAVE_HOSTNET_TAP)
1.1.1.9 ! root 223: CreateTap();
1.1 root 224: #else
1.1.1.9 ! root 225: reason = ERR_NOTSUPP;
1.1 root 226: #endif
227:
1.1.1.9 ! root 228: } else if (type == "bpf") {
1.1 root 229: #if defined(HAVE_HOSTNET_BPF)
1.1.1.9 ! root 230: CreateBPF();
1.1 root 231: #else
1.1.1.9 ! root 232: reason = ERR_NOTSUPP;
1.1 root 233: #endif
234:
1.1.1.9 ! root 235: } else if (type == "afpacket") {
1.1 root 236: #if defined(HAVE_HOSTNET_AFPACKET)
1.1.1.9 ! root 237: CreateAFPacket();
1.1 root 238: #else
1.1.1.9 ! root 239: reason = ERR_NOTSUPP;
1.1 root 240: #endif
241:
1.1.1.9 ! root 242: } else {
! 243: // 知らないドライバ種別
! 244: reason = ERR_INVALID;
1.1 root 245: }
246:
247: if ((bool)driver == false) {
1.1.1.9 ! root 248: // 指定のドライバが使えなかった場合、
! 249: // o 起動時ならエラー終了する。
! 250: // o 実行中なら none にフォールバックする。
! 251: if (startup) {
! 252: switch (reason) {
! 253: case ERR_INVALID:
! 254: item.Err("Invalid driver name");
! 255: break;
! 256: case ERR_CONFIG:
! 257: item.Err("Could not configure the driver");
! 258: warnx("(See details with option -C -L%s=1)", key.c_str());
! 259: break;
! 260: case ERR_NOTSUPP:
! 261: item.Err("Hostnet driver %s not compiled", type.c_str());
! 262: break;
! 263: default:
! 264: assert(false);
! 265: }
! 266: return false;
! 267: } else {
! 268: // UI に通知してフォールバック。
! 269: int n = GetId() - OBJ_HOSTNET0;
! 270: UIMessage::Post(UIMessage::HOSTNET_FAILED, n);
! 271:
! 272: CreateNone();
! 273: }
1.1 root 274: }
275: assert((bool)driver);
276:
277: // ドライバ名は Capitalize だがログはほぼ小文字なので雰囲気を揃える…
278: putmsg(1, "selected host driver: %s",
279: string_tolower(driver->GetDriverName()).c_str());
280:
281: return true;
282: }
283:
1.1.1.9 ! root 284: // None ドライバを生成する。
! 285: // 戻り値はなく、成否は (bool)driver で判断する。
! 286: void
1.1 root 287: HostNetDevice::CreateNone()
288: {
1.1.1.8 root 289: try {
290: driver.reset(new NetDriverNone(this));
291: } catch (...) { }
1.1 root 292: if ((bool)driver) {
293: if (driver->InitDriver()) {
294: // 成功
1.1.1.9 ! root 295: return;
1.1 root 296: }
297: errmsg = driver->errmsg;
298: driver.reset();
299: }
300: }
301:
1.1.1.9 ! root 302: // Slirp ドライバを生成する。
! 303: // 戻り値はなく、成否は (bool)driver で判断する。
! 304: void
! 305: HostNetDevice::CreateSlirp(bool startup)
1.1.1.7 root 306: {
307: #if defined(HAVE_HOSTNET_SLIRP)
1.1.1.8 root 308: try {
309: driver.reset(new NetDriverSlirp(this));
310: } catch (...) { }
1.1.1.7 root 311: if ((bool)driver) {
1.1.1.9 ! root 312: if (driver->InitDriver(startup)) {
1.1.1.7 root 313: // 成功
1.1.1.9 ! root 314: return;
1.1.1.7 root 315: }
316: errmsg = driver->errmsg;
317: driver.reset();
318: }
319: #endif
320: }
321:
1.1.1.9 ! root 322: // Tap ドライバを生成する。
! 323: // 戻り値はなく、成否は (bool)driver で判断する。
! 324: void
1.1 root 325: HostNetDevice::CreateTap()
326: {
327: #if defined(HAVE_HOSTNET_TAP)
1.1.1.3 root 328: int n = GetId() - OBJ_HOSTNET0;
329: const std::string keyname = string_format("hostnet%d-tap-devpath", n);
330: const ConfigItem& item = gConfig->Find(keyname);
1.1 root 331: const std::string& devpath = item.AsString();
332:
1.1.1.8 root 333: try {
334: driver.reset(new NetDriverTap(this, devpath));
335: } catch (...) { }
1.1 root 336: if ((bool)driver) {
337: if (driver->InitDriver()) {
338: // 成功
1.1.1.9 ! root 339: return;
1.1 root 340: }
341: errmsg = driver->errmsg;
342: driver.reset();
343: }
344: #endif
345: }
346:
1.1.1.9 ! root 347: // bpf ドライバを生成する。
! 348: // 戻り値はなく、成否は (bool)driver で判断する。
! 349: void
1.1 root 350: HostNetDevice::CreateBPF()
351: {
352: #if defined(HAVE_HOSTNET_BPF)
1.1.1.3 root 353: int n = GetId() - OBJ_HOSTNET0;
354: const std::string keyname = string_format("hostnet%d-bpf-ifname", n);
355: const ConfigItem& item = gConfig->Find(keyname);
1.1 root 356: const std::string& ifname = item.AsString();
357:
1.1.1.8 root 358: try {
359: driver.reset(new NetDriverBPF(this, ifname));
360: } catch (...) { }
1.1 root 361: if ((bool)driver) {
362: if (driver->InitDriver()) {
363: // 成功
1.1.1.9 ! root 364: return;
1.1 root 365: }
366: errmsg = driver->errmsg;
367: driver.reset();
368: }
369: #endif
370: }
371:
1.1.1.9 ! root 372: // AFPacket ドライバを生成する。
! 373: // 戻り値はなく、成否は (bool)driver で判断する。
! 374: void
1.1 root 375: HostNetDevice::CreateAFPacket()
376: {
377: #if defined(HAVE_HOSTNET_AFPACKET)
1.1.1.3 root 378: int n = GetId() - OBJ_HOSTNET0;
379: const std::string keyname = string_format("hostnet%d-afpacket-ifname", n);
380: const ConfigItem& item = gConfig->Find(keyname);
1.1 root 381: const std::string& ifname = item.AsString();
382:
1.1.1.8 root 383: try {
384: driver.reset(new NetDriverAFPacket(this, ifname));
385: } catch (...) { }
1.1 root 386: if ((bool)driver) {
387: if (driver->InitDriver()) {
388: // 成功
1.1.1.9 ! root 389: return;
1.1 root 390: }
391: errmsg = driver->errmsg;
392: driver.reset();
393: }
394: #endif
395: }
396:
397: // VM からの送信 (VM スレッドで呼ばれる)
398: bool
399: HostNetDevice::Tx(const NetPacket& packet)
400: {
1.1.1.5 root 401: // 長さ 0 のパケットは破棄する。バグでもないと通常は起きない。
402: // runt frame はどうするか?
403: if (packet.length < 1) {
404: stat.txzero_pkts++;
405: putlog(1, "Tx: drop empty packet");
406: return true;
407: }
408:
1.1 root 409: // 送信キューに入れて..
410: if (txq.Enqueue(packet) == false) {
411: stat.txqfull_pkts++;
412: stat.txqfull_bytes += packet.length;
413: putlog(2, "txq exhausted");
414: return false;
415: }
416:
417: stat.tx_pkts++;
418: stat.tx_bytes += packet.length;
419:
420: // ざっくりピーク値
1.1.1.5 root 421: stat.txq_peak = std::max((uint)txq.Length(), stat.txq_peak);
1.1 root 422:
1.1.1.9 ! root 423: // パイプで通知。
! 424: return WritePipe(PIPE_TX);
1.1 root 425: }
426:
1.1.1.6 root 427: // rxq への投入を行う場合は true。
428: // VM スレッドから呼ばれる。
1.1 root 429: void
430: HostNetDevice::EnableRx(bool enable)
431: {
432: rx_enable = enable;
1.1.1.6 root 433:
434: // 受信を停止した時はキューに残っているのを破棄する。
435: // (ゲスト再起動によるデバイスリセット時とか)
436: if (rx_enable == false) {
437: // 統計情報に足すためだけに一旦取り出す。
438: NetPacket drop;
439: while (rxq.Dequeue(&drop)) {
440: stat.rxdisable_pkts++;
441: stat.rxdisable_bytes += drop.length;
442: }
443: }
1.1 root 444: }
445:
446: // パケットをキューから取り出す。
447: // VM 側から呼ばれる。
448: bool
449: HostNetDevice::Rx(NetPacket *dst)
450: {
451: if (rxq.Dequeue(dst) == false) {
452: // キューが空
453: return false;
454: }
455: stat.rx_pkts++;
456: stat.rx_bytes += dst->length;
1.1.1.3 root 457: if (__predict_false(loglevel >= 2)) {
1.1.1.5 root 458: putlogn("Recv %u bytes", dst->length);
1.1.1.7 root 459: if (loglevel >= 4) {
1.1.1.3 root 460: std::string buf;
1.1.1.5 root 461: for (uint i = 0; i < dst->length; i++) {
1.1.1.3 root 462: if (i % 16 == 0) {
463: buf += string_format("%04x:", i);
464: }
465: buf += string_format(" %02x", (*dst)[i]);
466: if (i % 16 == 7) {
467: buf += " ";
468: } else if (i % 16 == 15) {
469: putlogn("%s", buf.c_str());
470: buf = "";
471: }
472: }
473: if (buf.empty() == false) {
474: putlogn("%s", buf.c_str());
475: }
476: }
477: }
1.1 root 478:
479: return true;
480: }
481:
482: // 外部からの読み込み (パケットを受信)。
483: // 戻り値はキューに投入したパケット数。
484: int
485: HostNetDevice::Read()
486: {
487: int queued = 0;
488: int left = 0;
489:
1.1.1.9 ! root 490: std::lock_guard<std::mutex> guard(driverlock);
1.1 root 491: assert((bool)driver);
492:
493: do {
494: NetPacket *p;
495:
496: p = rxq.BeginWrite();
497: if (p == NULL) {
498: NetPacket discard;
499: left = driver->Read(&discard);
500: if (left < 0) {
501: break;
502: }
503: stat.rxqfull_pkts++;
504: stat.rxqfull_bytes += discard.length;
505: continue;
506: }
507:
508: // driver->Read() は VM に投入すべきパケットがなければ負数を返す。
509: // パケットがあれば p に書き戻して、driver 側のバッファに残っている
510: // パケット数 (といっても 0 か 1以上) を返してくる。
511: left = driver->Read(p);
512: if (left < 0) {
513: rxq.CancelWrite();
514: break;
515: }
516:
517: NetPacket& packet = *p;
518:
519: stat.read_pkts++;
520: stat.read_bytes += packet.length;
521:
522: if (rx_enable == false) {
523: rxq.CancelWrite();
524: stat.rxdisable_pkts++;
525: stat.rxdisable_bytes += packet.length;
526: continue;
527: }
528:
529: // イーサネットフレームより長いパケットはゲスト OS が期待していない。
530: // ここでドロップしてみる。
531: // これによりゲストでの dropping chained buffer が出なくなる。
532: if (packet.length > 1518) {
533: rxq.CancelWrite();
534: stat.rxjumbo_pkts++;
535: stat.rxjumbo_bytes += packet.length;
536: continue;
537: }
538:
539: // ホストカーネルから直接着信したパケット(というかフレームか)は
540: // 60バイトパディングされないまま読み出せるので、ここでパディングする。
541: while (packet.length < 60) {
542: packet.Append(0x00);
543: }
544:
1.1.1.7 root 545: // デバイスがこのアドレス宛のフレームを受け取るか。
546: // 受け取らないと分かっているフレームは VM へのキューに入れる前に
547: // 落としておきたい。
548: MacAddr dstaddr(&packet[0]);
549: auto res = ihwaddrfilter->HWAddrFilter(dstaddr);
550: if (res != 0) {
551: switch (res) {
552: case IHWAddrFilter::HPF_DROP_UNICAST:
553: stat.rxnotme_pkts++;
554: stat.rxnotme_bytes += packet.length;
555: break;
556: case IHWAddrFilter::HPF_DROP_MULTICAST:
557: stat.rxmcast_pkts++;
558: stat.rxmcast_bytes += packet.length;
559: break;
560: default:
561: assertmsg(false, "corrupted res=%u", res);
1.1 root 562: }
1.1.1.7 root 563: rxq.CancelWrite();
564: continue;
1.1 root 565: }
566:
567: // CRC XXX 計算すること
568: for (int i = 0; i < 4; i++) {
569: packet.Append(0x00);
570: }
571:
572: rxq.EndWrite();
573: queued++;
574: } while (left > 0);
575:
576: // ざっくりピーク値
1.1.1.5 root 577: stat.rxq_peak = std::max((uint)rxq.Length(), stat.rxq_peak);
1.1 root 578:
579: return queued;
580: }
581:
582: // 外部への書き出し(パケットを送信)
583: void
1.1.1.9 ! root 584: HostNetDevice::Write()
1.1 root 585: {
586: const NetPacket *p;
587:
1.1.1.9 ! root 588: std::lock_guard<std::mutex> guard(driverlock);
1.1 root 589: assert((bool)driver);
590:
591: // 送信キューから取り出す
592: while ((p = txq.BeginRead()) != NULL) {
593: const NetPacket& packet = *p;
594:
1.1.1.3 root 595: if (__predict_false(loglevel >= 2)) {
1.1.1.5 root 596: putlogn("Send %u bytes", packet.length);
1.1.1.7 root 597: if (loglevel >= 4) {
1.1.1.3 root 598: std::string buf;
1.1.1.5 root 599: for (uint i = 0; i < packet.length; i++) {
1.1.1.3 root 600: if (i % 16 == 0) {
601: buf += string_format("%04x:", i);
602: }
603: buf += string_format(" %02x", packet[i]);
604: if (i % 16 == 7) {
605: buf += " ";
606: } else if (i % 16 == 15) {
607: putlogn("%s", buf.c_str());
608: buf = "";
609: }
610: }
611: if (buf.empty() == false) {
612: putlogn("%s", buf.c_str());
613: }
614: }
615: }
1.1 root 616: stat.write_pkts++;
617: stat.write_bytes += packet.length;
618:
619: driver->Write(packet.data(), packet.length);
620: txq.EndRead();
621: }
622: }
623:
624: // ドライバ名を返す
625: const std::string
1.1.1.9 ! root 626: HostNetDevice::GetDriverName()
1.1 root 627: {
1.1.1.9 ! root 628: std::lock_guard<std::mutex> guard(driverlock);
1.1 root 629: assert((bool)driver);
630: return driver->GetDriverName();
631: }
632:
1.1.1.7 root 633: // 統計情報に1パケット分加算する。
634: // これだけ SLIRP 裏スレッドから呼ばれるため。
635: // 現状書き込むのが SLIRP スレッドだけなのでロックとかはしていない。
636: void
637: HostNetDevice::CountTXUnsupp(size_t bytes)
638: {
639: stat.txunsupp_pkts++;
640: stat.txunsupp_bytes += bytes;
641: }
642:
1.1 root 643: // モニタ
644: void
645: HostNetDevice::MonitorUpdate(Monitor *, TextScreen& screen)
646: {
647: screen.Clear();
648:
1.1.1.9 ! root 649: screen.Print(0, 0, "Device(Port) : %s", GetPortName().c_str());
! 650: {
! 651: std::lock_guard<std::mutex> guard(driverlock);
! 652: screen.Print(0, 1, "HostNet Driver: %s", driver->GetDriverName());
! 653: // 次の2行はドライバ依存情報
! 654: driver->MonitorUpdateMD(screen, 2);
! 655: }
1.1 root 656:
657: // 01234567890123456
658: // Write to host
659: // Drop:TxQ Full
660: // Drop:Rx Disabled
661: // Drop:Jumbo Frame
662: // Drop:Addr Filter
663:
1.1.1.3 root 664: int y = 5;
1.1 root 665: screen.Print(0, y++, "%-17s%13s %17s", "<Tx>", "Packets", "Bytes");
666: screen.Print(0, y++, "%-17s%13s %17s", "VM sends",
667: format_number(stat.tx_pkts).c_str(),
668: format_number(stat.tx_bytes).c_str());
669: screen.Print(0, y++, "%-17s%13s %17s", "Write to host",
670: format_number(stat.write_pkts).c_str(),
671: format_number(stat.write_bytes).c_str());
1.1.1.5 root 672: screen.Print(0, y++, "%-17s%13s %17s", "Drop:Empty Frame",
673: format_number(stat.txzero_pkts).c_str(),
674: "0");
1.1.1.7 root 675: screen.Print(0, y++, "%-17s%13s %17s", "Drop:Unsupported",
676: format_number(stat.txunsupp_pkts).c_str(),
677: format_number(stat.txunsupp_bytes).c_str());
1.1 root 678: screen.Print(0, y++, "%-17s%13s %17s", "Drop:TxQ Full",
679: format_number(stat.txqfull_pkts).c_str(),
680: format_number(stat.txqfull_bytes).c_str());
681: y++;
682:
683: screen.Print(0, y++, "%-17s%13s %17s", "<Rx>", "Packets", "Bytes");
684: screen.Print(0, y++, "%-17s%13s %17s", "Read from host",
685: format_number(stat.read_pkts).c_str(),
686: format_number(stat.read_bytes).c_str());
687: screen.Print(0, y++, "%-17s%13s %17s", "VM receives",
688: format_number(stat.rx_pkts).c_str(),
689: format_number(stat.rx_bytes).c_str());
690: screen.Print(0, y++, "%-17s%13s %17s", "Drop:Rx Disabled",
691: format_number(stat.rxdisable_pkts).c_str(),
692: format_number(stat.rxdisable_bytes).c_str());
693: screen.Print(0, y++, "%-17s%13s %17s", "Drop:Jumbo Frame",
694: format_number(stat.rxjumbo_pkts).c_str(),
695: format_number(stat.rxjumbo_bytes).c_str());
696: screen.Print(0, y++, "%-17s%13s %17s", "Drop:RxQ Full",
697: format_number(stat.rxqfull_pkts).c_str(),
698: format_number(stat.rxqfull_bytes).c_str());
1.1.1.4 root 699: screen.Print(0, y++, "%-17s%13s %17s", "Drop:Unicast",
700: format_number(stat.rxnotme_pkts).c_str(),
701: format_number(stat.rxnotme_bytes).c_str());
702: screen.Print(0, y++, "%-17s%13s %17s", "Drop:Multicast",
703: format_number(stat.rxmcast_pkts).c_str(),
704: format_number(stat.rxmcast_bytes).c_str());
1.1 root 705: y++;
706:
707: screen.Print(5, y++, "Capacity Peak");
1.1.1.5 root 708: screen.Print(0, y++, "TxQ %4u/%4u %4u",
709: (uint)txq.Length(), (uint)txq.Capacity(), stat.txq_peak);
710: screen.Print(0, y++, "RxQ %4u/%4u %4u",
711: (uint)rxq.Length(), (uint)rxq.Capacity(), stat.rxq_peak);
1.1 root 712: }
1.1.1.7 root 713:
714: // 16進ダンプに整形して、文字列の配列(改行を含まない)を返す。
715: /*static*/ std::vector<std::string>
716: HostNetDevice::DumpHex(const void *src, size_t srclen)
717: {
718: std::vector<std::string> lines;
719: std::string buf;
720:
721: for (size_t i = 0; i < srclen; i++) {
722: buf += string_format(" %02x", ((const uint8 *)src)[i]);
723: if (i % 16 == 7) {
724: buf += ' ';
725: }
726: if (i % 16 == 15) {
727: lines.emplace_back(buf);
728: buf.clear();
729: }
730: }
731: if (buf.empty() == false) {
732: lines.emplace_back(buf);
733: }
734: return lines;
735: }
736:
737: // イーサネットフレームを整形して、文字列の配列(改行は含まない)を返す。
738: /*static*/ std::vector<std::string>
739: HostNetDevice::DumpFrame(const void *src, size_t srclen)
740: {
741: std::vector<std::string> lines;
742: struct eth_header {
743: uint8 dst[6];
744: uint8 src[6];
745: uint16 type;
746: } __packed;
747:
748: const eth_header& eh = *(const eth_header *)src;
749: uint16 type = ntohs(eh.type);
750: std::string ethtype;
751: switch (type) {
752: case 0x0800: ethtype = "IPv4"; break;
753: case 0x0806: ethtype = "ARP"; break;
754: case 0x86dd: ethtype = "IPv6"; break;
755: default:
756: ethtype = string_format("%04x", type);
757: break;
758: }
759: lines.emplace_back(string_format("Eth: %02x:%02x:%02x:%02x:%02x:%02x -> "
760: "%02x:%02x:%02x:%02x:%02x:%02x (%s)",
761: eh.src[0], eh.src[1], eh.src[2], eh.src[3], eh.src[4], eh.src[5],
762: eh.dst[0], eh.dst[1], eh.dst[2], eh.dst[3], eh.dst[4], eh.dst[5],
763: ethtype.c_str()));
764:
765: // ペイロードは次の行につなげる。
766: const uint8 *payload = (const uint8 *)src + sizeof(eth_header);
767: size_t payloadlen = srclen - sizeof(eth_header);
768: std::vector<std::string> lines2;
769: switch (type) {
770: case 0x0800:
771: lines2 = DumpIPv4(payload, payloadlen);
772: break;
773: case 0x0806:
774: lines2 = DumpARP(payload, payloadlen);
775: break;
776: case 0x86dd:
777: lines2 = DumpIPv6(payload, payloadlen);
778: break;
779: default:
780: break;
781: }
782: if (lines2.empty() == false) {
783: for (auto& buf : lines2) {
784: lines.emplace_back(buf);
785: }
786: }
787:
788: return lines;
789: }
790:
791: // ARP パケットを整形して、文字列の配列(改行は含まない)を返す。
792: /*static*/ std::vector<std::string>
793: HostNetDevice::DumpARP(const void *src, size_t srclen)
794: {
795: std::vector<std::string> lines;
796: struct arp_header {
797: uint16 hwtype;
798: uint16 prototype;
799: uint8 hwsize;
800: uint8 protosize;
801: enum : uint16 {
802: ARP_REQUEST = 1,
803: ARP_REPLY = 2,
804: } opcode;
805: uint8 dstmac[6];
806: uint8 dstip[4];
807: uint8 srcmac[6];
808: uint8 srcip[4];
809: } __packed;
810:
811: const arp_header& a = *(const arp_header *)src;
812: uint16 opcode = ntohs(a.opcode);
813: std::string opstr;
814: switch (opcode) {
815: case arp_header::ARP_REQUEST:
816: lines.emplace_back(string_format(
817: " ARP: Who has %u.%u.%u.%u? Tell %u.%u.%u.%u",
818: a.dstip[0], a.dstip[1], a.dstip[2], a.dstip[3],
819: a.srcip[0], a.srcip[1], a.srcip[2], a.srcip[3]));
820: break;
821: case arp_header::ARP_REPLY:
822: lines.emplace_back(string_format(
823: " ARP: Reply %u.%u.%u.%u is at %02x:%02x:%02x:%02x:%02x:%02x",
824: a.dstip[0], a.dstip[1], a.dstip[2], a.dstip[3],
825: a.dstmac[0], a.dstmac[1], a.dstmac[2],
826: a.dstmac[3], a.dstmac[4], a.dstmac[5]));
827: break;
828: default:
829: lines.emplace_back(string_format(" ARP: unknown op 0x%04x", opcode));
830: break;
831: }
832:
833: return lines;
834: }
835:
836: // IPv4 パケットを整形して、文字列の配列(改行は含まない)を返す。
837: /*static*/ std::vector<std::string>
838: HostNetDevice::DumpIPv4(const void *src, size_t srclen)
839: {
840: std::vector<std::string> lines;
841: struct ipv4_header {
842: uint8 ver_len;
843: uint8 tos;
844: uint16 total_len;
845: uint16 id;
846: uint16 fragment;
847: uint8 ttl;
848: uint8 proto;
849: uint16 cksum;
850: uint8 src[4];
851: uint8 dst[4];
852: } __packed;
853:
854: const ipv4_header& ip = *(const ipv4_header *)src;
855: const uint8 *payload = (const uint8 *)src + sizeof(ipv4_header);
856: size_t payloadlen = srclen - sizeof(ipv4_header);
857:
858: char srcname[INET_ADDRSTRLEN];
859: char dstname[INET_ADDRSTRLEN];
860: srcname[0] = '\0';
861: dstname[0] = '\0';
862: inet_ntop(AF_INET, &ip.src[0], srcname, (socklen_t)sizeof(srcname));
863: inet_ntop(AF_INET, &ip.dst[0], dstname, (socklen_t)sizeof(dstname));
864:
865: switch (ip.proto) {
866: case 1:
867: lines = DumpICMPv4(srcname, dstname, payload, payloadlen);
868: break;
869: case 6:
870: lines = DumpTCPv4(srcname, dstname, payload, payloadlen);
871: break;
872: case 17:
873: lines = DumpUDPv4(srcname, dstname, payload, payloadlen);
874: break;
875: default:
876: {
877: std::string protoname;
878: const struct protoent *pent = getprotobynumber(ip.proto);
879: if (pent) {
880: protoname = string_format("(%s)", pent->p_name);
881: }
882: lines.emplace_back(string_format(" IPv4 %s -> %s 0x%02x%s",
883: srcname, dstname, ip.proto, protoname.c_str()));
884: break;
885: }
886: }
887:
888: return lines;
889: }
890:
891: // ICMP(v4) パケットを整形して、文字列の配列(改行は含まない)を返す。
892: /*static*/ std::vector<std::string>
893: HostNetDevice::DumpICMPv4(const char *srcname, const char *dstname,
894: const void *src, size_t srclen)
895: {
896: std::vector<std::string> lines;
897: struct icmp_header {
898: uint8 type;
899: uint8 code;
900: uint16 cksum;
901: } __packed;
902:
903: const icmp_header& icmp = *(const icmp_header *)src;
904: size_t payloadlen = srclen - sizeof(icmp_header);
905:
906: std::string msg = string_format(" ICMP %s -> %s ", srcname, dstname);
907: uint type = icmp.type;
908: uint code = icmp.code;
909:
910: switch (type) {
911: case 0: // ICMP_ECHOREPLY
912: msg += string_format("Echo Reply %zu bytes", payloadlen);
913: break;
914:
915: case 3: // ICMP_UNREACH
916: {
917: static const char * const reasons[] = {
918: "Destination Network Unreachable", // 0
919: "Destination Host Unreachable", // 1
920: "Destination Protocol Unreachable", // 2
921: "Destination Port Unreachable", // 3
922: "Fragment needed and DF set", // 4
923: "Source Route Failed", // 5
924: "Destination Network Unknown", // 6
925: "Destination Host Unknown", // 7
926: "Source Host Isolated", // 8
927: "Communication with Destination Network is prohibited", // 9
928: "Communication with Destination Host is prohibited", // 10
929: "Bad ToS for Destination Network", // 11
930: "Bad ToS for Destination Host", // 12
931: "Communication is Administratively prohibited", // 13
932: "Host Precedence Violation", // 14
933: "Precedence cutoff", // 15
934: };
935: if (code < countof(reasons)) {
936: msg += reasons[code];
937: } else {
938: msg += string_format("Network Unreachable: code=%02x", code);
939: }
940: break;
941: }
942:
943: case 5: // ICMP_REDIRECT
944: msg += string_format("Redirect code=%x", code);
945: break;
946:
947: case 8: // ICMP_ECHO
948: msg += string_format("Echo Request %zu bytes", payloadlen);
949: break;
950:
951: default:
952: msg += string_format("Type=0x%02x Code=0x%02x", type, code);
953: break;
954: }
955: lines.emplace_back(msg);
956:
957: return lines;
958: }
959:
960: // TCPv4 パケットを整形して、文字列の配列(改行は含まない)を返す。
961: /*static*/ std::vector<std::string>
962: HostNetDevice::DumpTCPv4(const char *srcname, const char *dstname,
963: const void *src, size_t srclen)
964: {
965: std::vector<std::string> lines;
966: struct tcp_header {
967: uint16 sport;
968: uint16 dport;
969: uint32 seq;
970: uint32 ack;
971: uint8 off;
972: uint8 flags;
973: uint16 window;
974: uint16 cksum;
975: uint16 urp;
976: } __packed;
977:
978: const tcp_header& tcp = *(const tcp_header *)src;
979: size_t payloadlen = srclen - sizeof(tcp_header);
980:
981: std::string flagstr;
982: if (tcp.flags != 0) {
983: flagstr = ' ';
984: if ((tcp.flags & 0x01)) flagstr += ",FIN";
985: if ((tcp.flags & 0x02)) flagstr += ",SYN";
986: if ((tcp.flags & 0x04)) flagstr += ",RST";
987: if ((tcp.flags & 0x08)) flagstr += ",PUSH";
988: if ((tcp.flags & 0x10)) flagstr += ",ACK";
989: if ((tcp.flags & 0x20)) flagstr += ",URG";
990: if ((tcp.flags & 0x40)) flagstr += ",ECE";
991: if ((tcp.flags & 0x80)) flagstr += ",CWR";
992: flagstr[1] = '<';
993: flagstr += '>';
994: }
995: std::string sserv = GetServByPort(tcp.sport, "tcp");
996: std::string dserv = GetServByPort(tcp.dport, "tcp");
997: lines.emplace_back(string_format(" TCP %s:%u%s -> %s:%u%s%s %zu bytes",
998: srcname, ntohs(tcp.sport), sserv.c_str(),
999: dstname, ntohs(tcp.dport), dserv.c_str(),
1000: flagstr.c_str(), payloadlen));
1001:
1002: return lines;
1003: }
1004:
1005: // UDPv4 パケットを整形して、文字列の配列(改行は含まない)を返す。
1006: /*static*/ std::vector<std::string>
1007: HostNetDevice::DumpUDPv4(const char *srcname, const char *dstname,
1008: const void *src, size_t srclen)
1009: {
1010: std::vector<std::string> lines;
1011: struct udp_header {
1012: uint16 sport;
1013: uint16 dport;
1014: uint16 len;
1015: uint16 cksum;
1016: } __packed;
1017:
1018: const udp_header& udp = *(const udp_header *)src;
1019: const uint8 *payload = (const uint8 *)src + sizeof(udp_header);
1020: size_t payloadlen = srclen - sizeof(udp_header);
1021:
1022: std::string sserv = GetServByPort(udp.sport, "udp");
1023: std::string dserv = GetServByPort(udp.dport, "udp");
1024: int sport = ntohs(udp.sport);
1025: int dport = ntohs(udp.dport);
1026: lines.emplace_back(string_format(" UDP %s:%u%s -> %s:%u%s %zu bytes",
1027: srcname, sport, sserv.c_str(),
1028: dstname, dport, dserv.c_str(),
1029: payloadlen));
1030:
1031: if (dport == 67 || dport == 68) {
1032: auto lines2 = DumpDHCP(payload, payloadlen);
1033: for (auto& buf : lines2) {
1034: lines.emplace_back(buf);
1035: }
1036: }
1037:
1038: return lines;
1039: }
1040:
1041: // BOOTP/DHCP パケットを整形して、文字列の配列(改行は含まない)を返す。
1042: /*static*/ std::vector<std::string>
1043: HostNetDevice::DumpDHCP(const void *src, size_t srclen)
1044: {
1045: std::vector<std::string> lines;
1046: struct bootp_msg {
1047: uint8 op; // Message Operation Code
1048: uint8 htype; // Hardware Type
1049: uint8 hlen; // Hardware Address Length
1050: uint8 hops;
1051: uint32 xid; // Transaction ID
1052: uint16 secs; // Seconds Elapsed (払い出し期間)
1053: uint16 flags;
1054: uint32 ciaddr; // Client IP Address (クライアントが使用)
1055: uint32 yiaddr; // Your IP Address (払い出し IP)
1056: uint32 siaddr; // Server IP Address (BOOTP)
1057: uint32 giaddr; // Gateway IP Address
1058: uint8 chaddr[16]; // Client Hardware Address
1059: uint8 sname[64]; // Server Name (BOOTP)
1060: uint8 file[128]; // Boot Filename (BOOTP)
1061: // ここから options
1062: } __packed;
1063:
1064: const bootp_msg& bootp = *(const bootp_msg *)src;
1065:
1066: std::string msg = " DHCP "; // IP,UDP の次のインデント
1067: if (bootp.op == 1) {
1068: msg += "Request";
1069: } else if (bootp.op == 2) {
1070: msg += "Reply";
1071: } else {
1072: msg += string_format("OP=0x%02x?", bootp.op);
1073: }
1074:
1075: if (bootp.htype != 1) {
1076: msg += string_format(" htype=0x%02x?", bootp.htype);
1077: }
1078: if (bootp.hlen != 6) {
1079: msg += string_format(" hlen=0x%02x?", bootp.hlen);
1080: }
1081: if (bootp.ciaddr != 0) {
1082: char ci[INET_ADDRSTRLEN];
1083: inet_ntop(AF_INET, &bootp.ciaddr, ci, (socklen_t)sizeof(ci));
1084: msg += " Client=";
1085: msg += ci;
1086: }
1087: if (bootp.yiaddr != 0) {
1088: char yi[INET_ADDRSTRLEN];
1089: inet_ntop(AF_INET, &bootp.yiaddr, yi, (socklen_t)sizeof(yi));
1090: msg += " YourIP=";
1091: msg += yi;
1092: }
1093: lines.emplace_back(msg);
1094:
1095: const uint8 *options = (const uint8 *)src + sizeof(bootp_msg);
1096: size_t optionslen = srclen - sizeof(bootp_msg);
1097: // オプションの先頭4バイトはマジック。
1098: if (optionslen >= 4 && memcmp(options, "\x63\x82\x53\x63", 4) == 0) {
1099: // 以降は Code-Length-Value 形式。
1100: const uint8 *s = options + 4;
1101: optionslen -= 4;
1102: while (s - options < optionslen) {
1103: uint8 code = *s++;
1104: if (code == 255) { // End
1105: break;
1106: }
1107: if (code == 0) { // Pad
1108: continue;
1109: }
1110: static const char * const optnames[] = {
1111: "", // 0
1112: "Subnet Mask", // 1
1113: "Time Offset", // 2
1114: "Router", // 3
1115: "Time Server", // 4
1116: "IEN116 Name Server", // 5
1117: "DNS Server", // 6
1118: "Log Server", // 7
1119: "Quotes Server", // 8
1120: "LPR Server", // 9
1121: "Impress Server", // 10
1122: "RLP Server", // 11
1123: "Hostname", // 12
1124: "Boot File Size", // 13
1125: "Merit Dump File", // 14
1126: "Domain Name", // 15
1127: "Swap Server", // 16
1128: "Root Path", // 17
1129: "Extension File", // 18
1130: "Forward Enable", // 19
1131: "Source Route Enable", // 20
1132: "Policy Filter", // 21
1133: "Max DG Assembly", // 22
1134: "Default IP TTL", // 23
1135: "MTU Timeout", // 24
1136: "MTU Plateau", // 25
1137: "MTU Interface", // 26
1138: "MTU Subnet", // 27
1139: "Broadcast Address", // 28
1140: "Mask Discovery", // 29
1141: "Mask Supplier", // 30
1142: "Router Discovery", // 31
1143: "Router Request", // 32
1144: "Static Route", // 33
1145: "Trailers", // 34
1146: "ARP Timeout", // 35
1147: "Ethernet", // 36
1148: "Default TCP TTL", // 37
1149: "Keepalive Time", // 38
1150: "Keepalive Data", // 39
1151: "NIS Domain", // 40
1152: "NIS Servers", // 41
1153: "NTP Servers", // 42
1154: "Vendor Specific", // 43
1155: "NETBIOS Name Server", // 44
1156: "NETBIOS Dist Server", // 45
1157: "NETBIOS Node Type", // 46
1158: "NETBIOS Scope", // 47
1159: "X Window Font", // 48
1160: "X Window Manager", // 49
1161: "Requested Address", // 50
1162: "Lease Time", // 51
1163: "Overload", // 52
1164: "DHCP Message Type", // 53
1165: "DHCP Server Id", // 54
1166: "Parameter List", // 55
1167: "DHCP Message", // 56
1168: "DHCP Max Msg Size", // 57
1169: "Renewal Time", // 58
1170: "Rebinding Time", // 59
1171: "Class Id", // 60
1172: "Client Id", // 61
1173: "Netware/IP Domain", // 62
1174: "Netware/IP Option", // 63
1175: "NIS Domain Name", // 64
1176: "NIS Server Addr", // 65
1177: "TFTP Server Name", // 66
1178: "Bootfile Name", // 67
1179: "Home Agent Addrs", // 68
1180: "SMTP Server", // 69
1181: "POP3 Server", // 70
1182: "NNTP Server", // 71
1183: "WWW Server", // 72
1184: "Finger Server", // 73
1185: "IRC Server", // 74
1186: "StreetTalk Server", // 75
1187: "STDA Server", // 76
1188: "User Class", // 77
1189: "Directory Agent", // 78
1190: "Service Scope", // 79
1191: "Naming Authority", // 80
1192: "Client FQDN", // 81
1193: "Agent Circuit ID", // 82
1194: "Agent Remote ID", // 83
1195: "Agent Subnet Mask", // 84
1196: "NDS Servers", // 85
1197: "NDS Tree Name", // 86
1198: "NDS Context", // 87
1199: "TimeZone", // 88
1200: "FQDN", // 89
1201: "Authentication", // 90
1202: "Vines TCP/IP", // 91
1203: "Server Selection", // 92
1204: "Client System", // 93
1205: "Client NDI", // 94
1206: "LDAP", // 95
1207: "IPv6 Transitions", // 96
1208: "UUID/GUID", // 97
1209: "User-Auth", // 98
1210: "", // 99
1211: "Printer Name", // 100
1212: "MDHCP", // 101
1213: "", // 102
1214: "", // 103
1215: "", // 104
1216: "", // 105
1217: "", // 106
1218: "", // 107
1219: "Swap Path", // 108
1220: "", // 109
1221: "IPX Compatability", // 110
1222: "", // 111
1223: "Netinfo Address", // 112
1224: "Netinfo Tag", // 113
1225: "URL", // 114
1226: "DHCP Failover", // 115
1227: "DHCP AutoConfig", // 116
1228: "Name Service Search", // 117
1229: "Subnet Selection", // 118
1230: };
1231: std::string opt = " ";
1232: if (code < countof(optnames) && optnames[code][0] != '\0') {
1233: opt += optnames[code];
1234: } else {
1235: opt += '?';
1236: }
1237: opt += string_format("(%d): ", code);
1238: size_t len = *s++;
1239: switch (code) {
1240: case 1: // Subnet Mask
1241: case 50: // Requested Address
1242: case 54: // DHCP Server Id
1243: // 単一アドレス
1244: opt += DumpDHCPAddrList(s, 1);
1245: break;
1246:
1247: case 3: // Router
1248: case 6: // DNS Server
1249: // アドレスリスト
1250: opt += DumpDHCPAddrList(s, len / 4);
1251: break;
1252:
1253: case 12: // Hostname
1254: case 15: // Domain Name
1255: {
1256: // 文字列 (終端文字なし)
1257: std::vector<char> buf(len + 1);
1258: memcpy(buf.data(), s, len);
1259: opt += buf.data();
1260: break;
1261: }
1262:
1263: case 51: // Lease Time
1264: {
1265: uint32 sec =
1266: (s[0] << 24)
1267: | (s[1] << 16)
1268: | (s[2] << 8)
1269: | (s[3]);
1270: opt += string_format("%d sec", sec);
1271: break;
1272: }
1273:
1274: case 53: // DHCP Message Type
1275: {
1276: static const char * const msgtypes[] = {
1277: "0",
1278: "DHCP DISCOVER",
1279: "DHCP OFFER",
1280: "DHCP REQUEST",
1281: "DHCP DECLINE",
1282: "DHCP ACK",
1283: "DHCP NAK",
1284: "DHCP RELEASE",
1285: "DHCP INFORM",
1286: };
1287: int type = s[0];
1288: if (type < countof(msgtypes)) {
1289: opt += msgtypes[type];
1290: } else {
1291: opt += string_format("0x%02x", type);
1292: }
1293: break;
1294: }
1295:
1296: default:
1297: // 簡易ダンプしとくか。
1298: for (size_t i = 0; i < len; i++) {
1299: opt += string_format("%02x", s[i]);
1300: if (i % 4 == 3) {
1301: opt += ' ';
1302: }
1303: }
1304: break;
1305: }
1306: lines.emplace_back(opt);
1307: s += len;
1308: }
1309: }
1310:
1311: return lines;
1312: }
1313:
1314: // s から num 個の IPv4 アドレスリストを文字列にして返す。
1315: // DumpDHCP() の下請け。
1316: /*static*/ std::string
1317: HostNetDevice::DumpDHCPAddrList(const uint8 *s, size_t num)
1318: {
1319: std::string buf;
1320:
1321: for (size_t i = 0; i < num; i++) {
1322: char addr[INET_ADDRSTRLEN];
1323: inet_ntop(AF_INET, s, addr, (socklen_t)sizeof(addr));
1324: if (i != 0) {
1325: buf += ' ';
1326: }
1327: buf += addr;
1328: }
1329:
1330: return buf;
1331: }
1332:
1333: // IPv6 パケットを整形して、文字列の配列(改行は含まない)を返す。
1334: /*static*/ std::vector<std::string>
1335: HostNetDevice::DumpIPv6(const void *src, size_t srclen)
1336: {
1337: std::vector<std::string> lines;
1338: struct ipv6_header {
1339: uint8 ver_cls;
1340: uint8 cls_flow;
1341: uint16 flowlabel;
1342: uint16 payload_len;
1343: uint8 nexthdr;
1344: uint8 hoplimit;
1345: uint8 src[16];
1346: uint8 dst[16];
1347: } __packed;
1348:
1349: const ipv6_header& ip6 = *(const ipv6_header *)src;
1350: const uint8 *payload = (const uint8 *)src + sizeof(ipv6_header);
1351: size_t payloadlen = srclen - sizeof(ipv6_header);
1352:
1353: char srcname[INET6_ADDRSTRLEN];
1354: char dstname[INET6_ADDRSTRLEN];
1355: srcname[0] = '\0';
1356: dstname[0] = '\0';
1357: inet_ntop(AF_INET6, &ip6.src[0], srcname, (socklen_t)sizeof(srcname));
1358: inet_ntop(AF_INET6, &ip6.dst[0], dstname, (socklen_t)sizeof(dstname));
1359:
1360: switch (ip6.nexthdr) {
1361: case 58:
1362: lines = DumpICMPv6(srcname, dstname, payload, payloadlen);
1363: break;
1364: default:
1365: {
1366: std::string protoname;
1367: const struct protoent *pent = getprotobynumber(ip6.nexthdr);
1368: if (pent) {
1369: protoname = string_format("(%s)", pent->p_name);
1370: }
1371: lines.emplace_back(string_format(" IPv6 %s -> %s 0x%02x%s",
1372: srcname, dstname, ip6.nexthdr, protoname.c_str()));
1373: break;
1374: }
1375: }
1376:
1377: return lines;
1378: }
1379:
1380: // ICMPv6 パケットを整形して、文字列の配列(改行は含まない)を返す。
1381: /*static*/ std::vector<std::string>
1382: HostNetDevice::DumpICMPv6(const char *srcname, const char *dstname,
1383: const void *src, size_t srclen)
1384: {
1385: std::vector<std::string> lines;
1386: // フォーマット自体は ICMPv4 と同じ。
1387: struct icmp_header {
1388: uint8 type;
1389: uint8 code;
1390: uint16 cksum;
1391: } __packed;
1392:
1393: const icmp_header& icmp6 = *(const icmp_header *)src;
1394:
1395: std::string msg = string_format(" ICMPv6 %s -> %s ", srcname, dstname);
1396: uint type = icmp6.type;
1397: uint code = icmp6.code;
1398:
1399: switch (type) {
1400: case 1:
1401: static const char * const reasons[] = {
1402: "No route to destination", // 0
1403: "Administratively prohibited", // 1
1404: "Beyond scope of source address", // 2
1405: "Address unreachable", // 3
1406: "Port unreachable", // 4
1407: "Source address failed ingress/egress policy", // 5
1408: "Reject route to destination", // 6
1409: "Error in source routing header", // 7
1410: };
1411: if (code < countof(reasons)) {
1412: msg += reasons[code];
1413: } else {
1414: msg += string_format("Destination Unreachable: code=%02x", code);
1415: }
1416: break;
1417:
1418: case 2:
1419: msg += "Packet too big";
1420: break;
1421: case 3:
1422: msg += "Time exceeded";
1423: break;
1424: case 4:
1425: msg += "Parameter Problem";
1426: break;
1427: case 128:
1428: msg += "Echo Request";
1429: break;
1430: case 129:
1431: msg += "Echo Reply";
1432: break;
1433: case 130:
1434: msg += "Multicast Listener Query";
1435: break;
1436: case 131:
1437: msg += "Multicast Listener Report";
1438: break;
1439: case 132:
1440: msg += "Multicast Listener Done";
1441: break;
1442: case 133:
1443: msg += "NDP Router Solicitation";
1444: break;
1445: case 134:
1446: msg += "NDP Router Advertisement";
1447: break;
1448: case 135:
1449: msg += "NDP Neighbor Solicitation";
1450: break;
1451: case 136:
1452: msg += "NDP Neighbor Advertisement";
1453: break;
1454: case 137:
1455: msg += "NDP Redirect";
1456: break;
1457: case 138:
1458: msg += "Router Renumber";
1459: break;
1460: case 139:
1461: msg += "ICMP Node Information Query";
1462: break;
1463: case 140:
1464: msg += "ICMP Node Information Reply";
1465: break;
1466: default:
1467: msg += string_format("Type=0x%02x Code=0x%02x", type, code);
1468: break;
1469: }
1470: lines.emplace_back(msg);
1471:
1472: return lines;
1473: }
1474:
1475: // ポート番号に対する名前を括弧をつけて返す。表示用。
1476: // 名前が引けなければ空文字列を返す。
1477: /*static*/ std::string
1478: HostNetDevice::GetServByPort(uint16 port_be, const char *protoname)
1479: {
1480: std::string name;
1481:
1482: // getservbyport() の引数はネットワークバイトオーダ…。
1483: // かつ、戻り値は内部のスタティックな領域を指している可能性がある。
1484: const struct servent *serv = getservbyport(port_be, protoname);
1485: if (serv) {
1486: name = string_format("(%s)", serv->s_name);
1487: }
1488: return name;
1489: }
1490:
1491:
1492: // IHWAddrFilter の デストラクタ
1493: IHWAddrFilter::~IHWAddrFilter()
1494: {
1495: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.