|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2025 nono project
4: // Licensed under nono-license.txt
5: //
6:
7: //
8: // ホストネットワークの usermode (SLIRP) ドライバ
9: //
10:
11: //
12: // NetDriverSlirp SlirpThread
13: // (HostNet スレッド) : (裏スレッド)
14: //
15: // 送信時のフロー:
16: // NetDriverSlirp() は送信パケットをパイプ txfd (=txfd_w) に書き込む。
17: // SlirpThread 側で txfd_r に着信するので取り出して slirp_input() へ送る。
18: //
19: // NetDriverSlirp::Write() :
20: // |
21: // | txfd(=txfd_w) txfd_r
22: // +--------------->| pipe |------+ … パイプで裏スレッドに送信
23: // | |
24: // <-+ : v
25: // --- kevent @ ThreadRun()
26: // : |
27: // SlirpThread::Write()
28: // : |
29: // +-----> slirp_input()
30: //
31:
32: // 受信時のフロー:
33: // SlirpThread 側のイベントループにて、管理する受信ディスクリプタに
34: // 着信があれば SlirpThread::Read() がそれを読み出してパイプ rxfd_w に
35: // 書き込む。
36: // このパイプの対向は HostNetDevice に AddOuter() で登録したものなので
37: // この書き込みに対する着信で HostDevice::Dispatch() が動き、
38: // その結果 NetDriverSlirp() が呼ばれる。
39: // NetDriverSlirp() はこのパイプからパケットを読み出して親に引き渡す。
40: //
41: // --- kevent @ ThreadRun()
42: // |
43: // SlirpThread::Read()
44: // |
45: // rxfd(=rxfd_r) rxfd_w|
46: // +---------------| pipe |<-----+
47: // | 着信通知 ‖
48: // v ‖
49: // --- kqueue ‖
50: // | ‖
51: // HostNetDevice::Read() ‖
52: // | ‖
53: // NetDriverSlirp::Read() ‖
54: // | ‖
55: // パイプから受信 <==++
56: // |
57: // <--+ VM 側へ
58:
59: #include "netdriver_slirp.h"
60: #include "hostnet.h"
61: #include "scheduler.h"
62: #include <sys/socket.h>
63: #include <sys/uio.h>
64: #include <slirp/libslirp.h>
65:
66: //
67: // NetDriver 側スレッド
68: //
69:
70: // コンストラクタ
71: NetDriverSlirp::NetDriverSlirp(HostDevice *hostdev_)
1.1.1.3 root 72: : inherited(hostdev_, "usermode")
1.1 root 73: {
74: txd = -1;
75: rxd = -1;
76: }
77:
78: // デストラクタ
79: NetDriverSlirp::~NetDriverSlirp()
80: {
81: Close();
82: }
83:
84: // ログレベルを設定。
85: void
86: NetDriverSlirp::SetLogLevel(int loglevel_)
87: {
88: inherited::SetLogLevel(loglevel_);
89:
90: // バックエンドにも伝達。
91: if ((bool)backend) {
92: backend->SetLogLevel(loglevel_);
93: }
94: }
95:
96: // ドライバ初期化
97: bool
1.1.1.3 root 98: NetDriverSlirp::InitDriver(bool startup)
1.1 root 99: {
100: putmsg(1, "trying usermode...");
101:
102: if (slirp_occupied) {
1.1.1.3 root 103: errmsg = "'usermode' is already in use by another hostnet-driver";
104: putmsg(1, "%s", errmsg.c_str());
1.1 root 105: return false;
106: }
107:
1.1.1.2 root 108: try {
109: backend.reset(new SlirpThread(this));
110: } catch (...) { }
1.1 root 111: if ((bool)backend == false) {
1.1.1.3 root 112: errmsg = string_format("Failed to initialize SlirpThread at %s",
113: __method__);
114: putmsg(1, "%s", errmsg.c_str());
1.1 root 115: return false;
116: }
117:
118: // ディスクリプタは裏スレッドが所有しているのでこちらでは解放しないこと。
119: const std::string key = hostdev->GetConfigKey();
120: if (backend->InitBackend(key, &rxd, &txd) == false) {
1.1.1.3 root 121: errmsg = backend->errmsg;
122: putmsg(1, "%s", errmsg.c_str());
1.1 root 123: return false;
124: }
125:
126: // 読み込み側を Slirp からの受信端として親に登録。
127: if (hostdev->AddOuter(rxd) < 0) {
1.1.1.3 root 128: errmsg = string_format("AddOuter(rxd=%d): %s", rxd, strerror(errno));
129: putmsg(1, "%s", errmsg.c_str());
1.1 root 130: return false;
131: }
132:
1.1.1.3 root 133: // 起動時は一斉に StartThread() されて backend のスレッドも起動するが、
134: // 再選択時はここで手動でスレッドを起動する必要がある。
135: if (startup == false) {
136: backend->StartThread();
137: }
138:
1.1 root 139: slirp_occupied = true;
140: putmsg(1, "opened");
141: return true;
142: }
143:
144: // クローズ
145: void
146: NetDriverSlirp::Close()
147: {
148: // rxd がすでに閉じられていたらとかはここでは関係なくて、
149: // この番号を kqueue から外す必要がある。(Linux)
1.1.1.3 root 150: if (rxd >= 0) {
151: hostdev->DelOuter(rxd);
152: }
1.1 root 153:
154: // txd, rxd は裏スレッドの所有なのでこちらでは何もしない。
155:
156: if ((bool)backend) {
157: backend->Terminate();
158: backend->Close();
1.1.1.3 root 159: backend.reset();
1.1 root 160: }
161: slirp_occupied = false;
162: }
163:
164: // モニタ (ドライバ依存情報のみ)
165: void
1.1.1.5 ! root 166: NetDriverSlirp::MonitorScreenMD(TextScreen& screen, int y)
1.1 root 167: {
168: // なし
169: }
170:
171: // パケットを送信する。
172: // と言っても裏スレッドに送り直すだけ。
173: void
174: NetDriverSlirp::Write(const void *buf, int buflen)
175: {
176: struct iovec iov[2];
1.1.1.5 ! root 177: ssize_t n;
1.1 root 178:
179: // 先頭4バイトに後続パケット長を入れておく。
180: static_assert(sizeof(buflen) == sizeof(uint32), "");
181: iov[0].iov_base = &buflen;
182: iov[0].iov_len = sizeof(buflen);
183: iov[1].iov_base = const_cast<void *>(buf);
184: iov[1].iov_len = buflen;
1.1.1.5 ! root 185: n = writev(txd, &iov[0], countof(iov));
! 186: if (n < 0) {
! 187: putmsg(0, "writev(%zu+%d) failed: %s",
! 188: sizeof(buflen), buflen, strerror(errno));
! 189: return;
! 190: }
! 191: if (n < sizeof(buflen) + buflen) {
! 192: putmsg(0, "writev(%zu+%d): short(%zd)", sizeof(buflen), buflen, n);
1.1 root 193: return;
194: }
195: }
196:
197: // パケットを受信する。
198: // これは rxd に着信があってから HostDevice::Dispatch() から呼ばれるほう。
199: int
200: NetDriverSlirp::Read(NetPacket *p)
201: {
1.1.1.5 ! root 202: std::vector<uint8> databuf;
! 203: ssize_t r;
! 204: ssize_t len;
! 205: ssize_t bufsize;
! 206: uint8 *buf;
! 207: uint32 datalen;
1.1 root 208:
209: // 先頭4バイトに後続パケット長を入れてある。
1.1.1.5 ! root 210: buf = reinterpret_cast<uint8 *>(&datalen);
! 211: bufsize = sizeof(datalen);
! 212: for (len = 0; len < bufsize; ) {
! 213: r = read(rxd, buf + len, bufsize - len);
! 214: if (r < 0) {
! 215: putmsg(0, "read(len) failed: %s", strerror(errno));
! 216: goto nodata;
! 217: }
! 218: if (r == 0) {
! 219: putmsg(0, "read(len) failed: EOF?");
! 220: goto nodata;
! 221: }
! 222: len += r;
1.1 root 223: }
224:
1.1.1.5 ! root 225: // データ本体。
! 226: databuf.resize(datalen);
! 227: len = 0;
! 228: for (auto datasize = databuf.size(); len < datasize; ) {
! 229: r = read(rxd, databuf.data() + len, datasize - len);
! 230: if (r < 0) {
! 231: putmsg(0, "read(data) failed: %s", strerror(errno));
! 232: goto nodata;
! 233: }
! 234: if (r == 0) {
! 235: putmsg(0, "read(data) failed: EOF?");
! 236: goto nodata;
! 237: }
! 238: len += r;
1.1 root 239: }
1.1.1.5 ! root 240: p->Assign(databuf.data(), len);
1.1 root 241:
242: return 0;
1.1.1.5 ! root 243:
! 244: nodata:
! 245: // 一旦全部読み捨てるくらいしか。
! 246: std::vector<uint8> dropbuf(1024);
! 247: for (;;) {
! 248: r = read(rxd, dropbuf.data(), dropbuf.size());
! 249: if (r <= 0) {
! 250: break;
! 251: }
! 252: }
! 253: return NODATA;
1.1 root 254: }
255:
256: // usermode を使えるのは同時に1人だけに限定する。
257: /*static*/ bool NetDriverSlirp::slirp_occupied = false;
258:
259:
260: //
261: // 裏スレッド
262: //
263:
264: // おそらく同じはずなので無駄な変換はしない。
265: #if SLIRP_POLL_IN == POLLIN && \
266: SLIRP_POLL_OUT == POLLOUT && \
267: SLIRP_POLL_PRI == POLLPRI && \
268: SLIRP_POLL_ERR == POLLERR && \
269: SLIRP_POLL_HUP == POLLHUP
270: #define POLL_EVENT_to_SLIRP_EVENT(x) (x)
271: #define SLIRP_EVENT_to_POLL_EVENT(x) (x)
272: #else
273: static int POLL_EVENT_to_SLIRP_EVENT(int pollevents)
274: {
275: int slevents = 0;
276: if ((pollevents & POLLIN)) slevents |= SLIRP_POLL_IN;
277: if ((pollevents & POLLOUT)) slevents |= SLIRP_POLL_OUT;
278: if ((pollevents & POLLPRI)) slevents |= SLIRP_POLL_PRI;
279: if ((pollevents & POLLERR)) slevents |= SLIRP_POLL_ERR;
280: if ((pollevents & POLLHUP)) slevents |= SLIRP_POLL_HUP;
281: return slevents;
282: }
283: static int SLIRP_EVENT_to_POLL_EVENT(int slevents)
284: {
285: int pollevents = 0;
286: if ((slevents & SLIRP_POLL_IN)) pollevents |= POLLIN;
287: if ((slevents & SLIRP_POLL_OUT)) pollevents |= POLLOUT;
288: if ((slevents & SLIRP_POLL_PRI)) pollevents |= POLLPRI;
289: if ((slevents & SLIRP_POLL_ERR)) pollevents |= POLLERR;
290: if ((slevents & SLIRP_POLL_HUP)) pollevents |= POLLHUP;
291: return pollevents;
292: }
293: #endif
294:
295: // タイマーは TimerNewCB() コールバックで確保して返す。
296: // 確保した領域そのものはライブラリが管理し、TimerFreeCB() コールバックで
297: // 解放する。
298: // 一方 timerlist は有効なタイマーのリストなので、期限が来たらこのリスト
299: // からは削除してよい。
300: class SlirpTimer
301: {
302: public:
303: SlirpTimer(SlirpTimerCb func_, void *arg_)
304: {
305: func = func_;
306: arg = arg_;
307: }
308:
309: SlirpTimerCb func {};
310: void *arg {};
311: int64 expire_msec {}; // 期限の(仮想?)絶対時刻 [msec]
312: int num {}; // デバッグ用のタイマー番号。
313: };
314:
315: static ssize_t send_packet_cb(const void *, size_t, void *);
316: static void guest_error_cb(const char *msg, void *);
317: static int64 clock_get_ns_cb(void *);
318: static void *timer_new_cb(SlirpTimerCb cb, void *cb_arg, void *);
319: static void timer_free_cb(void *timer, void *);
320: static void timer_mod_cb(void *timer, int64 expire_msec, void *);
321: static void register_poll_fd_cb(int fd, void *);
322: static void unregister_poll_fd_cb(int fd, void *);
323: static void notify_cb(void *);
324: static int add_poll_cb(int fd, int events, void *);
325: static int get_revents_cb(int idx, void *);
326:
327: static SlirpCb slirp_callbacks = {
328: .send_packet = send_packet_cb,
329: .guest_error = guest_error_cb,
330: .clock_get_ns = clock_get_ns_cb,
331: .timer_new = timer_new_cb,
332: .timer_free = timer_free_cb,
333: .timer_mod = timer_mod_cb,
334: .register_poll_fd = register_poll_fd_cb,
335: .unregister_poll_fd = unregister_poll_fd_cb,
336: .notify = notify_cb,
337: };
338:
339: // コンストラクタ
340: SlirpThread::SlirpThread(NetDriverSlirp *parent_)
341: : inherited(OBJ_NONE)
342: {
343: parent = parent_;
344: hostnet = dynamic_cast<HostNetDevice *>(parent->GetHostDev());
345: SetName(parent->GetName());
1.1.1.4 root 346: SetThreadName("SlirpThread");
1.1 root 347:
348: // コンストラクト後ただちにログ出力できるようここで一度追従しておく。
349: // 以降は親 (NetDriver側) の SetLogLevel() で変更する。
350: loglevel = parent->loglevel;
351: }
352:
353: // デストラクタ
354: SlirpThread::~SlirpThread()
355: {
356: TerminateThread();
1.1.1.3 root 357: Close();
1.1 root 358: }
359:
360: // 初期化。
361: // Device::Init() とは違い、NetDriver::InitDriver() から呼ばれる独自版。
362: // (表スレッドから見た裏スレッドへの) 受信側(RX)と送信側(TX)の
1.1.1.3 root 363: // ディスクリプタを書き戻す。
364: // 成功すれば true を返す。
365: // 失敗すれば (こちらのメンバ変数の) errmsg をセットして false を返す。
1.1 root 366: // これはスレッド起動前に (VM スレッドで) 呼ばれる。
367: bool
368: SlirpThread::InitBackend(const std::string& key, int *rxdp, int *txdp)
369: {
370: SlirpConfig config;
371: struct in_addr vnetwork;
372: struct in_addr vnetmask;
373: struct in6_addr vprefix_addr6;
374: uint vprefix_len;
375: int fds[2];
376:
1.1.1.3 root 377: const ConfigItem& netitem = gConfig->Find(key + "-usermode-net");
378: if (ParseConfigNet(netitem, &vnetwork, &vnetmask) == false) {
379: return false;
1.1 root 380: }
381:
1.1.1.3 root 382: const ConfigItem& net6item = gConfig->Find(key + "-usermode-net6");
383: if (ParseConfigNet6(net6item, &vprefix_addr6, &vprefix_len) == false) {
384: return false;
1.1 root 385: }
386:
1.1.1.3 root 387: // hostnet-usermode-hostfwd=<entry1>[;<entry2>[;<entry3>...]]
1.1 root 388: const ConfigItem& fwditem = gConfig->Find(key + "-usermode-hostfwd");
389: auto entries = string_split(fwditem.AsString(), ';');
1.1.1.3 root 390: if (entries.size() == 1) {
391: std::string entry = string_trim(entries[0]);
392: if (ParseConfigHostFwdEntry(fwditem, entry, "") == false) {
393: fwdinfo.clear();
1.1 root 394: return false;
395: }
1.1.1.3 root 396: } else {
397: for (const auto& e : entries) {
398: std::string entry = string_trim(e);
399: // エントリが複数ある時はそのうちのどこで起きたか表示したい。
400: std::string where = " at \"" + entry + "\"";
401: if (ParseConfigHostFwdEntry(fwditem, entry, where) == false) {
402: fwdinfo.clear();
403: return false;
404: }
1.1 root 405: }
406: }
407:
408: // Slirp を初期化。
409: memset(&config, 0, sizeof(config));
410: config.version = 4;
411: config.in_enabled = true;
412: config.vnetwork = vnetwork;
413: config.vnetmask = vnetmask;
414: config.vhost.s_addr = htonl(ntohl(vnetwork.s_addr) + 0x01);
415: config.vnameserver.s_addr = htonl(ntohl(vnetwork.s_addr) + 0x02);
416: config.vdhcp_start.s_addr = htonl(ntohl(vnetwork.s_addr) + 0x0a);
417: config.in6_enabled = true;
418: config.vprefix_addr6 = vprefix_addr6;
419: config.vprefix_len = vprefix_len;
420: config.vhost6 = vprefix_addr6;
421: config.vhost6.s6_addr[15] = 1;
422: config.vnameserver6 = vprefix_addr6;
423: config.vnameserver6.s6_addr[15] = 2;
424: gw6 = config.vhost6;
425: dns6 = config.vnameserver6;
426:
427: sl = slirp_new(&config, &slirp_callbacks, this);
428: if (sl == NULL) {
1.1.1.3 root 429: errmsg = "slirp_new() failed";
1.1 root 430: return false;
431: }
432:
433: for (const auto& fwd : fwdinfo) {
434: int r = slirp_add_hostfwd(sl, fwd.is_udp,
435: fwd.host.sin_addr, fwd.host.sin_port,
436: fwd.guest.sin_addr, fwd.guest.sin_port);
437: if (r != 0) {
438: char hname[INET_ADDRSTRLEN];
439: char gname[INET_ADDRSTRLEN];
440: hname[0] = '\0';
441: gname[0] = '\0';
442: inet_ntop(AF_INET, &fwd.host.sin_addr,
443: hname, (socklen_t)sizeof(hname));
444: inet_ntop(AF_INET, &fwd.guest.sin_addr,
445: gname, (socklen_t)sizeof(gname));
1.1.1.3 root 446: errmsg = string_format("slirp_add_hostfwd(%s,%s:%d,%s:%d) failed",
1.1 root 447: (fwd.is_udp ? "udp" : "tcp"),
448: hname, fwd.host.sin_port, gname, fwd.guest.sin_port);
1.1.1.3 root 449: goto abort;
1.1 root 450: }
451: }
452:
453: // libslirp のバージョンをチェック。
1.1.1.3 root 454: {
455: const char *version_str = slirp_version_string();
456: uint major;
457: uint minor;
458: uint patch;
459: if (sscanf(version_str, "%u.%u.%u", &major, &minor, &patch) == 3) {
460: putmsg(1, "libslirp version %u.%u", major, minor);
461: ver = VER(major, minor, patch);
462: }
1.1 root 463: }
464:
465: // 送信用のパイプを用意。
466: if (pipe(fds) < 0) {
1.1.1.3 root 467: errmsg = string_format("pipe(): %s", strerror(errno));
468: goto abort;
1.1 root 469: }
470: txd_r = fds[0];
471: txd_w = fds[1];
472:
473: // 受信用のパイプを用意。
474: if (pipe(fds) < 0) {
1.1.1.3 root 475: errmsg = string_format("pipe(): %s", strerror(errno));
476: goto abort;
1.1 root 477: }
478: rxd_r = fds[0];
479: rxd_w = fds[1];
480:
481: *rxdp = rxd_r;
482: *txdp = txd_w;
483:
1.1.1.3 root 484: // モニタを設定。(登録自体は hostnet で行ってある)
485: monitor = gMonitorManager->Find(ID_MONITOR_SLIRP);
486: assert(monitor);
487: monitor->obj = this;
1.1.1.5 ! root 488: monitor->SetCallback(&SlirpThread::MonitorScreen);
1.1 root 489: monitor->SetSize(80, 40);
490:
491: return true;
1.1.1.3 root 492:
493: abort:
494: Close();
495: return false;
1.1 root 496: }
497:
1.1.1.3 root 498: // hostnetN-usermode-net の引数 <addr>/<netmask> or <addr>/<netlen> を
499: // パースして *pnetwork, *pnetmask に格納する。
500: // 失敗したら errmsg をセットして false を返す。
1.1 root 501: bool
1.1.1.3 root 502: SlirpThread::ParseConfigNet(const ConfigItem& item,
503: struct in_addr *pnetwork, struct in_addr *pnetmask)
1.1 root 504: {
1.1.1.3 root 505: std::string net = item.AsString();
1.1 root 506:
1.1.1.3 root 507: auto list = string_split(net, '/');
508: if (list.empty()) {
509: syntax_error:
510: errmsg = item.ErrMsg("Syntax is <addr>/<netmask>");
511: return false;
512: }
1.1 root 513:
1.1.1.3 root 514: // アドレス。
515: auto addr = list[0];
516: if (addr.empty()) {
517: goto syntax_error;
518: }
519: if (inet_pton(AF_INET, addr.c_str(), pnetwork) < 1) {
520: errmsg = item.ErrMsg("Invalid network address");
521: return false;
522: }
523:
524: // 区切りの '/'。
525: if (list.size() == 1) {
526: goto syntax_error;
527: }
528:
529: // ここからネットマスク or ネットマスク長。
530: auto mask = list[1];
531: const char *p = mask.c_str();
532:
533: // アドレスでも長さでも必ず1文字目は10進数値。
534: // 特に strtoul() は先頭のスペースを無視して成功してしまうので
535: // 先頭がスペースでないことはチェックする必要がある。
536: if (*p < '0' || *p > '9') {
537: goto syntax_error;
538: }
539: char *end;
540: errno = 0;
541: unsigned long netlen = strtoul(p, &end, 10);
542: if (*end == '\0') {
543: // 数値だけから成っていれば、ネットマスク長かも知れない。
544:
545: if (errno == ERANGE) {
546: out_of_range:
547: errmsg = item.ErrMsg("netmask len is out of range");
1.1 root 548: return false;
1.1.1.3 root 549: } else if (errno != 0) {
550: errmsg = item.ErrMsg("Invalid netmask len: %s", strerror(errno));
551: return false;
552: }
553: // DHCP 配布アドレスまで入れるには最小でも /28 (16-2個) が必要。
554: if (netlen < 1 || netlen > 28) {
555: goto out_of_range;
1.1 root 556: }
1.1.1.3 root 557: pnetmask->s_addr = htonl(((1U << netlen) - 1) << (32 - netlen));
558: } else {
559: // 数値以外も含まれていれば、ネットマスクかも知れない。
560: if (inet_pton(AF_INET, p, pnetmask) < 1) {
561: errmsg = item.ErrMsg("Invalid netmask");
1.1 root 562: return false;
563: }
1.1.1.3 root 564: }
565:
566: // これ以上続くのはエラー。
567: if (list.size() > 2) {
568: goto syntax_error;
569: }
570:
571: return true;
572: }
573:
574: // hostnetN-usermode-net6 の引数 <addr6>/<prefixlen> をパースして
575: // *paddr6, *plen に格納する。
576: // 失敗したら errmsg をセットして false を返す。
577: bool
578: SlirpThread::ParseConfigNet6(const ConfigItem& item,
579: struct in6_addr *paddr6, uint *plen)
580: {
581: std::string net6 = item.AsString();
582:
583: auto list = string_split(net6, '/');
584: if (list.empty()) {
585: syntax_error:
586: errmsg = item.ErrMsg("Syntax is <v6addr>/<len>");
587: return false;
588: }
589:
590: // アドレス。
591: auto addr = list[0];
592: if (addr.empty()) {
593: goto syntax_error;
594: }
595: if (inet_pton(AF_INET6, addr.c_str(), paddr6) < 1) {
596: errmsg = item.ErrMsg("Invalid network address");
597: return false;
598: }
599:
600: // 区切りの '/'。
601: if (list.size() == 1) {
602: goto syntax_error;
603: }
604:
605: // プレフィックス長。
606: auto prefixlen = list[1];
607: const char *p = prefixlen.c_str();
608:
609: // strtoul() は先頭のスペースを無視して成功してしまうので
610: // 先頭がスペースでないことはチェックする必要がある。
611: if (*p < '0' || *p > '9') {
612: goto syntax_error;
613: }
614: char *end;
615: errno = 0;
616: unsigned long len = strtoul(p, &end, 10);
617: if (*end != '\0') {
618: goto syntax_error;
619: }
620: if (errno == ERANGE) {
621: out_of_range:
622: errmsg = item.ErrMsg("prefixlen is out of range");
623: return false;
624: } else if (errno != 0) {
625: errmsg = item.ErrMsg("Invalid netmask len: %s", strerror(errno));
626: return false;
627: }
628: // 適切な範囲がよく分からないのでとりあえず物理限界だけチェック。
629: if (len < 1 || len > 124) {
630: goto out_of_range;
631: }
632: *plen = len;
633:
634: // これ以上続くのはエラー。
635: if (list.size() > 2) {
636: goto syntax_error;
637: }
638:
639: return true;
640: }
641:
642: // hostnetN-usermode-hostfwd の引数のエントリ1つ分をパースして fwdinfo に
643: // 追加する。失敗したら errmsg をセットして false を返す。
644: //
645: // 引数は <entry> を複数ならセミコロンで区切ったもの。
646: // ここに渡される一つの <entry> の書式は次の通り。
647: // <entry> := <proto>,[<hostaddr>:]<hostport>,[<guestaddr>:]<guestport>
648: bool
649: SlirpThread::ParseConfigHostFwdEntry(const ConfigItem& item,
650: const std::string& entry, const std::string& where)
651: {
652: int r;
653:
654: // エントリが空なのは許容するか。
655: if (entry.empty()) {
656: return true;
657: }
658:
659: auto val = string_split(entry, ',');
660: if (val.size() != 3) {
661: syntax_error:
662: errmsg = item.ErrMsg(
663: "Syntax is <proto>,[<hostaddr>:]<port>,[<guestaddr>]:<port>[;...]"
664: + where);
665: return false;
666: }
667:
668: FwdInfo fwd;
669: memset(&fwd, 0, sizeof(fwd));
670:
671: // proto
672: auto proto = string_trim(val[0]);
673: if (strcasecmp(proto.c_str(), "tcp") == 0) {
674: fwd.is_udp = 0;
675: } else if (strcasecmp(proto.c_str(), "udp") == 0) {
676: fwd.is_udp = 1;
1.1 root 677: } else {
1.1.1.3 root 678: errmsg = item.ErrMsg("protocol must be \"tcp\" or \"udp\"" + where);
679: return false;
1.1 root 680: }
681:
1.1.1.3 root 682: // host
683: r = ParseAddrPort(item, val[1], &fwd.host, "host", where);
684: if (r < 0) {
685: goto syntax_error;
686: } else if (r == 0) {
1.1 root 687: return false;
688: }
1.1.1.3 root 689:
690: // guest
691: r = ParseAddrPort(item, val[2], &fwd.guest, "guest", where);
692: if (r < 0) {
693: goto syntax_error;
694: } else if (r == 0) {
695: return false;
696: }
697:
698: fwdinfo.push_back(fwd);
1.1 root 699:
700: return true;
701: }
702:
1.1.1.3 root 703: // "[アドレス:]ポート" 形式の hostport_arg からアドレスとポートを取り出して
704: // sin に格納する。
705: // 戻り値は 1 が成功、
706: // 0 なら失敗で errno はセット済み、
707: // -1 なら失敗で呼び出し元で syntax_error へ分岐。
708: int
709: SlirpThread::ParseAddrPort(const ConfigItem& item,
710: const std::string& hostport_arg, struct sockaddr_in *sin,
711: const char *which, const std::string& where)
712: {
713: std::string hostport = string_trim(hostport_arg);
714: if (hostport.empty()) {
715: return -1;
716: }
717:
718: // ':' で分離。
719: std::string port;
720: auto list = string_split(hostport, ':');
721: if (list.size() == 1) {
722: // ポートのみ。
723: port = list[0];
724: } else {
725: // list.size() == 0 はないので、2以上。
726: std::string host;
727: host = list[0];
728: port = list[1];
729:
730: // アドレス。
731: if (host.empty()) {
732: return -1;
733: }
734: if (inet_pton(AF_INET, host.c_str(), &sin->sin_addr) < 1) {
735: errmsg = item.ErrMsg("Invalid %s address%s", which, where.c_str());
736: return 0;
737: }
738: }
739:
740: // ポート。
741: const char *p = port.c_str();
742: if (*p < '0' || *p > '9') {
743: invalid_port:
744: errmsg = item.ErrMsg("Invalid %s port%s", which, where.c_str());
745: return 0;
746: }
747: char *end;
748: errno = 0;
749: unsigned long portnum = strtoul(p, &end, 10);
750: if (*end != '\0') {
751: goto invalid_port;
752: }
753: if (errno == ERANGE) {
754: out_of_range:
755: errmsg = item.ErrMsg("%s port is out of range%s", which, where.c_str());
756: return 0;
757: }
758: if (errno != 0) {
759: errmsg = item.ErrMsg("%s port: %s%s",
760: which, strerror(errno), where.c_str());
761: return 0;
762: }
763: if (portnum < 1 || portnum > 65535) {
764: goto out_of_range;
765: }
766:
767: // これ以上続くのはエラー。
768: if (list.size() > 2) {
769: return -1;
770: }
771:
772: sin->sin_port = portnum;
773: return 1;
774: }
775:
1.1 root 776: void
777: SlirpThread::Close()
778: {
779: txd_r.Close();
780: txd_w.Close();
781: rxd_r.Close();
782: rxd_w.Close();
783:
784: if (sl) {
785: for (const auto& fwd : fwdinfo) {
786: slirp_remove_hostfwd(sl, fwd.is_udp,
787: fwd.host.sin_addr, fwd.host.sin_port);
788: }
789: slirp_cleanup(sl);
790: sl = NULL;
791: }
792: }
793:
794: // スレッドの終了を指示
795: void
796: SlirpThread::Terminate()
797: {
798: txd_r.Close();
1.1.1.5 ! root 799: txd_w.Close();
! 800: rxd_r.Close();
! 801: rxd_w.Close();
1.1 root 802: }
803:
804: // スレッド
805: void
806: SlirpThread::ThreadRun()
807: {
808: SetThreadAffinityHint(AffinityClass::Light);
809:
810: while (exit_requested == false) {
811: // タイマー処理。
1.1.1.5 ! root 812: int64 cur_msec = nsec_to_msec(ClockGetNsCB());
1.1 root 813: for (auto it = timerlist.begin(); it != timerlist.end(); ) {
814: SlirpTimer *timer = *it;
815: if (timer->expire_msec <= cur_msec) {
816: // 期限が来ていれば登録されているハンドラを実行。
817: // このハンドラ内から TimerModCB() が呼ばれて
818: // timerlist が書き換わる可能性があるので先に削除。
819: timerlist.erase(it);
820: timer->func(timer->arg);
821: // この場合 it の状態が保証されなくなるので、
822: // もう一度先頭からやり直す。
823: it = timerlist.begin();
824: } else {
825: it++;
826: }
827: }
828:
829: // poll に入る前に内部のテーブル(文字列)を取得しておく。
830: UpdateInfo();
831:
832: // 先頭を txd とする。
833: pollfds.clear();
834: AddPollCB(txd_r, SLIRP_POLL_IN);
835:
836: // slirp ハンドルが持っているディスクリプタを pollfds[] にセット。
837: // コールバックで都度 AddPollCB() が呼ばれてそいつが追加している。
838: //
839: // slirp_pollfds_fill() の &timeout_ms 引数は、timeout_ms を
840: // 書き出す(out パラメータ)ではなく、現行の timeout_ms を必要に
841: // 応じて更新というか短くする(ref パラメータ)。つまり呼び出し前に
842: // 適切な値をセットしておく必要がある。値は必ず 1000 以下にしてくる
843: // ため、初期値も 1000 をセットするのがよさそう。
844: // ドキュメントをちゃんと書け。
845: uint32 timeout_ms = 1000;
846: slirp_pollfds_fill(sl, &timeout_ms, add_poll_cb, this);
847:
848: int err = poll(pollfds.data(), pollfds.size(), timeout_ms);
849: if (err < 0) {
850: if (errno == EINTR) {
851: continue;
852: }
853: // XXX どうする?
854: putmsg(0, "poll failed: %s", strerror(errno));
855: break;
856: }
857:
858: // txd に何か起きた。
859: if (pollfds[0].revents != 0) {
860: // txd のクローズはこのスレッドの終了通知。
861: if ((pollfds[0].revents & (POLLERR | POLLHUP | POLLNVAL))) {
862: exit_requested = true;
863: continue;
864: }
865:
866: // txd への着信は VM (-> HostNet スレッド) からのパケット送信。
867: if ((pollfds[0].revents & POLLIN)) {
868: Write();
869: }
870: }
871:
872: // poll() 完了後に slirp ハンドルの持っている各ディスクリプタの
873: // revents (GetReventsCB() コールバックを通じて取得する) に応じた
874: // 処理をするようだ。
875: slirp_pollfds_poll(sl, (err < 0), get_revents_cb, this);
876: }
877: }
878:
879: // slirp_pollfds_fill() から呼ばれるコールバック。
880: // fd, events をこっちの pollfds[] に追加し、追加したインデックスを返す。
881: int
882: SlirpThread::AddPollCB(int fd, int slevents)
883: {
884: struct pollfd pfd;
885:
886: pfd.fd = fd;
887: pfd.events = SLIRP_EVENT_to_POLL_EVENT(slevents);
888: pfd.revents = 0;
889:
890: int idx = pollfds.size();
891: pollfds.emplace_back(pfd);
892: return idx;
893: }
894:
895: // slirp_pollfds_poll() から呼ばれるコールバック。
896: // pollfds[idx] の revents (SLRIP_POLL_*) を返す。
897: int
898: SlirpThread::GetReventsCB(int idx)
899: {
900: if (idx < 0 || idx >= pollfds.size()) {
901: return 0;
902: }
903:
904: int slevents = POLL_EVENT_to_SLIRP_EVENT(pollfds[idx].revents);
905: return slevents;
906: }
907:
908: // HostNet(NetDriver) スレッドから txd に着信したパケットを Slirp に送信する。
909: void
910: SlirpThread::Write()
911: {
912: uint32 len;
913: int r;
914:
915: // 先頭4バイトに後続パケット長を入れてある。
916: r = read(txd_r, &len, sizeof(len));
917: if (r < 0) {
918: putmsg(0, "Write: read(len) failed: %s", strerror(errno));
919: return;
920: }
921:
922: std::vector<uint8> buf(len);
923: r = read(txd_r, buf.data(), buf.size());
924: if (r < 0) {
925: putmsg(0, "Write: read(buf) failed: %s", strerror(errno));
926: return;
927: }
928:
929: // 一部のフレームを libslirp に渡す前にこちらで処理する。
930: if (__predict_false(WriteHook(buf))) {
931: return;
932: }
933:
934: if (__predict_false(loglevel >= 2)) {
935: putmsgn("Send to SLIRP:");
936: DumpFrame(buf.data(), buf.size());
937: }
938: slirp_input(sl, buf.data(), buf.size());
939: }
940:
941: // 一部の frame を libslirp に渡す前にこちらで処理する。
942: // 処理した (libslirp に渡さない) 場合は true を返す。
943: // 処理しない (libslirp に渡す) 場合は false を返す。
944: //
945: // 現状、自分(ルータと DNS サーバ)以外への ICMPv6 Echo Request が該当。
946: bool
947: SlirpThread::WriteHook(const std::vector<uint8>& frame) const
948: {
949: const uint8 *payload;
950: size_t payloadlen;
951:
952: // XXX libslirp-4.7.0 は、自身が管理するルータ・DNS サーバ以外の
953: // アドレスへの ICMPv6 Echo Request の送出に対する処理が未実装。
954: // それ自体はいいのだが、slirp_input() がそのパケットを受け取ると
955: // GLib の機構でコンソールにログを出してしまい、このログはこちらで制御
956: // 出来ない (しにくい) のにユーザに目立つ形で表示されるので大変困る。
957: // そこで、このパケットを事前にここで検出して、自分で処理というか
958: // ドロップして putmsg() で控えめにログを出すことにする。
959: // libslirp-4.8.0 で修正された。
960: if (ver >= VER(4, 8, 0)) {
961: return false;
962: }
963:
964: // イーサネットフレームが IPv6。
965: if (__predict_false(frame.size() < 14)) {
966: return false;
967: }
968: if (frame[12] != 0x86 || frame[13] != 0xdd) {
969: return false;
970: }
971:
972: struct ipv6_hdr {
973: uint8 ver_cls; // 上位4ビットが version
974: uint8 clf_flw;
975: uint16 flowlabel;
976: uint16 payloadlen;
977: uint8 nexthdr;
978: uint8 hoplimit;
979: uint8 srcip[16];
980: uint8 dstip[16];
981: } __packed;
982: payload = frame.data() + 14;
983: payloadlen = frame.size() - 14;
984: const ipv6_hdr& ipv6 = *(const ipv6_hdr *)payload;
985: if (__predict_false(payloadlen < sizeof(ipv6_hdr))) {
986: return false;
987: }
988: // 先に NextHdr をチェック。途中に別ヘッダが挟まるケースは諦める。
989: if (ipv6.nexthdr != 58) {
990: return false;
991: }
992:
993: struct icmp_hdr {
994: uint8 type;
995: uint8 code;
996: uint16 cksum;
997: } __packed;
998: payload += sizeof(ipv6_hdr);
999: payloadlen -= sizeof(ipv6_hdr);
1000: const icmp_hdr& icmp = *(const icmp_hdr *)payload;
1001: if (__predict_false(payloadlen < sizeof(icmp_hdr))) {
1002: return false;
1003: }
1004: if (icmp.type != 128) { // ICMPV6 Echo Request
1005: return false;
1006: }
1007:
1008: // ICMPv6 Echo Reuqest は確定したのでここで宛先をチェック。
1009: if (0) {
1010: char srcname[100];
1011: char dstname[100];
1012: inet_ntop(AF_INET6, ipv6.srcip, srcname, (socklen_t)sizeof(srcname));
1013: inet_ntop(AF_INET6, ipv6.dstip, dstname, (socklen_t)sizeof(dstname));
1014: printf("ICMPv6 src=%s dst=%s\n", srcname, dstname);
1015: }
1016:
1017: // 宛先が自分のルータか DNS サーバなら処理可能なので何もしない。
1018: if (memcmp(ipv6.dstip, &gw6, sizeof(gw6)) == 0) {
1019: return false;
1020: }
1021: if (memcmp(ipv6.dstip, &dns6, sizeof(dns6)) == 0) {
1022: return false;
1023: }
1.1.1.2 root 1024: // リンクローカルはここで作って比較。
1025: struct in6_addr linklocal;
1026: memset(&linklocal, 0, sizeof(linklocal));
1027: linklocal.s6_addr[0] = 0xfe;
1028: linklocal.s6_addr[1] = 0x80;
1029: memcpy(&linklocal.s6_addr[8], &gw6.s6_addr[8], 8);
1030: if (memcmp(ipv6.dstip, &linklocal, sizeof(linklocal)) == 0) {
1031: return false;
1032: }
1033: memcpy(&linklocal.s6_addr[8], &dns6.s6_addr[8], 8);
1034: if (memcmp(ipv6.dstip, &linklocal, sizeof(linklocal)) == 0) {
1035: return false;
1036: }
1.1 root 1037:
1038: // ここから未実装ログが出る組み合わせ。
1039:
1040: // 統計情報。
1041: hostnet->CountTXUnsupp(frame.size());
1042:
1043: return true;
1044: }
1045:
1046: // Slirp ライブラリがパケットを "送信した" 時に呼ばれるコールバック。
1047: // なのでこちらから見れば HUB から NIC への着信。
1048: ssize_t
1049: SlirpThread::SendPacketCB(const void *src, size_t srclen)
1050: {
1051: if (__predict_false(loglevel >= 2)) {
1052: putmsgn("Recv from SLIRP");
1053: DumpFrame(src, srclen);
1054: }
1055:
1056: // 受信ディスクリプタ (の書き込み端) に書き込む。
1057: // 先頭4バイトはホストバイトオーダーでの後続のパケット長。
1058: uint32 lenbuf = srclen;
1059:
1060: struct iovec iov[2];
1061: iov[0].iov_base = &lenbuf;
1062: iov[0].iov_len = sizeof(lenbuf);
1063: iov[1].iov_base = const_cast<void *>(src);
1064: iov[1].iov_len = srclen;
1065:
1066: ssize_t r = writev(rxd_w, &iov[0], countof(iov));
1067: if (r < 0) {
1068: putmsg(0, "writev failed: %s", strerror(errno));
1069: return -1;
1070: }
1071: if (r < sizeof(lenbuf) + srclen) {
1072: putmsg(0, "writev failed: too short");
1073: return -1;
1074: }
1075:
1076: return srclen;
1077: }
1078:
1079: // 現在の仮想時間を返すコールバック。
1080: int64
1081: SlirpThread::ClockGetNsCB() const
1082: {
1083: // XXX scheduler がセットされる前から呼ばれるのでとりあえず。
1084: if (__predict_false(scheduler == NULL)) {
1085: return 0;
1086: }
1087: uint64 time = scheduler->GetVirtTime();
1088: return (int64)time;
1089: }
1090:
1091: // 新しいタイマー(イベント)を返すコールバック。
1092: // 引数は時間が来たら呼ぶハンドラと引数。
1093: void *
1094: SlirpThread::TimerNewCB(SlirpTimerCb func, void *arg)
1095: {
1096: SlirpTimer *newtimer = new SlirpTimer(func, arg);
1097: newtimer->num = latest_timer_num++;
1098: return newtimer;
1099: }
1100:
1101: // タイマーを削除する。
1102: void
1103: SlirpThread::TimerFreeCB(SlirpTimer *timer)
1104: {
1105: // まだアクティブならそれも削除する。
1106: timerlist.remove(timer);
1107: delete timer;
1108: }
1109:
1110: // タイマーの期限を新しく設定する?。
1111: void
1112: SlirpThread::TimerModCB(SlirpTimer *timer, int64 expire_msec)
1113: {
1114: timer->expire_msec = expire_msec;
1115:
1116: // リストから一旦削除してから、適切なところに挿入し直す。
1117: timerlist.remove(timer);
1118: if (timerlist.empty()) {
1119: timerlist.push_back(timer);
1120: } else {
1121: for (auto it = timerlist.begin(); it != timerlist.end(); ++it) {
1122: auto *t = *it;
1123: if (t->expire_msec > timer->expire_msec) {
1124: timerlist.insert(it, timer);
1125: break;
1126: }
1127: }
1128: }
1129: }
1130:
1131: // ゲスト (VM) から送信しようとしたパケットのエラーメッセージ。
1132: // とりあえずログに出しておく。
1133: void
1134: SlirpThread::GuestErrorCB(const char *msg)
1135: {
1136: putmsg(1, "libslirp: %s", msg);
1137: }
1138:
1139: // Slirp の内部テーブルのこちら側のコピーを更新する。
1140: // メインループ内から呼ばれる。
1141: void
1142: SlirpThread::UpdateInfo()
1143: {
1144: // 取得。
1145: char *newconn = slirp_connection_info(sl);
1146: char *newnbr = slirp_neighbor_info(sl);
1147:
1148: // 更新が必要か。前回と同じなら今取得したほうを解放。
1149: if (conninfo && strcmp(conninfo, newconn) == 0) {
1150: free(newconn);
1151: newconn = NULL;
1152: }
1153: if (nbrinfo && strcmp(nbrinfo, newnbr) == 0) {
1154: free(newnbr);
1155: newnbr = NULL;
1156: }
1157: // どちらも更新なしならここで終了。
1158: if (newconn == NULL && newnbr == NULL) {
1159: return;
1160: }
1161:
1162: // 更新。
1163: char *oldconn = NULL;
1164: char *oldnbr = NULL;
1165: {
1.1.1.4 root 1166: std::lock_guard<std::mutex> lock(info_mtx);
1.1 root 1167:
1168: if (newconn) {
1169: oldconn = conninfo;
1170: conninfo = newconn;
1171: }
1172: if (newnbr) {
1173: oldnbr = nbrinfo;
1174: nbrinfo = newnbr;
1175: }
1176: }
1177:
1178: free(oldconn);
1179: free(oldnbr);
1180: }
1181:
1182: void
1.1.1.5 ! root 1183: SlirpThread::MonitorScreen(Monitor *, TextScreen& screen)
1.1 root 1184: {
1185: std::string local_conn;
1186: std::string local_nbr;
1187: int y;
1188:
1189: // スレッド越しにコピーを取る。
1190: {
1.1.1.4 root 1191: std::lock_guard<std::mutex> lock(info_mtx);
1.1 root 1192: local_conn = std::string(conninfo);
1193: local_nbr = std::string(nbrinfo);
1194: }
1195:
1.1.1.3 root 1196: // Connection State の UDP 欄は [0 sec] の次に一瞬だけ [42949?? sec]
1197: // くらいになる。これは slirp_connection_info() が文字列を返してきた時点で
1.1 root 1198: // こうなっているのでこっちの話ではないのだが、あまりに幼稚すぎて
1199: // 自分のソフトでこれが表示されるのは恥ずかしいのでパッチしておく。
1.1.1.3 root 1200: // UDP[4294967 sec]
1201: static const char udphdr[] = "UDP[";
1202: static const char patch[] = "expired] ";
1203: for (char *s = &local_conn[0]; (s = strstr(s, udphdr)) != NULL; ) {
1204: const char *end;
1205: s += 4;
1206: for (end = s; '0' <= *end && *end <= '9'; end++)
1207: ; // nop
1208: if (__predict_false(end - s >= 7)) {
1209: for (const char *p = patch; *s && *p; ) {
1210: *s++ = *p++;
1211: }
1212: }
1.1 root 1213: }
1214:
1215: screen.Clear();
1216: y = 0;
1217:
1218: auto lines = string_split(local_conn, '\n');
1219: for (auto& buf : lines) {
1220: screen.Puts(0, y++, buf.c_str());
1221: }
1222:
1223: lines = string_split(local_nbr, '\n');
1224: for (auto& buf : lines) {
1225: screen.Puts(0, y++, buf.c_str());
1226: }
1227: // あふれたら諦める…。
1228: }
1229:
1230: // src から srclen バイトの16進ダンプをログに(無条件に)出力する。
1231: void
1232: SlirpThread::DumpHex(const void *src, size_t srclen) const
1233: {
1234: std::vector<std::string> lines = HostNetDevice::DumpHex(src, srclen);
1235: for (auto& line : lines) {
1236: putmsgn("%s", line.c_str());
1237: }
1238: }
1239:
1240: // イーサネットフレームを整形してログに(無条件に)出力する。
1241: void
1242: SlirpThread::DumpFrame(const void *src, size_t srclen) const
1243: {
1244: std::vector<std::string> lines = HostNetDevice::DumpFrame(src, srclen);
1245: for (auto& line : lines) {
1246: putmsgn("%s", line.c_str());
1247: }
1248: }
1249:
1250: // コールバックのトランポリン関数たち
1251:
1252: static ssize_t
1253: send_packet_cb(const void *buf, size_t buflen, void *opaque)
1254: {
1255: auto *backend = reinterpret_cast<SlirpThread *>(opaque);
1256: return backend->SendPacketCB(buf, buflen);
1257: }
1258:
1259: static void
1260: guest_error_cb(const char *msg, void *opaque)
1261: {
1262: auto *backend = reinterpret_cast<SlirpThread *>(opaque);
1263: backend->GuestErrorCB(msg);
1264: }
1265:
1266: static int64
1267: clock_get_ns_cb(void *opaque)
1268: {
1269: auto *backend = reinterpret_cast<SlirpThread *>(opaque);
1270: return backend->ClockGetNsCB();
1271: }
1272:
1273: static void *
1274: timer_new_cb(SlirpTimerCb func, void *arg, void *opaque)
1275: {
1276: auto *backend = reinterpret_cast<SlirpThread *>(opaque);
1277: return backend->TimerNewCB(func, arg);
1278: }
1279:
1280: static void
1281: timer_free_cb(void *timer, void *opaque)
1282: {
1283: auto *backend = reinterpret_cast<SlirpThread *>(opaque);
1284: auto *sltimer = reinterpret_cast<SlirpTimer *>(timer);
1285: return backend->TimerFreeCB(sltimer);
1286: }
1287:
1288: static void
1289: timer_mod_cb(void *timer, int64 expire_msec, void *opaque)
1290: {
1291: auto *backend = reinterpret_cast<SlirpThread *>(opaque);
1292: auto *sltimer = reinterpret_cast<SlirpTimer *>(timer);
1293: backend->TimerModCB(sltimer, expire_msec);
1294: }
1295:
1296: // おそらく不要で何もしなくていいのだが、コールバックを NULL に出来ないため。
1297: static void
1298: register_poll_fd_cb(int fd, void *)
1299: {
1300: }
1301:
1302: // おそらく不要で何もしなくていいのだが、コールバックを NULL に出来ないため。
1303: static void
1304: unregister_poll_fd_cb(int fd, void *)
1305: {
1306: }
1307:
1308: // シングルスレッド動作なので不要なはずだが、コールバックを NULL に出来ない。
1309: static void
1310: notify_cb(void *)
1311: {
1312: }
1313:
1314: static int
1315: add_poll_cb(int fd, int events, void *opaque)
1316: {
1317: auto *backend = reinterpret_cast<SlirpThread *>(opaque);
1318: return backend->AddPollCB(fd, events);
1319: }
1320:
1321: static int
1322: get_revents_cb(int idx, void *opaque)
1323: {
1324: auto *backend = reinterpret_cast<SlirpThread *>(opaque);
1325: return backend->GetReventsCB(idx);
1326: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.