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