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