From 1bcf3de7f521d83185cce580db2dea6d50a617b6 Mon Sep 17 00:00:00 2001 From: Ren Kararou Date: Sun, 26 Jan 2025 03:41:25 -0600 Subject: try bazel --- .builds/arch-bazel.yml | 16 ++ .builds/freebsd-bazel.yml | 13 ++ .gitignore | 4 + MODULE.bazel | 0 MODULE.bazel.lock | 240 +++++++++++++++++++++ inc/handlers.h | 53 ----- inc/netascii.h | 10 - inc/packet.h | 61 ------ makefile | 4 +- nbtpd/BUILD | 33 +++ nbtpd/handlers.c | 535 ++++++++++++++++++++++++++++++++++++++++++++++ nbtpd/handlers.h | 54 +++++ nbtpd/main.c | 313 +++++++++++++++++++++++++++ nbtpd/netascii.c | 53 +++++ nbtpd/netascii.h | 10 + nbtpd/packet.c | 126 +++++++++++ nbtpd/packet.h | 61 ++++++ src/handlers.c | 535 ---------------------------------------------- src/main.c | 313 --------------------------- src/netascii.c | 53 ----- src/packet.c | 125 ----------- 21 files changed, 1460 insertions(+), 1152 deletions(-) create mode 100644 .builds/arch-bazel.yml create mode 100644 .builds/freebsd-bazel.yml create mode 100644 MODULE.bazel create mode 100644 MODULE.bazel.lock delete mode 100644 inc/handlers.h delete mode 100644 inc/netascii.h delete mode 100644 inc/packet.h create mode 100644 nbtpd/BUILD create mode 100644 nbtpd/handlers.c create mode 100644 nbtpd/handlers.h create mode 100644 nbtpd/main.c create mode 100644 nbtpd/netascii.c create mode 100644 nbtpd/netascii.h create mode 100644 nbtpd/packet.c create mode 100644 nbtpd/packet.h delete mode 100644 src/handlers.c delete mode 100644 src/main.c delete mode 100644 src/netascii.c delete mode 100644 src/packet.c diff --git a/.builds/arch-bazel.yml b/.builds/arch-bazel.yml new file mode 100644 index 0000000..f9337e6 --- /dev/null +++ b/.builds/arch-bazel.yml @@ -0,0 +1,16 @@ +image: archlinux +packages: + - base-devel + - clang + - bazel +sources: + - https://git.sr.ht/~spicywolf/nbtpd +triggers: + - action: email + condition: always + to: ~spicywolf/public-inbox@lists.sr.ht +tasks: + - build: | + cd nbtpd + bazel build //nbtpd:nbtpd + diff --git a/.builds/freebsd-bazel.yml b/.builds/freebsd-bazel.yml new file mode 100644 index 0000000..f2094af --- /dev/null +++ b/.builds/freebsd-bazel.yml @@ -0,0 +1,13 @@ +image: freebsd/latest +packages: + - bazel +sources: + - https://git.sr.ht/~spicywolf/nbtpd +triggers: + - action: email + condition: always + to: ~spicywolf/public-inbox@lists.sr.ht +tasks: + - build: | + cd nbtpd + bazel build //nbtpd:nbtpd diff --git a/.gitignore b/.gitignore index a7b2d8c..937adb3 100644 --- a/.gitignore +++ b/.gitignore @@ -13,4 +13,8 @@ dbg/ *.so *.pch nbtpd +!nbtpd/ a.out + +# bazel +bazel-* diff --git a/MODULE.bazel b/MODULE.bazel new file mode 100644 index 0000000..e69de29 diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock new file mode 100644 index 0000000..99f9358 --- /dev/null +++ b/MODULE.bazel.lock @@ -0,0 +1,240 @@ +{ + "lockFileVersion": 16, + "registryFileHashes": { + "https://bcr.bazel.build/bazel_registry.json": "8a28e4aff06ee60aed2a8c281907fb8bcbf3b753c91fb5a5c57da3215d5b3497", + "https://bcr.bazel.build/modules/abseil-cpp/20210324.2/MODULE.bazel": "7cd0312e064fde87c8d1cd79ba06c876bd23630c83466e9500321be55c96ace2", + "https://bcr.bazel.build/modules/abseil-cpp/20211102.0/MODULE.bazel": "70390338f7a5106231d20620712f7cccb659cd0e9d073d1991c038eb9fc57589", + "https://bcr.bazel.build/modules/abseil-cpp/20230125.1/MODULE.bazel": "89047429cb0207707b2dface14ba7f8df85273d484c2572755be4bab7ce9c3a0", + "https://bcr.bazel.build/modules/abseil-cpp/20230802.0.bcr.1/MODULE.bazel": "1c8cec495288dccd14fdae6e3f95f772c1c91857047a098fad772034264cc8cb", + "https://bcr.bazel.build/modules/abseil-cpp/20230802.0/MODULE.bazel": "d253ae36a8bd9ee3c5955384096ccb6baf16a1b1e93e858370da0a3b94f77c16", + "https://bcr.bazel.build/modules/abseil-cpp/20230802.1/MODULE.bazel": "fa92e2eb41a04df73cdabeec37107316f7e5272650f81d6cc096418fe647b915", + "https://bcr.bazel.build/modules/abseil-cpp/20240116.1/MODULE.bazel": "37bcdb4440fbb61df6a1c296ae01b327f19e9bb521f9b8e26ec854b6f97309ed", + "https://bcr.bazel.build/modules/abseil-cpp/20240116.1/source.json": "9be551b8d4e3ef76875c0d744b5d6a504a27e3ae67bc6b28f46415fd2d2957da", + "https://bcr.bazel.build/modules/bazel_features/1.1.1/MODULE.bazel": "27b8c79ef57efe08efccbd9dd6ef70d61b4798320b8d3c134fd571f78963dbcd", + "https://bcr.bazel.build/modules/bazel_features/1.11.0/MODULE.bazel": "f9382337dd5a474c3b7d334c2f83e50b6eaedc284253334cf823044a26de03e8", + "https://bcr.bazel.build/modules/bazel_features/1.15.0/MODULE.bazel": "d38ff6e517149dc509406aca0db3ad1efdd890a85e049585b7234d04238e2a4d", + "https://bcr.bazel.build/modules/bazel_features/1.17.0/MODULE.bazel": "039de32d21b816b47bd42c778e0454217e9c9caac4a3cf8e15c7231ee3ddee4d", + "https://bcr.bazel.build/modules/bazel_features/1.18.0/MODULE.bazel": "1be0ae2557ab3a72a57aeb31b29be347bcdc5d2b1eb1e70f39e3851a7e97041a", + "https://bcr.bazel.build/modules/bazel_features/1.19.0/MODULE.bazel": "59adcdf28230d220f0067b1f435b8537dd033bfff8db21335ef9217919c7fb58", + "https://bcr.bazel.build/modules/bazel_features/1.21.0/MODULE.bazel": "675642261665d8eea09989aa3b8afb5c37627f1be178382c320d1b46afba5e3b", + "https://bcr.bazel.build/modules/bazel_features/1.21.0/source.json": "3e8379efaaef53ce35b7b8ba419df829315a880cb0a030e5bb45c96d6d5ecb5f", + "https://bcr.bazel.build/modules/bazel_features/1.4.1/MODULE.bazel": "e45b6bb2350aff3e442ae1111c555e27eac1d915e77775f6fdc4b351b758b5d7", + "https://bcr.bazel.build/modules/bazel_features/1.9.1/MODULE.bazel": "8f679097876a9b609ad1f60249c49d68bfab783dd9be012faf9d82547b14815a", + "https://bcr.bazel.build/modules/bazel_skylib/1.0.3/MODULE.bazel": "bcb0fd896384802d1ad283b4e4eb4d718eebd8cb820b0a2c3a347fb971afd9d8", + "https://bcr.bazel.build/modules/bazel_skylib/1.1.1/MODULE.bazel": "1add3e7d93ff2e6998f9e118022c84d163917d912f5afafb3058e3d2f1545b5e", + "https://bcr.bazel.build/modules/bazel_skylib/1.2.0/MODULE.bazel": "44fe84260e454ed94ad326352a698422dbe372b21a1ac9f3eab76eb531223686", + "https://bcr.bazel.build/modules/bazel_skylib/1.2.1/MODULE.bazel": "f35baf9da0efe45fa3da1696ae906eea3d615ad41e2e3def4aeb4e8bc0ef9a7a", + "https://bcr.bazel.build/modules/bazel_skylib/1.3.0/MODULE.bazel": "20228b92868bf5cfc41bda7afc8a8ba2a543201851de39d990ec957b513579c5", + "https://bcr.bazel.build/modules/bazel_skylib/1.4.1/MODULE.bazel": "a0dcb779424be33100dcae821e9e27e4f2901d9dfd5333efe5ac6a8d7ab75e1d", + "https://bcr.bazel.build/modules/bazel_skylib/1.4.2/MODULE.bazel": "3bd40978e7a1fac911d5989e6b09d8f64921865a45822d8b09e815eaa726a651", + "https://bcr.bazel.build/modules/bazel_skylib/1.5.0/MODULE.bazel": "32880f5e2945ce6a03d1fbd588e9198c0a959bb42297b2cfaf1685b7bc32e138", + "https://bcr.bazel.build/modules/bazel_skylib/1.6.1/MODULE.bazel": "8fdee2dbaace6c252131c00e1de4b165dc65af02ea278476187765e1a617b917", + "https://bcr.bazel.build/modules/bazel_skylib/1.7.0/MODULE.bazel": "0db596f4563de7938de764cc8deeabec291f55e8ec15299718b93c4423e9796d", + "https://bcr.bazel.build/modules/bazel_skylib/1.7.1/MODULE.bazel": "3120d80c5861aa616222ec015332e5f8d3171e062e3e804a2a0253e1be26e59b", + "https://bcr.bazel.build/modules/bazel_skylib/1.7.1/source.json": "f121b43eeefc7c29efbd51b83d08631e2347297c95aac9764a701f2a6a2bb953", + "https://bcr.bazel.build/modules/buildozer/7.1.2/MODULE.bazel": "2e8dd40ede9c454042645fd8d8d0cd1527966aa5c919de86661e62953cd73d84", + "https://bcr.bazel.build/modules/buildozer/7.1.2/source.json": "c9028a501d2db85793a6996205c8de120944f50a0d570438fcae0457a5f9d1f8", + "https://bcr.bazel.build/modules/google_benchmark/1.8.2/MODULE.bazel": "a70cf1bba851000ba93b58ae2f6d76490a9feb74192e57ab8e8ff13c34ec50cb", + "https://bcr.bazel.build/modules/googletest/1.11.0/MODULE.bazel": "3a83f095183f66345ca86aa13c58b59f9f94a2f81999c093d4eeaa2d262d12f4", + "https://bcr.bazel.build/modules/googletest/1.14.0.bcr.1/MODULE.bazel": "22c31a561553727960057361aa33bf20fb2e98584bc4fec007906e27053f80c6", + "https://bcr.bazel.build/modules/googletest/1.14.0.bcr.1/source.json": "41e9e129f80d8c8bf103a7acc337b76e54fad1214ac0a7084bf24f4cd924b8b4", + "https://bcr.bazel.build/modules/googletest/1.14.0/MODULE.bazel": "cfbcbf3e6eac06ef9d85900f64424708cc08687d1b527f0ef65aa7517af8118f", + "https://bcr.bazel.build/modules/jsoncpp/1.9.5/MODULE.bazel": "31271aedc59e815656f5736f282bb7509a97c7ecb43e927ac1a37966e0578075", + "https://bcr.bazel.build/modules/jsoncpp/1.9.5/source.json": "4108ee5085dd2885a341c7fab149429db457b3169b86eb081fa245eadf69169d", + "https://bcr.bazel.build/modules/libpfm/4.11.0/MODULE.bazel": "45061ff025b301940f1e30d2c16bea596c25b176c8b6b3087e92615adbd52902", + "https://bcr.bazel.build/modules/platforms/0.0.10/MODULE.bazel": "8cb8efaf200bdeb2150d93e162c40f388529a25852b332cec879373771e48ed5", + "https://bcr.bazel.build/modules/platforms/0.0.10/source.json": "f22828ff4cf021a6b577f1bf6341cb9dcd7965092a439f64fc1bb3b7a5ae4bd5", + "https://bcr.bazel.build/modules/platforms/0.0.4/MODULE.bazel": "9b328e31ee156f53f3c416a64f8491f7eb731742655a47c9eec4703a71644aee", + "https://bcr.bazel.build/modules/platforms/0.0.5/MODULE.bazel": "5733b54ea419d5eaf7997054bb55f6a1d0b5ff8aedf0176fef9eea44f3acda37", + "https://bcr.bazel.build/modules/platforms/0.0.6/MODULE.bazel": "ad6eeef431dc52aefd2d77ed20a4b353f8ebf0f4ecdd26a807d2da5aa8cd0615", + "https://bcr.bazel.build/modules/platforms/0.0.7/MODULE.bazel": "72fd4a0ede9ee5c021f6a8dd92b503e089f46c227ba2813ff183b71616034814", + "https://bcr.bazel.build/modules/platforms/0.0.8/MODULE.bazel": "9f142c03e348f6d263719f5074b21ef3adf0b139ee4c5133e2aa35664da9eb2d", + "https://bcr.bazel.build/modules/protobuf/21.7/MODULE.bazel": "a5a29bb89544f9b97edce05642fac225a808b5b7be74038ea3640fae2f8e66a7", + "https://bcr.bazel.build/modules/protobuf/27.0/MODULE.bazel": "7873b60be88844a0a1d8f80b9d5d20cfbd8495a689b8763e76c6372998d3f64c", + "https://bcr.bazel.build/modules/protobuf/27.1/MODULE.bazel": "703a7b614728bb06647f965264967a8ef1c39e09e8f167b3ca0bb1fd80449c0d", + "https://bcr.bazel.build/modules/protobuf/29.0-rc2/MODULE.bazel": "6241d35983510143049943fc0d57937937122baf1b287862f9dc8590fc4c37df", + "https://bcr.bazel.build/modules/protobuf/29.0/MODULE.bazel": "319dc8bf4c679ff87e71b1ccfb5a6e90a6dbc4693501d471f48662ac46d04e4e", + "https://bcr.bazel.build/modules/protobuf/29.0/source.json": "b857f93c796750eef95f0d61ee378f3420d00ee1dd38627b27193aa482f4f981", + "https://bcr.bazel.build/modules/protobuf/3.19.0/MODULE.bazel": "6b5fbb433f760a99a22b18b6850ed5784ef0e9928a72668b66e4d7ccd47db9b0", + "https://bcr.bazel.build/modules/pybind11_bazel/2.11.1/MODULE.bazel": "88af1c246226d87e65be78ed49ecd1e6f5e98648558c14ce99176da041dc378e", + "https://bcr.bazel.build/modules/pybind11_bazel/2.11.1/source.json": "be4789e951dd5301282729fe3d4938995dc4c1a81c2ff150afc9f1b0504c6022", + "https://bcr.bazel.build/modules/re2/2023-09-01/MODULE.bazel": "cb3d511531b16cfc78a225a9e2136007a48cf8a677e4264baeab57fe78a80206", + "https://bcr.bazel.build/modules/re2/2023-09-01/source.json": "e044ce89c2883cd957a2969a43e79f7752f9656f6b20050b62f90ede21ec6eb4", + "https://bcr.bazel.build/modules/rules_android/0.1.1/MODULE.bazel": "48809ab0091b07ad0182defb787c4c5328bd3a278938415c00a7b69b50c4d3a8", + "https://bcr.bazel.build/modules/rules_android/0.1.1/source.json": "e6986b41626ee10bdc864937ffb6d6bf275bb5b9c65120e6137d56e6331f089e", + "https://bcr.bazel.build/modules/rules_cc/0.0.1/MODULE.bazel": "cb2aa0747f84c6c3a78dad4e2049c154f08ab9d166b1273835a8174940365647", + "https://bcr.bazel.build/modules/rules_cc/0.0.10/MODULE.bazel": "ec1705118f7eaedd6e118508d3d26deba2a4e76476ada7e0e3965211be012002", + "https://bcr.bazel.build/modules/rules_cc/0.0.13/MODULE.bazel": "0e8529ed7b323dad0775ff924d2ae5af7640b23553dfcd4d34344c7e7a867191", + "https://bcr.bazel.build/modules/rules_cc/0.0.14/MODULE.bazel": "5e343a3aac88b8d7af3b1b6d2093b55c347b8eefc2e7d1442f7a02dc8fea48ac", + "https://bcr.bazel.build/modules/rules_cc/0.0.15/MODULE.bazel": "6704c35f7b4a72502ee81f61bf88706b54f06b3cbe5558ac17e2e14666cd5dcc", + "https://bcr.bazel.build/modules/rules_cc/0.0.16/MODULE.bazel": "7661303b8fc1b4d7f532e54e9d6565771fea666fbdf839e0a86affcd02defe87", + "https://bcr.bazel.build/modules/rules_cc/0.0.16/source.json": "227e83737046aa4f50015da48e98e0d8ab42fd0ec74d8d653b6cc9f9a357f200", + "https://bcr.bazel.build/modules/rules_cc/0.0.2/MODULE.bazel": "6915987c90970493ab97393024c156ea8fb9f3bea953b2f3ec05c34f19b5695c", + "https://bcr.bazel.build/modules/rules_cc/0.0.6/MODULE.bazel": "abf360251023dfe3efcef65ab9d56beefa8394d4176dd29529750e1c57eaa33f", + "https://bcr.bazel.build/modules/rules_cc/0.0.8/MODULE.bazel": "964c85c82cfeb6f3855e6a07054fdb159aced38e99a5eecf7bce9d53990afa3e", + "https://bcr.bazel.build/modules/rules_cc/0.0.9/MODULE.bazel": "836e76439f354b89afe6a911a7adf59a6b2518fafb174483ad78a2a2fde7b1c5", + "https://bcr.bazel.build/modules/rules_foreign_cc/0.9.0/MODULE.bazel": "c9e8c682bf75b0e7c704166d79b599f93b72cfca5ad7477df596947891feeef6", + "https://bcr.bazel.build/modules/rules_fuzzing/0.5.2/MODULE.bazel": "40c97d1144356f52905566c55811f13b299453a14ac7769dfba2ac38192337a8", + "https://bcr.bazel.build/modules/rules_fuzzing/0.5.2/source.json": "c8b1e2c717646f1702290959a3302a178fb639d987ab61d548105019f11e527e", + "https://bcr.bazel.build/modules/rules_java/4.0.0/MODULE.bazel": "5a78a7ae82cd1a33cef56dc578c7d2a46ed0dca12643ee45edbb8417899e6f74", + "https://bcr.bazel.build/modules/rules_java/5.3.5/MODULE.bazel": "a4ec4f2db570171e3e5eb753276ee4b389bae16b96207e9d3230895c99644b86", + "https://bcr.bazel.build/modules/rules_java/6.0.0/MODULE.bazel": "8a43b7df601a7ec1af61d79345c17b31ea1fedc6711fd4abfd013ea612978e39", + "https://bcr.bazel.build/modules/rules_java/6.4.0/MODULE.bazel": "e986a9fe25aeaa84ac17ca093ef13a4637f6107375f64667a15999f77db6c8f6", + "https://bcr.bazel.build/modules/rules_java/6.5.2/MODULE.bazel": "1d440d262d0e08453fa0c4d8f699ba81609ed0e9a9a0f02cd10b3e7942e61e31", + "https://bcr.bazel.build/modules/rules_java/7.10.0/MODULE.bazel": "530c3beb3067e870561739f1144329a21c851ff771cd752a49e06e3dc9c2e71a", + "https://bcr.bazel.build/modules/rules_java/7.12.2/MODULE.bazel": "579c505165ee757a4280ef83cda0150eea193eed3bef50b1004ba88b99da6de6", + "https://bcr.bazel.build/modules/rules_java/7.2.0/MODULE.bazel": "06c0334c9be61e6cef2c8c84a7800cef502063269a5af25ceb100b192453d4ab", + "https://bcr.bazel.build/modules/rules_java/7.3.2/MODULE.bazel": "50dece891cfdf1741ea230d001aa9c14398062f2b7c066470accace78e412bc2", + "https://bcr.bazel.build/modules/rules_java/7.6.1/MODULE.bazel": "2f14b7e8a1aa2f67ae92bc69d1ec0fa8d9f827c4e17ff5e5f02e91caa3b2d0fe", + "https://bcr.bazel.build/modules/rules_java/8.6.1/MODULE.bazel": "f4808e2ab5b0197f094cabce9f4b006a27766beb6a9975931da07099560ca9c2", + "https://bcr.bazel.build/modules/rules_java/8.6.1/source.json": "f18d9ad3c4c54945bf422ad584fa6c5ca5b3116ff55a5b1bc77e5c1210be5960", + "https://bcr.bazel.build/modules/rules_jvm_external/4.4.2/MODULE.bazel": "a56b85e418c83eb1839819f0b515c431010160383306d13ec21959ac412d2fe7", + "https://bcr.bazel.build/modules/rules_jvm_external/5.1/MODULE.bazel": "33f6f999e03183f7d088c9be518a63467dfd0be94a11d0055fe2d210f89aa909", + "https://bcr.bazel.build/modules/rules_jvm_external/5.2/MODULE.bazel": "d9351ba35217ad0de03816ef3ed63f89d411349353077348a45348b096615036", + "https://bcr.bazel.build/modules/rules_jvm_external/5.3/MODULE.bazel": "bf93870767689637164657731849fb887ad086739bd5d360d90007a581d5527d", + "https://bcr.bazel.build/modules/rules_jvm_external/6.1/MODULE.bazel": "75b5fec090dbd46cf9b7d8ea08cf84a0472d92ba3585b476f44c326eda8059c4", + "https://bcr.bazel.build/modules/rules_jvm_external/6.3/MODULE.bazel": "c998e060b85f71e00de5ec552019347c8bca255062c990ac02d051bb80a38df0", + "https://bcr.bazel.build/modules/rules_jvm_external/6.3/source.json": "6f5f5a5a4419ae4e37c35a5bb0a6ae657ed40b7abc5a5189111b47fcebe43197", + "https://bcr.bazel.build/modules/rules_kotlin/1.9.0/MODULE.bazel": "ef85697305025e5a61f395d4eaede272a5393cee479ace6686dba707de804d59", + "https://bcr.bazel.build/modules/rules_kotlin/1.9.6/MODULE.bazel": "d269a01a18ee74d0335450b10f62c9ed81f2321d7958a2934e44272fe82dcef3", + "https://bcr.bazel.build/modules/rules_kotlin/1.9.6/source.json": "2faa4794364282db7c06600b7e5e34867a564ae91bda7cae7c29c64e9466b7d5", + "https://bcr.bazel.build/modules/rules_license/0.0.3/MODULE.bazel": "627e9ab0247f7d1e05736b59dbb1b6871373de5ad31c3011880b4133cafd4bd0", + "https://bcr.bazel.build/modules/rules_license/0.0.7/MODULE.bazel": "088fbeb0b6a419005b89cf93fe62d9517c0a2b8bb56af3244af65ecfe37e7d5d", + "https://bcr.bazel.build/modules/rules_license/1.0.0/MODULE.bazel": "a7fda60eefdf3d8c827262ba499957e4df06f659330bbe6cdbdb975b768bb65c", + "https://bcr.bazel.build/modules/rules_license/1.0.0/source.json": "a52c89e54cc311196e478f8382df91c15f7a2bfdf4c6cd0e2675cc2ff0b56efb", + "https://bcr.bazel.build/modules/rules_pkg/0.7.0/MODULE.bazel": "df99f03fc7934a4737122518bb87e667e62d780b610910f0447665a7e2be62dc", + "https://bcr.bazel.build/modules/rules_pkg/1.0.1/MODULE.bazel": "5b1df97dbc29623bccdf2b0dcd0f5cb08e2f2c9050aab1092fd39a41e82686ff", + "https://bcr.bazel.build/modules/rules_pkg/1.0.1/source.json": "bd82e5d7b9ce2d31e380dd9f50c111d678c3bdaca190cb76b0e1c71b05e1ba8a", + "https://bcr.bazel.build/modules/rules_proto/4.0.0/MODULE.bazel": "a7a7b6ce9bee418c1a760b3d84f83a299ad6952f9903c67f19e4edd964894e06", + "https://bcr.bazel.build/modules/rules_proto/5.3.0-21.7/MODULE.bazel": "e8dff86b0971688790ae75528fe1813f71809b5afd57facb44dad9e8eca631b7", + "https://bcr.bazel.build/modules/rules_proto/6.0.2/MODULE.bazel": "ce916b775a62b90b61888052a416ccdda405212b6aaeb39522f7dc53431a5e73", + "https://bcr.bazel.build/modules/rules_proto/7.0.2/MODULE.bazel": "bf81793bd6d2ad89a37a40693e56c61b0ee30f7a7fdbaf3eabbf5f39de47dea2", + "https://bcr.bazel.build/modules/rules_proto/7.0.2/source.json": "1e5e7260ae32ef4f2b52fd1d0de8d03b606a44c91b694d2f1afb1d3b28a48ce1", + "https://bcr.bazel.build/modules/rules_python/0.10.2/MODULE.bazel": "cc82bc96f2997baa545ab3ce73f196d040ffb8756fd2d66125a530031cd90e5f", + "https://bcr.bazel.build/modules/rules_python/0.23.1/MODULE.bazel": "49ffccf0511cb8414de28321f5fcf2a31312b47c40cc21577144b7447f2bf300", + "https://bcr.bazel.build/modules/rules_python/0.25.0/MODULE.bazel": "72f1506841c920a1afec76975b35312410eea3aa7b63267436bfb1dd91d2d382", + "https://bcr.bazel.build/modules/rules_python/0.28.0/MODULE.bazel": "cba2573d870babc976664a912539b320cbaa7114cd3e8f053c720171cde331ed", + "https://bcr.bazel.build/modules/rules_python/0.31.0/MODULE.bazel": "93a43dc47ee570e6ec9f5779b2e64c1476a6ce921c48cc9a1678a91dd5f8fd58", + "https://bcr.bazel.build/modules/rules_python/0.4.0/MODULE.bazel": "9208ee05fd48bf09ac60ed269791cf17fb343db56c8226a720fbb1cdf467166c", + "https://bcr.bazel.build/modules/rules_python/0.40.0/MODULE.bazel": "9d1a3cd88ed7d8e39583d9ffe56ae8a244f67783ae89b60caafc9f5cf318ada7", + "https://bcr.bazel.build/modules/rules_python/0.40.0/source.json": "939d4bd2e3110f27bfb360292986bb79fd8dcefb874358ccd6cdaa7bda029320", + "https://bcr.bazel.build/modules/rules_shell/0.2.0/MODULE.bazel": "fda8a652ab3c7d8fee214de05e7a9916d8b28082234e8d2c0094505c5268ed3c", + "https://bcr.bazel.build/modules/rules_shell/0.2.0/source.json": "7f27af3c28037d9701487c4744b5448d26537cc66cdef0d8df7ae85411f8de95", + "https://bcr.bazel.build/modules/stardoc/0.5.1/MODULE.bazel": "1a05d92974d0c122f5ccf09291442580317cdd859f07a8655f1db9a60374f9f8", + "https://bcr.bazel.build/modules/stardoc/0.5.3/MODULE.bazel": "c7f6948dae6999bf0db32c1858ae345f112cacf98f174c7a8bb707e41b974f1c", + "https://bcr.bazel.build/modules/stardoc/0.5.6/MODULE.bazel": "c43dabc564990eeab55e25ed61c07a1aadafe9ece96a4efabb3f8bf9063b71ef", + "https://bcr.bazel.build/modules/stardoc/0.7.0/MODULE.bazel": "05e3d6d30c099b6770e97da986c53bd31844d7f13d41412480ea265ac9e8079c", + "https://bcr.bazel.build/modules/stardoc/0.7.1/MODULE.bazel": "3548faea4ee5dda5580f9af150e79d0f6aea934fc60c1cc50f4efdd9420759e7", + "https://bcr.bazel.build/modules/stardoc/0.7.1/source.json": "b6500ffcd7b48cd72c29bb67bcac781e12701cc0d6d55d266a652583cfcdab01", + "https://bcr.bazel.build/modules/upb/0.0.0-20220923-a547704/MODULE.bazel": "7298990c00040a0e2f121f6c32544bab27d4452f80d9ce51349b1a28f3005c43", + "https://bcr.bazel.build/modules/zlib/1.2.11/MODULE.bazel": "07b389abc85fdbca459b69e2ec656ae5622873af3f845e1c9d80fe179f3effa0", + "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.3/MODULE.bazel": "af322bc08976524477c79d1e45e241b6efbeb918c497e8840b8ab116802dda79", + "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.3/source.json": "2be409ac3c7601245958cd4fcdff4288be79ed23bd690b4b951f500d54ee6e7d", + "https://bcr.bazel.build/modules/zlib/1.3.1/MODULE.bazel": "751c9940dcfe869f5f7274e1295422a34623555916eb98c174c1e945594bf198" + }, + "selectedYankedVersions": {}, + "moduleExtensions": { + "@@platforms//host:extension.bzl%host_platform": { + "general": { + "bzlTransitiveDigest": "xelQcPZH8+tmuOHVjL9vDxMnnQNMlwj0SlvgoqBkm4U=", + "usagesDigest": "SeQiIN/f8/Qt9vYQk7qcXp4I4wJeEC0RnQDiaaJ4tb8=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "host_platform": { + "repoRuleId": "@@platforms//host:extension.bzl%host_platform_repo", + "attributes": {} + } + }, + "recordedRepoMappingEntries": [] + } + }, + "@@rules_java+//java:rules_java_deps.bzl%compatibility_proxy": { + "general": { + "bzlTransitiveDigest": "84xJEZ1jnXXwo8BXMprvBm++rRt4jsTu9liBxz0ivps=", + "usagesDigest": "jTQDdLDxsS43zuRmg1faAjIEPWdLAbDAowI1pInQSoo=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "compatibility_proxy": { + "repoRuleId": "@@rules_java+//java:rules_java_deps.bzl%_compatibility_proxy_repo_rule", + "attributes": {} + } + }, + "recordedRepoMappingEntries": [ + [ + "rules_java+", + "bazel_tools", + "bazel_tools" + ] + ] + } + }, + "@@rules_kotlin+//src/main/starlark/core/repositories:bzlmod_setup.bzl%rules_kotlin_extensions": { + "general": { + "bzlTransitiveDigest": "sFhcgPbDQehmbD1EOXzX4H1q/CD5df8zwG4kp4jbvr8=", + "usagesDigest": "QI2z8ZUR+mqtbwsf2fLqYdJAkPOHdOV+tF2yVAUgRzw=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "com_github_jetbrains_kotlin_git": { + "repoRuleId": "@@rules_kotlin+//src/main/starlark/core/repositories:compiler.bzl%kotlin_compiler_git_repository", + "attributes": { + "urls": [ + "https://github.com/JetBrains/kotlin/releases/download/v1.9.23/kotlin-compiler-1.9.23.zip" + ], + "sha256": "93137d3aab9afa9b27cb06a824c2324195c6b6f6179d8a8653f440f5bd58be88" + } + }, + "com_github_jetbrains_kotlin": { + "repoRuleId": "@@rules_kotlin+//src/main/starlark/core/repositories:compiler.bzl%kotlin_capabilities_repository", + "attributes": { + "git_repository_name": "com_github_jetbrains_kotlin_git", + "compiler_version": "1.9.23" + } + }, + "com_github_google_ksp": { + "repoRuleId": "@@rules_kotlin+//src/main/starlark/core/repositories:ksp.bzl%ksp_compiler_plugin_repository", + "attributes": { + "urls": [ + "https://github.com/google/ksp/releases/download/1.9.23-1.0.20/artifacts.zip" + ], + "sha256": "ee0618755913ef7fd6511288a232e8fad24838b9af6ea73972a76e81053c8c2d", + "strip_version": "1.9.23-1.0.20" + } + }, + "com_github_pinterest_ktlint": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_file", + "attributes": { + "sha256": "01b2e0ef893383a50dbeb13970fe7fa3be36ca3e83259e01649945b09d736985", + "urls": [ + "https://github.com/pinterest/ktlint/releases/download/1.3.0/ktlint" + ], + "executable": true + } + }, + "rules_android": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "sha256": "cd06d15dd8bb59926e4d65f9003bfc20f9da4b2519985c27e190cddc8b7a7806", + "strip_prefix": "rules_android-0.1.1", + "urls": [ + "https://github.com/bazelbuild/rules_android/archive/v0.1.1.zip" + ] + } + } + }, + "recordedRepoMappingEntries": [ + [ + "rules_kotlin+", + "bazel_tools", + "bazel_tools" + ] + ] + } + } + } +} diff --git a/inc/handlers.h b/inc/handlers.h deleted file mode 100644 index acf994e..0000000 --- a/inc/handlers.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef NBD_NBTPD_HANDLERS_H -#define NBD_NBTPD_HANDLERS_H - -#include -#include "packet.h" - -#define NBD_NBTPD_ARGS_PATH_MAX 768 -#define NBD_NBTPD_ARGS_MODE_MAX 32 - -typedef enum opmode { - NOT_FOUND, - NETASCII, - OCTET, - MAIL -// any additional modes -} nbd_opmode; - -typedef struct { - char path[NBD_NBTPD_ARGS_PATH_MAX]; - char mode[NBD_NBTPD_ARGS_MODE_MAX]; - nbd_tftp_ecode err; - struct sockaddr_in client; -} nbd_nbtpd_args; - -nbd_opmode get_mode(char *mode); - - -/*! - * WARNING: use this only if you know what you are doing - * The actual function signature is `void read_req_resp(nbd_nbtpd_args *args)` - * Invoke this function as a response to getting a new read request. - * It opens a new UDP socket and reads file to transmit. - * ```c - * nbd_nbtpd_args *args = malloc(sizeof(nbd_nbtpd_args)); - * pthread_create(thread, attrs, read_req_resp, (void *)args); - * ``` - */ -void *read_req_resp(void *args); -/*! - * WARNING: use this only if you know what you are doing - * The actual function signature is `void write_req_resp(nbd_nbtpd_args *args)` - * Invoke this function as a response to getting a new write request. - * It opens a new UDP socket, receives file to write to disk. - * ```c - * nbd_nbtpd_args *args = malloc(sizeof(nbd_nbtpd_args)); - * pthread_create(thread, attrs, write_req_resp, (void *)args); - * ``` - */ -void *write_req_resp(void *args); -/// WARNING: use this only if you know what you are doing -void *nbd_nbtpd_resp_error(void *args); - -#endif diff --git a/inc/netascii.h b/inc/netascii.h deleted file mode 100644 index ae80bae..0000000 --- a/inc/netascii.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef NBD_NETASCII_H -#define NBD_NETASCII_H -#include -#include - -uint8_t is_netascii_char(char c); -uint8_t is_netascii_str(char *str); -uint8_t is_netascii_buf(char *buf, size_t len); - -#endif diff --git a/inc/packet.h b/inc/packet.h deleted file mode 100644 index 86b43a3..0000000 --- a/inc/packet.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef NBD_TFTP_PACKET_H -#define NBD_TFTP_PACKET_H - -#include -#include - -typedef enum { - RRQ = 1, - WRQ = 2, - DAT = 3, - ACK = 4, - ERR = 5, -} nbd_tftp_opcode; - -typedef enum { - ERROR = 0, - ENOTFOUND = 1, - EACCESS = 2, - ENOSPACE = 3, - EOPERATION = 4, - ETRANS = 5, - EEXISTS = 6, - EUSER = 7, -} nbd_tftp_ecode; - -typedef struct { - uint16_t opcode; - char *filename; - char *mode; -} nbd_tftp_packet_rq; - -typedef struct { - uint16_t opcode; - uint16_t block_num; - char *data; - size_t datalen; -} nbd_tftp_packet_data; - -typedef struct { - uint16_t opcode; - uint16_t block_num; -} nbd_tftp_packet_ack; - -typedef struct { - uint16_t opcode; - uint16_t err; - char *emsg; -} nbd_tftp_packet_error; - -char *nbd_tftp_error_to_message(nbd_tftp_ecode error); -char *nbd_tftp_ser_data(nbd_tftp_packet_data d); -char *nbd_tftp_ser_data_from_parts(uint16_t blocknum, char *data, size_t datalen); -nbd_tftp_packet_data nbd_tftp_de_data(char *data, size_t len); -char *nbd_tftp_ser_error(nbd_tftp_packet_error e); -char *nbd_tftp_ser_error_from_code(nbd_tftp_ecode error); -char *nbd_tftp_ser_ack(nbd_tftp_packet_ack ack); -char *nbd_tftp_ser_ack_from_block_num(uint16_t block_num); -nbd_tftp_packet_ack nbd_tftp_de_ack(char *buf, ssize_t buflen); - -#endif - diff --git a/makefile b/makefile index a4cec5a..6d8b57c 100644 --- a/makefile +++ b/makefile @@ -15,7 +15,7 @@ else CFLAGS += -std=c11 endif -INCLUDES=-Iinc/ +INCLUDES=-Inbtpd/ OBJECTS=obj/main.o obj/packet.o obj/netascii.o obj/handlers.o @@ -37,7 +37,7 @@ bin/%: $(OBJECTS) @if [ ! -d "bin" ]; then mkdir -p bin; fi $(CC) -g $(CFLAGS) $(LDFLAGS) -o bin/nbtpd $^ -obj/%.o: src/%.c +obj/%.o: nbtpd/%.c @if [ ! -d "obj" ]; then mkdir -p obj; fi $(CC) -g -c $(INCLUDES) $(CFLAGS) -o $@ $^ diff --git a/nbtpd/BUILD b/nbtpd/BUILD new file mode 100644 index 0000000..444c881 --- /dev/null +++ b/nbtpd/BUILD @@ -0,0 +1,33 @@ +cc_library( + name = "nbtpd-netascii", + srcs = ["netascii.c"], + hdrs = ["netascii.h"], +) + +cc_library( + name = "nbtpd-packet", + srcs = ["packet.c"], + hdrs = ["packet.h"], +) + +cc_library( + name = "nbtpd-handlers", + srcs = ["handlers.c"], + hdrs = [ + "handlers.h", + ], + deps = [ + ":nbtpd-netascii", + ":nbtpd-packet", + ], +) + +cc_binary( + name = "nbtpd", + srcs = ["main.c"], + deps = [ + ":nbtpd-netascii", + ":nbtpd-packet", + ":nbtpd-handlers", + ], +) diff --git a/nbtpd/handlers.c b/nbtpd/handlers.c new file mode 100644 index 0000000..d42382e --- /dev/null +++ b/nbtpd/handlers.c @@ -0,0 +1,535 @@ +#ifdef __linux__ +#define _POSIX_C_SOURCE 200809L +#define _DEFAULT_SOURCE +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __FreeBSD__ +#include +#endif + +#include "handlers.h" +#include "packet.h" +#include "netascii.h" + +inline nbd_opmode get_mode(char *mode) { + nbd_opmode opmode; + if (strncmp(mode, (char *)&"netascii", NBD_NBTPD_ARGS_MODE_MAX) == 0) { + opmode = NETASCII; + } else if (strncmp(mode, (char *)&"octet", NBD_NBTPD_ARGS_MODE_MAX) == 0) { + opmode = OCTET; + } else if (strncmp(mode, (char *)&"mail", NBD_NBTPD_ARGS_MODE_MAX) == 0) { + opmode = MAIL; + } else { + opmode = NOT_FOUND; + } + return opmode; +} + +int makesock(nbd_nbtpd_args *argptr) { + int s = socket(AF_INET, SOCK_DGRAM, 0); + if (s <= 0) { + syslog(LOG_ERR, "unable to define socket: %s", strerror(errno)); + return -1; + } + struct timeval timeout = { 30, 0 }; + if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0) { + syslog(LOG_ERR, "unable to set socket timeout: %s", strerror(errno)); + close(s); + return -1; + } + if (connect(s, (struct sockaddr *)&(argptr->client), sizeof(struct sockaddr)) < 0) { + syslog( + LOG_ERR, + "unable to connect to client %s: %s", + inet_ntoa(argptr->client.sin_addr), + strerror(errno) + ); + close(s); + return -1; + } + return s; +} + +char *checkpath(nbd_nbtpd_args *argptr, uint8_t read) { + char *fname = NULL, *wd = NULL, *path = NULL, *ptr = NULL; + char **parts = NULL; + if (!is_netascii_str((char *)&argptr->path)) { + argptr->err = 1; + goto cleanup; + } + if (read) { + fname = realpath((char *)&argptr->path, NULL); + } else { + //TODO: figure out how to canonicalize non-existent path + char *tok = NULL; + parts = malloc(sizeof(parts) * NBD_NBTPD_ARGS_PATH_MAX); + if (parts == NULL) { + goto cleanup; + } + memset(parts, '\0', sizeof(parts) * NBD_NBTPD_ARGS_PATH_MAX); + ptr = (char *)&argptr->path; + for (int i = 0; ((tok = strsep(&ptr, "/")) != NULL); i++ ) { + parts[i] = tok; + } + path = malloc(NBD_NBTPD_ARGS_PATH_MAX); + if (path == NULL) { + goto cleanup; + } + memset(path, '\0', NBD_NBTPD_ARGS_PATH_MAX); + int z = 0; + for (int i = 0; parts[i] != NULL; i++) { + if (strncmp(parts[i], "..", 2) == 0) { + continue; + } + if (strncmp(parts[i], ".", NBD_NBTPD_ARGS_PATH_MAX) == 0) { + continue; + } + for (int x = 0; parts[i][x] != '\0'; x++) { + if (z < NBD_NBTPD_ARGS_PATH_MAX) { + path[z++] = parts[i][x]; + } else { + goto cleanup; + } + } + if (z < NBD_NBTPD_ARGS_PATH_MAX) { + path[z++] = '/'; + } else { + goto cleanup; + } + } + // erase trailing slash + path[z - 1] = '\0'; + fname = strdup(path); + } + if (fname == NULL) { + syslog(LOG_ERR, "unable to get real path: %s", strerror(errno)); + argptr->err = 1; + goto cleanup; + } +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * POSIX does not define what happens when getcwd() is given NULL. * + * This means that illumos libc and GNU libc both return a newly * + * malloc()'d string, while FreeBSD libc does not. Also, FreeBSD uses * + * constant MAXPATHLEN defined in rather than PATH_MAX. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +#ifdef __FreeBSD__ + wd = malloc(MAXPATHLEN); + if (wd == NULL) { + syslog(LOG_ERR, "unable to allocate PATH_MAX memory: %s", strerror(errno)); + argptr->err = 0; + goto cleanup; + } + if (getcwd(wd, MAXPATHLEN) == NULL) { + argptr->err = 0; + goto cleanup; + } +#else + if ((wd = getcwd(NULL, PATH_MAX)) == NULL) { + argptr->err = 0; + goto cleanup; + } +#endif + syslog(LOG_DEBUG, "cwd: %s :: realpath: %s", wd, fname); + if (read) { + if (strncmp(wd, fname, strlen(wd))) { + syslog( + LOG_ERR, + "%s:%d requested invalid file %s", + inet_ntoa(argptr->client.sin_addr), + ntohs(argptr->client.sin_port), + fname + ); + argptr->err = 2; + goto cleanup; + } + } else { + strcat(wd, "/"); + strcat(wd, fname); + char *intermediate = wd; + wd = fname; + fname = intermediate; + } +cleanup: + free(wd); + free(path); + free(parts); + return fname; +} + +ssize_t senderror(int s, nbd_nbtpd_args *argptr) { + size_t buflen = 4 + strlen(nbd_tftp_error_to_message((nbd_tftp_ecode)argptr->err)); + char *buf = nbd_tftp_ser_error_from_code((nbd_tftp_ecode)argptr->err); + ssize_t sb = send(s, buf, buflen, 0); + free(buf); + return sb; +} + +void *read_req_resp(void *args) { + char *fname = NULL, *buf = NULL, *rxb = NULL; + FILE *fp = NULL; + nbd_nbtpd_args *argptr = (nbd_nbtpd_args *)args; + syslog( + LOG_DEBUG, + "%s:%d is requesting file %s", + inet_ntoa(argptr->client.sin_addr), + ntohs(argptr->client.sin_port), + argptr->path + ); + fname = checkpath(argptr, 1); + if (fname == NULL) { + goto pre_socket; + } + if (!is_netascii_str((char *)&(argptr->mode))) { + syslog( + LOG_ERR, + "%s:%d mode is invalid %s", + inet_ntoa(argptr->client.sin_addr), + ntohs(argptr->client.sin_port), + argptr->mode + ); + argptr->err = 4; + goto pre_socket; + } + nbd_opmode opmode = get_mode((char *)&(argptr->mode)); + if ((opmode != NETASCII) && (opmode != OCTET)) { + argptr->err = 4; + goto pre_socket; + } + fp = fopen(fname, "r"); + if (fp == NULL) { + syslog( + LOG_ERR, + "failed to open file for reading: %s", + strerror(errno) + ); + argptr->err = 2; + goto pre_socket; + } + buf = malloc(512); + rxb = malloc(256); + if ((buf == NULL) || (rxb == NULL)) { + syslog( + LOG_CRIT, + "failed to allocate memory: %s", + strerror(errno) + ); + argptr->err = 0; + goto pre_socket; + } + int s = makesock(argptr); + if (s <= 0) { + goto cleanup; + } + uint8_t rxon = 0, lon = 1; + uint16_t bnum = 0; + while (lon) { + memset(buf, '\0', 512); + uint8_t verif = 0; + uint8_t vcount = 0; + size_t num_read = fread(buf, 1, 512, fp); + if (((num_read < 512) && (!feof(fp))) || (vcount > 5)) { + argptr->err = 0; + senderror(s, argptr); + goto cleanup; + } + if ((opmode == NETASCII) && (!is_netascii_buf(buf, num_read))) { + syslog( + LOG_ERR, + "%s:%d: requested file is not netascii compliant.", + inet_ntoa(argptr->client.sin_addr), + ntohs(argptr->client.sin_port) + ); + argptr->err = 5; + senderror(s, argptr); + goto cleanup; + } + char *packet = nbd_tftp_ser_data_from_parts(++bnum, buf, num_read); + while (!verif) { + syslog(LOG_DEBUG, "sending block number %d to %s:%d", + bnum, + inet_ntoa(argptr->client.sin_addr), + htons(argptr->client.sin_port) + ); + if (send(s, packet, num_read + 4, 0) < 0) { + syslog( + LOG_ERR, + "unable to send data to %s: %s", + inet_ntoa(argptr->client.sin_addr), + strerror(errno) + ); + continue; + } + rxon = 1; + uint8_t rxcount = 0; + while (rxon) { + syslog(LOG_DEBUG, "waiting for ack %d from %s:%d", + bnum, + inet_ntoa(argptr->client.sin_addr), + htons(argptr->client.sin_port) + ); + memset(rxb, '\0', 256); + ssize_t rcv = recv(s, rxb, 256, 0); + syslog(LOG_DEBUG, "recv'd %ld bytes from %s:%d", + rcv, + inet_ntoa(argptr->client.sin_addr), + htons(argptr->client.sin_port) + ); + if (rcv == 4) { + nbd_tftp_packet_ack ack = nbd_tftp_de_ack(rxb, rcv); + if (ack.opcode == 5) { + goto socket_clean; + } + syslog(LOG_DEBUG, "%s:%d ack'd with block number: %d (expect %d)", + inet_ntoa(argptr->client.sin_addr), + htons(argptr->client.sin_port), + ack.block_num, + bnum + ); + if (ack.block_num == bnum) { + rxon = 0; + verif = 1; + break; + } + if (ack.block_num == (bnum - 1)) { + rxon = 0; + vcount++; + break; + } + } + if (++rxcount > 30) { + argptr->err = 0; + senderror(s, argptr); + goto cleanup; + } + if (rcv > 4) { + if ((((uint16_t)buf[0] << 8) + buf[1]) == 5) { + goto socket_clean; + } + } + } + } + free(packet); + if (num_read < 512) { + lon = 0; + } + } +socket_clean: + close(s); +cleanup: + fclose(fp); + free(buf); + free(rxb); + free(fname); + free(args); + return (void *)NULL; +pre_socket: + if (fp != NULL) { + fclose(fp); + } + free(buf); + free(rxb); + free(fname); + return nbd_nbtpd_resp_error(args); +} + +void *write_req_resp(void *args) { + char *fname = NULL, *rxb = NULL; + FILE *fp = NULL; + nbd_nbtpd_args *argptr = (nbd_nbtpd_args *)args; + syslog( + LOG_DEBUG, + "%s:%d is trying to write file %s", + inet_ntoa(argptr->client.sin_addr), + ntohs(argptr->client.sin_port), + argptr->path + ); + fname = checkpath(argptr, 0); + if (fname == NULL) { + syslog(LOG_ERR, "fname is NULL"); + goto pre_socket; + } + if (!is_netascii_str((char *)&(argptr->mode))) { + syslog( + LOG_ERR, + "%s:%d mode is invalid %s", + inet_ntoa(argptr->client.sin_addr), + ntohs(argptr->client.sin_port), + argptr->mode + ); + argptr->err = 4; + goto pre_socket; + } + nbd_opmode opmode = get_mode((char *)&(argptr->mode)); + if ((opmode != NETASCII) && (opmode != OCTET)) { + syslog(LOG_ERR, "%s:%d mode is not supported.", inet_ntoa(argptr->client.sin_addr), ntohs(argptr->client.sin_port)); + argptr->err = 4; + goto pre_socket; + } + fp = fopen(fname, "w"); + if (fp == NULL) { + syslog( + LOG_ERR, + "failed to open file for writing: %s", + strerror(errno) + ); + argptr->err = 2; + goto pre_socket; + } + rxb = malloc(768); // 768 is 1.5x expected block size + if (rxb == NULL) { + syslog( + LOG_CRIT, + "failed to allocate memory: %s", + strerror(errno) + ); + argptr->err = 0; + goto pre_socket; + } + int s = makesock(argptr); + if (s <= 0) { + goto cleanup; + } + uint8_t rxon = 0, lon = 1; + uint16_t bnum = 0; + ssize_t rcv = 516; + while (lon) { + uint8_t verif = 0; + uint8_t vcount = 0; + char *packet = nbd_tftp_ser_ack_from_block_num(bnum++); + while (!verif) { + syslog(LOG_DEBUG, "sending ack number %d to %s:%d", + bnum, + inet_ntoa(argptr->client.sin_addr), + htons(argptr->client.sin_port) + ); + if (send(s, packet, 4, 0) < 0) { + syslog( + LOG_ERR, + "unable to send ack to %s:%d: %s", + inet_ntoa(argptr->client.sin_addr), + htons(argptr->client.sin_port), + strerror(errno) + ); + continue; + } + if ((rcv < 516) || (vcount > 5)) { + lon = 0; + break; + } + rxon = 1; + uint8_t rxcount = 0; + while (rxon) { + syslog(LOG_DEBUG, "waiting for data from %s:%d", + inet_ntoa(argptr->client.sin_addr), + htons(argptr->client.sin_port) + ); + memset(rxb, '\0', 768); + rcv = recv(s, rxb, 768, 0); + syslog(LOG_DEBUG, "recv'd %ld bytes from %s:%d", + rcv, + inet_ntoa(argptr->client.sin_addr), + htons(argptr->client.sin_port) + ); + if (rcv >= 4) { + nbd_tftp_packet_data data = nbd_tftp_de_data(rxb, rcv); + if (data.opcode == 5) { + free(data.data); + goto cleanup; + } + syslog( + LOG_DEBUG, + "%s:%d sent block number: %d (expect %d)", + inet_ntoa(argptr->client.sin_addr), + htons(argptr->client.sin_port), + data.block_num, + bnum + ); + if (data.block_num == bnum) { + rxon = 0; + verif = 1; + if (data.datalen > 0) { + if ((opmode == NETASCII) && (!is_netascii_buf(data.data, data.datalen))) { + syslog( + LOG_ERR, + "%s:%d: requested file is not netascii compliant.", + inet_ntoa(argptr->client.sin_addr), + ntohs(argptr->client.sin_port) + ); + argptr->err = 5; + senderror(s, argptr); + free(data.data); + goto cleanup; + } + if (fwrite(data.data, 1, data.datalen, fp) < data.datalen) { + syslog(LOG_ERR, "filewrite failed for %s: %s", fname, strerror(errno)); + argptr->err = 0; + senderror(s, argptr); + free(data.data); + goto clean_socket; + } + } + free(data.data); + break; + } + if (data.block_num == (bnum - 1)) { + rxon = 0; + vcount++; + free(data.data); + break; + } + free(data.data); + } + if (++rxcount > 30) { + syslog(LOG_ERR, "retry count exceeded"); + argptr->err = 0; + senderror(s, argptr); + goto clean_socket; + } + } + } + free(packet); + } +clean_socket: + close(s); +cleanup: + fclose(fp); + free(rxb); + free(fname); + free(args); + return (void *)NULL; +pre_socket: + if (fp != NULL) { + fclose(fp); + } + free(rxb); + free(fname); + return nbd_nbtpd_resp_error(args); +} + +void *nbd_nbtpd_resp_error(void *args) { + nbd_nbtpd_args *argptr = (nbd_nbtpd_args *)args; + int s = makesock(argptr); + if (s <= 0) { + syslog( + LOG_ERR, + "cannot send error to %s:%d", + inet_ntoa(argptr->client.sin_addr), + ntohs(argptr->client.sin_port) + ); + goto cleanup; + } + senderror(s, argptr); +cleanup: + free(args); + return (void *)NULL; +} + diff --git a/nbtpd/handlers.h b/nbtpd/handlers.h new file mode 100644 index 0000000..c3504f5 --- /dev/null +++ b/nbtpd/handlers.h @@ -0,0 +1,54 @@ +#ifndef NBD_NBTPD_HANDLERS_H +#define NBD_NBTPD_HANDLERS_H + +#include + +#include "packet.h" + +#define NBD_NBTPD_ARGS_PATH_MAX 768 +#define NBD_NBTPD_ARGS_MODE_MAX 32 + +typedef enum opmode { + NOT_FOUND, + NETASCII, + OCTET, + MAIL +// any additional modes +} nbd_opmode; + +typedef struct { + char path[NBD_NBTPD_ARGS_PATH_MAX]; + char mode[NBD_NBTPD_ARGS_MODE_MAX]; + nbd_tftp_ecode err; + struct sockaddr_in client; +} nbd_nbtpd_args; + +nbd_opmode get_mode(char *mode); + + +/*! + * WARNING: use this only if you know what you are doing + * The actual function signature is `void read_req_resp(nbd_nbtpd_args *args)` + * Invoke this function as a response to getting a new read request. + * It opens a new UDP socket and reads file to transmit. + * ```c + * nbd_nbtpd_args *args = malloc(sizeof(nbd_nbtpd_args)); + * pthread_create(thread, attrs, read_req_resp, (void *)args); + * ``` + */ +void *read_req_resp(void *args); +/*! + * WARNING: use this only if you know what you are doing + * The actual function signature is `void write_req_resp(nbd_nbtpd_args *args)` + * Invoke this function as a response to getting a new write request. + * It opens a new UDP socket, receives file to write to disk. + * ```c + * nbd_nbtpd_args *args = malloc(sizeof(nbd_nbtpd_args)); + * pthread_create(thread, attrs, write_req_resp, (void *)args); + * ``` + */ +void *write_req_resp(void *args); +/// WARNING: use this only if you know what you are doing +void *nbd_nbtpd_resp_error(void *args); + +#endif diff --git a/nbtpd/main.c b/nbtpd/main.c new file mode 100644 index 0000000..7114cc7 --- /dev/null +++ b/nbtpd/main.c @@ -0,0 +1,313 @@ +#ifdef __linux__ +#define _POSIX_C_SOURCE 2 +#define _DEFAULT_SOURCE +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//TODO: use threads.h instead +#include + +// illumos-only headers +#ifdef __illumos__ +#include +#endif + +#include "packet.h" +#include "netascii.h" +#include "handlers.h" + +int nbtpd_stop = 0; + +void stop_handler(int i) { + syslog(LOG_ERR, "caught shutdown signal, cleaning up and awaiting threads"); + if (i != 0) { + nbtpd_stop = i; + } else { + nbtpd_stop = 1; + } + return; +} + +void usage(char *name) { + //TODO: print to stderr; cleanup to be compliant + fprintf(stderr, + "usage: %s -h [-d [-u USER] [-g GROUP]] [-a INET_ADDRESS] [-p PORT] [-l LEVEL]\n", + name + ); + fprintf(stderr, "\td: daemonize.\n"); + fprintf(stderr, + "\tu: username to run as (default: nobody). Must be specified after -d.\n" + ); + fprintf(stderr, + "\tg: group to run as (default: nobody). Must be specified after -d.\n" + ); + fprintf(stderr, "\ta: address to bind to (default: 127.0.0.1)\n"); + fprintf(stderr, "\tp: port to bind to (default: 69)\n"); + fprintf(stderr, "\tl: log level; one of:\n"); + fprintf(stderr, "\t\temerg\n\t\talert\n\t\tcrit\n\t\terr\n\t\twarn\n"); + fprintf(stderr, "\t\tnotice\n\t\tinfo (default)\n\t\tdebug\n"); +} + +int set_loglevel(char *level) { + if (strncmp("emerg", level, 6) == 0) { + setlogmask(LOG_UPTO(LOG_EMERG)); + return 0; + } + if (strncmp("alert", level, 6) == 0) { + setlogmask(LOG_UPTO(LOG_ALERT)); + return 0; + } + if (strncmp("crit", level, 5) == 0) { + setlogmask(LOG_UPTO(LOG_CRIT)); + return 0; + } + if (strncmp("err", level, 4) == 0) { + setlogmask(LOG_UPTO(LOG_ERR)); + return 0; + } + if (strncmp("warn", level, 5) == 0) { + setlogmask(LOG_UPTO(LOG_WARNING)); + return 0; + } + if (strncmp("notice", level, 7) == 0) { + setlogmask(LOG_UPTO(LOG_NOTICE)); + return 0; + } + if (strncmp("info", level, 5) == 0) { + setlogmask(LOG_UPTO(LOG_INFO)); + return 0; + } + if (strncmp("debug", level, 6) == 0) { + setlogmask(LOG_UPTO(LOG_DEBUG)); + return 0; + } + return -1; +} + +int main(int argc, char **argv) { + int retme = 0; + int daemonize = 0, loglevset = 0; + char addr[17], user[32], group[32]; + memset(addr, '\0', sizeof(addr)); + memset(user, '\0', sizeof(user)); + memset(group, '\0', sizeof(group)); + strcpy(addr, "127.0.0.1"); + strcpy(user, "nobody"); + strcpy(group, "nobody"); + int port = 69; + int ch = 0; + while ((ch = getopt(argc, argv, "da:p:u:g:l:h")) != -1) { + switch (ch) { + case 'a': + strncpy(addr, optarg, sizeof(addr) - 1); + break; + case 'p': + port = atoi(optarg); + if ((port <= 0) || (port >= 65536)) { + fprintf(stderr, "invalid port specified.\n"); + return -1; + } + break; + case 'd': + daemonize = 1; + break; + case 'g': + if (daemonize) { + strncpy(group, optarg, sizeof(group) - 1); + } else { + fprintf(stderr, "-g requires -d\n"); + return -1; + } + break; + case 'u': + if (daemonize) { + strncpy(user, optarg, sizeof(user) - 1); + } else { + fprintf(stderr, "-u requires -d\n"); + return -1; + } + break; + case 'l': + loglevset = 1; + if (set_loglevel(optarg)) { + fprintf(stderr, "invalid option for -l\n"); + usage(argv[0]); + return -1; + } + break; + case 'h': case '?': + usage(argv[0]); + return -1; + } + } + if (!loglevset) { + setlogmask(LOG_UPTO(LOG_INFO)); + } +#ifdef __illumos__ + openlog(argv[0], LOG_PID | LOG_NDELAY, LOG_FTP); +#else + openlog(argv[0], LOG_PID | LOG_PERROR | LOG_NDELAY, LOG_FTP); +#endif + syslog(LOG_INFO, "starting up..."); + signal(SIGTERM, &stop_handler); + signal(SIGINT, &stop_handler); + char *buf = NULL; + int s = socket(AF_INET, SOCK_DGRAM, 0); + if (s <= 0) { + syslog(LOG_ERR, "unable to bind socket!"); + return -1; + } + if (daemonize) { + if (daemon(1, 0)) { + syslog(LOG_ERR, "failed to daemonize: %s", strerror(errno)); + retme = -1; + goto cleanup; + } else { + syslog(LOG_INFO, "daemonized"); + } + } + struct timeval timeout = { 30, 0 }; + if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0) { + syslog(LOG_ERR, "unable to set socket timeout: %s", strerror(errno)); + retme = -1; + goto cleanup; + } + struct sockaddr_in saddr; + saddr.sin_family = AF_INET; + saddr.sin_port = htons(port); + saddr.sin_addr.s_addr = inet_addr(addr); + if (bind(s, (struct sockaddr*)&saddr, sizeof(saddr)) < 0) { + syslog(LOG_ERR, "socket bind failed: %s", strerror(errno)); + retme = -1; + goto cleanup; + } + syslog(LOG_DEBUG, "socket bind success"); + if (daemonize) { + //TODO: use getpwnam_r() and getgrnam_r() + struct group *g = getgrnam((const char *)&group); + if (setgid((*g).gr_gid) == -1) { + syslog( + LOG_ERR, + "failed to drop group privileges: %s", + strerror(errno) + ); + retme = -1; + goto cleanup; + } + struct passwd *u = getpwnam((const char *)&user); + if (setuid((*u).pw_uid) == -1) { + syslog( + LOG_ERR, + "failed to drop user privileges: %s", + strerror(errno) + ); + retme = -1; + goto cleanup; + } + } +#ifdef __illumos__ + //TODO: illumos priv.h privdrop +#endif + buf = malloc(1024); + if (buf == NULL) { + syslog(LOG_CRIT, "unable to allocate memory: %s", strerror(errno)); + retme = -1; + goto cleanup; + } + while (!nbtpd_stop) { + struct sockaddr_in caddr; + unsigned int clen = sizeof(caddr); + memset(buf, '\0', 1024); + ssize_t recvd_bytes = 0; + if ((recvd_bytes = recvfrom(s, buf, 1024, 0, + (struct sockaddr *)&caddr, &clen)) < 0) { + continue; + } + if (recvd_bytes < 4) { + syslog( + LOG_ERR, + "ignoring invalid packet from %s.", + inet_ntoa(caddr.sin_addr) + ); + continue; + } + syslog( + LOG_INFO, + "got connection from %s:%d", + inet_ntoa(caddr.sin_addr), + ntohs(caddr.sin_port) + ); + nbd_nbtpd_args *args = malloc(sizeof(nbd_nbtpd_args)); + if (args == NULL) { + syslog( + LOG_CRIT, + "unable to allocate memory: %s", + strerror(errno) + ); + continue; + } + nbd_tftp_opcode oc = ((uint16_t)buf[0] << 8) + buf[1]; + args->client = caddr; + args->err = 0; + memset(args->path, '\0', NBD_NBTPD_ARGS_PATH_MAX); + memset(args->mode, '\0', NBD_NBTPD_ARGS_MODE_MAX); + int i; + for(i = 2; buf[i] != 0 && i < recvd_bytes && (i - 2) < (NBD_NBTPD_ARGS_PATH_MAX - 1); i++) { + args->path[i - 2] = buf[i]; + } + int s = i + 1; + if (s >= recvd_bytes) { + oc = 0; + } else { + for(i = s; buf[i] != 0 && i < recvd_bytes && (i - s) < (NBD_NBTPD_ARGS_MODE_MAX - 1); i++) { + args->mode[i - s] = buf[i]; + } + } + //TODO: use std threads + pthread_t _thread; + void *(*func)(void *); + switch (oc) { + case RRQ: + func = &read_req_resp; + break; + case WRQ: + func = &write_req_resp; + break; + default: + (*args).err = 4; + func = &nbd_nbtpd_resp_error; + } + //TODO: use std threads + int e; + syslog(LOG_ERR, "spawning thread for %s", inet_ntoa(caddr.sin_addr)); + if ((e = pthread_create(&_thread, 0, func, (void *)args)) != 0) { + syslog( + LOG_CRIT, + "unable to spawn thread: %s", + strerror(e) + ); + free(args); + } + } +cleanup: + free(buf); + close(s); + pthread_exit(NULL); + return retme; +} + diff --git a/nbtpd/netascii.c b/nbtpd/netascii.c new file mode 100644 index 0000000..d061e57 --- /dev/null +++ b/nbtpd/netascii.c @@ -0,0 +1,53 @@ +#include +#include + +#include "netascii.h" + +uint8_t is_netascii_char(char c) { + static const uint64_t LUT[4] = + {0xffffffff00003f81, + 0x7fffffffffffffff, + 0x00,0x00}; + int i = c / 64; + int e = i % 64; + return (LUT[i] >> e) & 1; +} + +/// WARNING! This function is NOT safe. Use only for strings you have already +/// verified are NULL terminated! +uint8_t is_netascii_str(char *str) { + for (uint64_t i = 0; str[i] != 0; i++) { + if (!is_netascii_char(str[i])) { + return 0; + } else { + if (str[i] == '\r') { + if (str[++i] != '\n') { + return 0; + } + } + } + } + return 1; +} + +uint8_t is_netascii_buf(char *buf, size_t len) { + for (uint64_t i = 0; i < len; i++) { + if (!is_netascii_char(buf[i])) { + return 0; + } else { + if (buf[i] == '\r') { + if ((i + 1) < len) { + switch (buf[++i]) { + case 0: case '\n': + break; + default: + return 0; + } + } else { + return 0; + } + } + } + } + return 1; +} diff --git a/nbtpd/netascii.h b/nbtpd/netascii.h new file mode 100644 index 0000000..ae80bae --- /dev/null +++ b/nbtpd/netascii.h @@ -0,0 +1,10 @@ +#ifndef NBD_NETASCII_H +#define NBD_NETASCII_H +#include +#include + +uint8_t is_netascii_char(char c); +uint8_t is_netascii_str(char *str); +uint8_t is_netascii_buf(char *buf, size_t len); + +#endif diff --git a/nbtpd/packet.c b/nbtpd/packet.c new file mode 100644 index 0000000..8302550 --- /dev/null +++ b/nbtpd/packet.c @@ -0,0 +1,126 @@ +#include +#include +#include +#include + +#include "packet.h" + +char *nbd_tftp_error_to_message(nbd_tftp_ecode error) { + switch (error) { + case 0: + return "ERROR"; + case 1: + return "File not Found"; + case 2: + return "Access violation"; + case 3: + return "Disk full or allocation exceeded"; + case 4: + return "Illegal TFTP operation"; + case 5: + return "Unknown Transfer ID"; + case 6: + return "File already exists"; + case 7: + return "No such user"; + } + return "UNKNOWN ERROR"; +} + +char *nbd_tftp_ser_data(nbd_tftp_packet_data d) { + char *buf = malloc(sizeof(d.opcode) + sizeof(d.block_num) + d.datalen); + if (buf != NULL) { + uint16_t netopcode = htons(d.opcode); + uint16_t netbnum = htons(d.block_num); + memcpy(buf, &netopcode, sizeof(netopcode)); + memcpy((buf + sizeof(netopcode)), &netbnum, sizeof(netbnum)); + memcpy((buf + sizeof(netopcode) + sizeof(netbnum)), d.data, d.datalen); + } + return buf; +} + +char *nbd_tftp_ser_data_from_parts(uint16_t blocknum, char *data, size_t datalen) { + char *buf = malloc(sizeof(uint16_t) + sizeof(blocknum) + datalen); + if (buf != NULL) { + uint16_t netopcode = htons(3); + uint16_t netbnum = htons(blocknum); + memcpy(buf, &netopcode, sizeof(netopcode)); + memcpy((buf + sizeof(netopcode)), &netbnum, sizeof(netbnum)); + memcpy((buf + sizeof(netopcode) + sizeof(netbnum)), data, datalen); + } + return buf; +} + +nbd_tftp_packet_data nbd_tftp_de_data(char *data, size_t len) { + nbd_tftp_packet_data ret = { 0, 0, (char *)NULL, (size_t)0 }; + if ((len >= 4) && (data != NULL)) { + ret.opcode = ((uint16_t)data[0] << 8) + data[1]; + ret.block_num = ((uint16_t)data[2] << 8) + data[3]; + ret.datalen = len - 4; + if (ret.datalen > 0) { + if ((ret.data = malloc(ret.datalen)) != NULL) { + memcpy(ret.data, (data + 4), ret.datalen); + } + } + } + return ret; +} + +char *nbd_tftp_ser_error(nbd_tftp_packet_error e) { + char *buf = malloc(sizeof(e.opcode) + sizeof((uint16_t)e.err) + strlen(e.emsg)); + if (buf != NULL) { + uint16_t netopcode = htons(e.opcode); + uint16_t netecode = htons((uint16_t)e.err); + memcpy(buf, &netopcode, sizeof(netopcode)); + memcpy((buf + sizeof(netopcode)), &netecode, sizeof(netecode)); + memcpy((buf + sizeof(netopcode) + sizeof(netecode)), e.emsg, strlen(e.emsg)); + } + return buf; +} + +char *nbd_tftp_ser_error_from_code(nbd_tftp_ecode error) { + char *emsg = nbd_tftp_error_to_message(error); + char *buf = malloc(sizeof(uint16_t) + sizeof(uint16_t) + strlen(emsg)); + if (buf != NULL) { + uint16_t netopcode = htons(5); + uint16_t netecode = htons((uint16_t)error); + memcpy(buf, &netopcode, sizeof(netopcode)); + memcpy((buf + sizeof(netopcode)), &netecode, sizeof(netecode)); + memcpy((buf + sizeof(netopcode) + sizeof(netecode)), emsg, strlen(emsg)); + } + return buf; +} + +char *nbd_tftp_ser_ack(nbd_tftp_packet_ack ack) { + char *buf = malloc(sizeof(ack.opcode) + sizeof(ack.block_num)); + if (buf != NULL) { + uint16_t netopcode = htons(ack.opcode); + uint16_t netbnum = htons(ack.block_num); + memcpy(buf, &netopcode, sizeof(netopcode)); + memcpy((buf + sizeof(netopcode)), &netbnum, sizeof(netbnum)); + } + return buf; +} + +char *nbd_tftp_ser_ack_from_block_num(uint16_t block_num) { + char *buf = malloc(sizeof(uint16_t) + sizeof(block_num)); + if (buf != NULL) { + uint16_t netopcode = htons(4); + uint16_t netbnum = htons(block_num); + memcpy(buf, &netopcode, sizeof(netopcode)); + memcpy((buf + sizeof(netopcode)), &netbnum, sizeof(netbnum)); + } + return buf; +} + +nbd_tftp_packet_ack nbd_tftp_de_ack(char *buf, ssize_t buflen) { + nbd_tftp_packet_ack ack = { 0, 0 }; + if ((buf != NULL) && (buflen == 4)) { + uint16_t opcode = ((uint16_t)buf[0] << 8) + buf[1]; + uint16_t block_num = ((uint16_t)buf[2] << 8) + buf[3]; + ack.opcode = opcode; + ack.block_num = block_num; + } + return ack; +} + diff --git a/nbtpd/packet.h b/nbtpd/packet.h new file mode 100644 index 0000000..86b43a3 --- /dev/null +++ b/nbtpd/packet.h @@ -0,0 +1,61 @@ +#ifndef NBD_TFTP_PACKET_H +#define NBD_TFTP_PACKET_H + +#include +#include + +typedef enum { + RRQ = 1, + WRQ = 2, + DAT = 3, + ACK = 4, + ERR = 5, +} nbd_tftp_opcode; + +typedef enum { + ERROR = 0, + ENOTFOUND = 1, + EACCESS = 2, + ENOSPACE = 3, + EOPERATION = 4, + ETRANS = 5, + EEXISTS = 6, + EUSER = 7, +} nbd_tftp_ecode; + +typedef struct { + uint16_t opcode; + char *filename; + char *mode; +} nbd_tftp_packet_rq; + +typedef struct { + uint16_t opcode; + uint16_t block_num; + char *data; + size_t datalen; +} nbd_tftp_packet_data; + +typedef struct { + uint16_t opcode; + uint16_t block_num; +} nbd_tftp_packet_ack; + +typedef struct { + uint16_t opcode; + uint16_t err; + char *emsg; +} nbd_tftp_packet_error; + +char *nbd_tftp_error_to_message(nbd_tftp_ecode error); +char *nbd_tftp_ser_data(nbd_tftp_packet_data d); +char *nbd_tftp_ser_data_from_parts(uint16_t blocknum, char *data, size_t datalen); +nbd_tftp_packet_data nbd_tftp_de_data(char *data, size_t len); +char *nbd_tftp_ser_error(nbd_tftp_packet_error e); +char *nbd_tftp_ser_error_from_code(nbd_tftp_ecode error); +char *nbd_tftp_ser_ack(nbd_tftp_packet_ack ack); +char *nbd_tftp_ser_ack_from_block_num(uint16_t block_num); +nbd_tftp_packet_ack nbd_tftp_de_ack(char *buf, ssize_t buflen); + +#endif + diff --git a/src/handlers.c b/src/handlers.c deleted file mode 100644 index d42382e..0000000 --- a/src/handlers.c +++ /dev/null @@ -1,535 +0,0 @@ -#ifdef __linux__ -#define _POSIX_C_SOURCE 200809L -#define _DEFAULT_SOURCE -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef __FreeBSD__ -#include -#endif - -#include "handlers.h" -#include "packet.h" -#include "netascii.h" - -inline nbd_opmode get_mode(char *mode) { - nbd_opmode opmode; - if (strncmp(mode, (char *)&"netascii", NBD_NBTPD_ARGS_MODE_MAX) == 0) { - opmode = NETASCII; - } else if (strncmp(mode, (char *)&"octet", NBD_NBTPD_ARGS_MODE_MAX) == 0) { - opmode = OCTET; - } else if (strncmp(mode, (char *)&"mail", NBD_NBTPD_ARGS_MODE_MAX) == 0) { - opmode = MAIL; - } else { - opmode = NOT_FOUND; - } - return opmode; -} - -int makesock(nbd_nbtpd_args *argptr) { - int s = socket(AF_INET, SOCK_DGRAM, 0); - if (s <= 0) { - syslog(LOG_ERR, "unable to define socket: %s", strerror(errno)); - return -1; - } - struct timeval timeout = { 30, 0 }; - if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0) { - syslog(LOG_ERR, "unable to set socket timeout: %s", strerror(errno)); - close(s); - return -1; - } - if (connect(s, (struct sockaddr *)&(argptr->client), sizeof(struct sockaddr)) < 0) { - syslog( - LOG_ERR, - "unable to connect to client %s: %s", - inet_ntoa(argptr->client.sin_addr), - strerror(errno) - ); - close(s); - return -1; - } - return s; -} - -char *checkpath(nbd_nbtpd_args *argptr, uint8_t read) { - char *fname = NULL, *wd = NULL, *path = NULL, *ptr = NULL; - char **parts = NULL; - if (!is_netascii_str((char *)&argptr->path)) { - argptr->err = 1; - goto cleanup; - } - if (read) { - fname = realpath((char *)&argptr->path, NULL); - } else { - //TODO: figure out how to canonicalize non-existent path - char *tok = NULL; - parts = malloc(sizeof(parts) * NBD_NBTPD_ARGS_PATH_MAX); - if (parts == NULL) { - goto cleanup; - } - memset(parts, '\0', sizeof(parts) * NBD_NBTPD_ARGS_PATH_MAX); - ptr = (char *)&argptr->path; - for (int i = 0; ((tok = strsep(&ptr, "/")) != NULL); i++ ) { - parts[i] = tok; - } - path = malloc(NBD_NBTPD_ARGS_PATH_MAX); - if (path == NULL) { - goto cleanup; - } - memset(path, '\0', NBD_NBTPD_ARGS_PATH_MAX); - int z = 0; - for (int i = 0; parts[i] != NULL; i++) { - if (strncmp(parts[i], "..", 2) == 0) { - continue; - } - if (strncmp(parts[i], ".", NBD_NBTPD_ARGS_PATH_MAX) == 0) { - continue; - } - for (int x = 0; parts[i][x] != '\0'; x++) { - if (z < NBD_NBTPD_ARGS_PATH_MAX) { - path[z++] = parts[i][x]; - } else { - goto cleanup; - } - } - if (z < NBD_NBTPD_ARGS_PATH_MAX) { - path[z++] = '/'; - } else { - goto cleanup; - } - } - // erase trailing slash - path[z - 1] = '\0'; - fname = strdup(path); - } - if (fname == NULL) { - syslog(LOG_ERR, "unable to get real path: %s", strerror(errno)); - argptr->err = 1; - goto cleanup; - } -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * POSIX does not define what happens when getcwd() is given NULL. * - * This means that illumos libc and GNU libc both return a newly * - * malloc()'d string, while FreeBSD libc does not. Also, FreeBSD uses * - * constant MAXPATHLEN defined in rather than PATH_MAX. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifdef __FreeBSD__ - wd = malloc(MAXPATHLEN); - if (wd == NULL) { - syslog(LOG_ERR, "unable to allocate PATH_MAX memory: %s", strerror(errno)); - argptr->err = 0; - goto cleanup; - } - if (getcwd(wd, MAXPATHLEN) == NULL) { - argptr->err = 0; - goto cleanup; - } -#else - if ((wd = getcwd(NULL, PATH_MAX)) == NULL) { - argptr->err = 0; - goto cleanup; - } -#endif - syslog(LOG_DEBUG, "cwd: %s :: realpath: %s", wd, fname); - if (read) { - if (strncmp(wd, fname, strlen(wd))) { - syslog( - LOG_ERR, - "%s:%d requested invalid file %s", - inet_ntoa(argptr->client.sin_addr), - ntohs(argptr->client.sin_port), - fname - ); - argptr->err = 2; - goto cleanup; - } - } else { - strcat(wd, "/"); - strcat(wd, fname); - char *intermediate = wd; - wd = fname; - fname = intermediate; - } -cleanup: - free(wd); - free(path); - free(parts); - return fname; -} - -ssize_t senderror(int s, nbd_nbtpd_args *argptr) { - size_t buflen = 4 + strlen(nbd_tftp_error_to_message((nbd_tftp_ecode)argptr->err)); - char *buf = nbd_tftp_ser_error_from_code((nbd_tftp_ecode)argptr->err); - ssize_t sb = send(s, buf, buflen, 0); - free(buf); - return sb; -} - -void *read_req_resp(void *args) { - char *fname = NULL, *buf = NULL, *rxb = NULL; - FILE *fp = NULL; - nbd_nbtpd_args *argptr = (nbd_nbtpd_args *)args; - syslog( - LOG_DEBUG, - "%s:%d is requesting file %s", - inet_ntoa(argptr->client.sin_addr), - ntohs(argptr->client.sin_port), - argptr->path - ); - fname = checkpath(argptr, 1); - if (fname == NULL) { - goto pre_socket; - } - if (!is_netascii_str((char *)&(argptr->mode))) { - syslog( - LOG_ERR, - "%s:%d mode is invalid %s", - inet_ntoa(argptr->client.sin_addr), - ntohs(argptr->client.sin_port), - argptr->mode - ); - argptr->err = 4; - goto pre_socket; - } - nbd_opmode opmode = get_mode((char *)&(argptr->mode)); - if ((opmode != NETASCII) && (opmode != OCTET)) { - argptr->err = 4; - goto pre_socket; - } - fp = fopen(fname, "r"); - if (fp == NULL) { - syslog( - LOG_ERR, - "failed to open file for reading: %s", - strerror(errno) - ); - argptr->err = 2; - goto pre_socket; - } - buf = malloc(512); - rxb = malloc(256); - if ((buf == NULL) || (rxb == NULL)) { - syslog( - LOG_CRIT, - "failed to allocate memory: %s", - strerror(errno) - ); - argptr->err = 0; - goto pre_socket; - } - int s = makesock(argptr); - if (s <= 0) { - goto cleanup; - } - uint8_t rxon = 0, lon = 1; - uint16_t bnum = 0; - while (lon) { - memset(buf, '\0', 512); - uint8_t verif = 0; - uint8_t vcount = 0; - size_t num_read = fread(buf, 1, 512, fp); - if (((num_read < 512) && (!feof(fp))) || (vcount > 5)) { - argptr->err = 0; - senderror(s, argptr); - goto cleanup; - } - if ((opmode == NETASCII) && (!is_netascii_buf(buf, num_read))) { - syslog( - LOG_ERR, - "%s:%d: requested file is not netascii compliant.", - inet_ntoa(argptr->client.sin_addr), - ntohs(argptr->client.sin_port) - ); - argptr->err = 5; - senderror(s, argptr); - goto cleanup; - } - char *packet = nbd_tftp_ser_data_from_parts(++bnum, buf, num_read); - while (!verif) { - syslog(LOG_DEBUG, "sending block number %d to %s:%d", - bnum, - inet_ntoa(argptr->client.sin_addr), - htons(argptr->client.sin_port) - ); - if (send(s, packet, num_read + 4, 0) < 0) { - syslog( - LOG_ERR, - "unable to send data to %s: %s", - inet_ntoa(argptr->client.sin_addr), - strerror(errno) - ); - continue; - } - rxon = 1; - uint8_t rxcount = 0; - while (rxon) { - syslog(LOG_DEBUG, "waiting for ack %d from %s:%d", - bnum, - inet_ntoa(argptr->client.sin_addr), - htons(argptr->client.sin_port) - ); - memset(rxb, '\0', 256); - ssize_t rcv = recv(s, rxb, 256, 0); - syslog(LOG_DEBUG, "recv'd %ld bytes from %s:%d", - rcv, - inet_ntoa(argptr->client.sin_addr), - htons(argptr->client.sin_port) - ); - if (rcv == 4) { - nbd_tftp_packet_ack ack = nbd_tftp_de_ack(rxb, rcv); - if (ack.opcode == 5) { - goto socket_clean; - } - syslog(LOG_DEBUG, "%s:%d ack'd with block number: %d (expect %d)", - inet_ntoa(argptr->client.sin_addr), - htons(argptr->client.sin_port), - ack.block_num, - bnum - ); - if (ack.block_num == bnum) { - rxon = 0; - verif = 1; - break; - } - if (ack.block_num == (bnum - 1)) { - rxon = 0; - vcount++; - break; - } - } - if (++rxcount > 30) { - argptr->err = 0; - senderror(s, argptr); - goto cleanup; - } - if (rcv > 4) { - if ((((uint16_t)buf[0] << 8) + buf[1]) == 5) { - goto socket_clean; - } - } - } - } - free(packet); - if (num_read < 512) { - lon = 0; - } - } -socket_clean: - close(s); -cleanup: - fclose(fp); - free(buf); - free(rxb); - free(fname); - free(args); - return (void *)NULL; -pre_socket: - if (fp != NULL) { - fclose(fp); - } - free(buf); - free(rxb); - free(fname); - return nbd_nbtpd_resp_error(args); -} - -void *write_req_resp(void *args) { - char *fname = NULL, *rxb = NULL; - FILE *fp = NULL; - nbd_nbtpd_args *argptr = (nbd_nbtpd_args *)args; - syslog( - LOG_DEBUG, - "%s:%d is trying to write file %s", - inet_ntoa(argptr->client.sin_addr), - ntohs(argptr->client.sin_port), - argptr->path - ); - fname = checkpath(argptr, 0); - if (fname == NULL) { - syslog(LOG_ERR, "fname is NULL"); - goto pre_socket; - } - if (!is_netascii_str((char *)&(argptr->mode))) { - syslog( - LOG_ERR, - "%s:%d mode is invalid %s", - inet_ntoa(argptr->client.sin_addr), - ntohs(argptr->client.sin_port), - argptr->mode - ); - argptr->err = 4; - goto pre_socket; - } - nbd_opmode opmode = get_mode((char *)&(argptr->mode)); - if ((opmode != NETASCII) && (opmode != OCTET)) { - syslog(LOG_ERR, "%s:%d mode is not supported.", inet_ntoa(argptr->client.sin_addr), ntohs(argptr->client.sin_port)); - argptr->err = 4; - goto pre_socket; - } - fp = fopen(fname, "w"); - if (fp == NULL) { - syslog( - LOG_ERR, - "failed to open file for writing: %s", - strerror(errno) - ); - argptr->err = 2; - goto pre_socket; - } - rxb = malloc(768); // 768 is 1.5x expected block size - if (rxb == NULL) { - syslog( - LOG_CRIT, - "failed to allocate memory: %s", - strerror(errno) - ); - argptr->err = 0; - goto pre_socket; - } - int s = makesock(argptr); - if (s <= 0) { - goto cleanup; - } - uint8_t rxon = 0, lon = 1; - uint16_t bnum = 0; - ssize_t rcv = 516; - while (lon) { - uint8_t verif = 0; - uint8_t vcount = 0; - char *packet = nbd_tftp_ser_ack_from_block_num(bnum++); - while (!verif) { - syslog(LOG_DEBUG, "sending ack number %d to %s:%d", - bnum, - inet_ntoa(argptr->client.sin_addr), - htons(argptr->client.sin_port) - ); - if (send(s, packet, 4, 0) < 0) { - syslog( - LOG_ERR, - "unable to send ack to %s:%d: %s", - inet_ntoa(argptr->client.sin_addr), - htons(argptr->client.sin_port), - strerror(errno) - ); - continue; - } - if ((rcv < 516) || (vcount > 5)) { - lon = 0; - break; - } - rxon = 1; - uint8_t rxcount = 0; - while (rxon) { - syslog(LOG_DEBUG, "waiting for data from %s:%d", - inet_ntoa(argptr->client.sin_addr), - htons(argptr->client.sin_port) - ); - memset(rxb, '\0', 768); - rcv = recv(s, rxb, 768, 0); - syslog(LOG_DEBUG, "recv'd %ld bytes from %s:%d", - rcv, - inet_ntoa(argptr->client.sin_addr), - htons(argptr->client.sin_port) - ); - if (rcv >= 4) { - nbd_tftp_packet_data data = nbd_tftp_de_data(rxb, rcv); - if (data.opcode == 5) { - free(data.data); - goto cleanup; - } - syslog( - LOG_DEBUG, - "%s:%d sent block number: %d (expect %d)", - inet_ntoa(argptr->client.sin_addr), - htons(argptr->client.sin_port), - data.block_num, - bnum - ); - if (data.block_num == bnum) { - rxon = 0; - verif = 1; - if (data.datalen > 0) { - if ((opmode == NETASCII) && (!is_netascii_buf(data.data, data.datalen))) { - syslog( - LOG_ERR, - "%s:%d: requested file is not netascii compliant.", - inet_ntoa(argptr->client.sin_addr), - ntohs(argptr->client.sin_port) - ); - argptr->err = 5; - senderror(s, argptr); - free(data.data); - goto cleanup; - } - if (fwrite(data.data, 1, data.datalen, fp) < data.datalen) { - syslog(LOG_ERR, "filewrite failed for %s: %s", fname, strerror(errno)); - argptr->err = 0; - senderror(s, argptr); - free(data.data); - goto clean_socket; - } - } - free(data.data); - break; - } - if (data.block_num == (bnum - 1)) { - rxon = 0; - vcount++; - free(data.data); - break; - } - free(data.data); - } - if (++rxcount > 30) { - syslog(LOG_ERR, "retry count exceeded"); - argptr->err = 0; - senderror(s, argptr); - goto clean_socket; - } - } - } - free(packet); - } -clean_socket: - close(s); -cleanup: - fclose(fp); - free(rxb); - free(fname); - free(args); - return (void *)NULL; -pre_socket: - if (fp != NULL) { - fclose(fp); - } - free(rxb); - free(fname); - return nbd_nbtpd_resp_error(args); -} - -void *nbd_nbtpd_resp_error(void *args) { - nbd_nbtpd_args *argptr = (nbd_nbtpd_args *)args; - int s = makesock(argptr); - if (s <= 0) { - syslog( - LOG_ERR, - "cannot send error to %s:%d", - inet_ntoa(argptr->client.sin_addr), - ntohs(argptr->client.sin_port) - ); - goto cleanup; - } - senderror(s, argptr); -cleanup: - free(args); - return (void *)NULL; -} - diff --git a/src/main.c b/src/main.c deleted file mode 100644 index 7114cc7..0000000 --- a/src/main.c +++ /dev/null @@ -1,313 +0,0 @@ -#ifdef __linux__ -#define _POSIX_C_SOURCE 2 -#define _DEFAULT_SOURCE -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -//TODO: use threads.h instead -#include - -// illumos-only headers -#ifdef __illumos__ -#include -#endif - -#include "packet.h" -#include "netascii.h" -#include "handlers.h" - -int nbtpd_stop = 0; - -void stop_handler(int i) { - syslog(LOG_ERR, "caught shutdown signal, cleaning up and awaiting threads"); - if (i != 0) { - nbtpd_stop = i; - } else { - nbtpd_stop = 1; - } - return; -} - -void usage(char *name) { - //TODO: print to stderr; cleanup to be compliant - fprintf(stderr, - "usage: %s -h [-d [-u USER] [-g GROUP]] [-a INET_ADDRESS] [-p PORT] [-l LEVEL]\n", - name - ); - fprintf(stderr, "\td: daemonize.\n"); - fprintf(stderr, - "\tu: username to run as (default: nobody). Must be specified after -d.\n" - ); - fprintf(stderr, - "\tg: group to run as (default: nobody). Must be specified after -d.\n" - ); - fprintf(stderr, "\ta: address to bind to (default: 127.0.0.1)\n"); - fprintf(stderr, "\tp: port to bind to (default: 69)\n"); - fprintf(stderr, "\tl: log level; one of:\n"); - fprintf(stderr, "\t\temerg\n\t\talert\n\t\tcrit\n\t\terr\n\t\twarn\n"); - fprintf(stderr, "\t\tnotice\n\t\tinfo (default)\n\t\tdebug\n"); -} - -int set_loglevel(char *level) { - if (strncmp("emerg", level, 6) == 0) { - setlogmask(LOG_UPTO(LOG_EMERG)); - return 0; - } - if (strncmp("alert", level, 6) == 0) { - setlogmask(LOG_UPTO(LOG_ALERT)); - return 0; - } - if (strncmp("crit", level, 5) == 0) { - setlogmask(LOG_UPTO(LOG_CRIT)); - return 0; - } - if (strncmp("err", level, 4) == 0) { - setlogmask(LOG_UPTO(LOG_ERR)); - return 0; - } - if (strncmp("warn", level, 5) == 0) { - setlogmask(LOG_UPTO(LOG_WARNING)); - return 0; - } - if (strncmp("notice", level, 7) == 0) { - setlogmask(LOG_UPTO(LOG_NOTICE)); - return 0; - } - if (strncmp("info", level, 5) == 0) { - setlogmask(LOG_UPTO(LOG_INFO)); - return 0; - } - if (strncmp("debug", level, 6) == 0) { - setlogmask(LOG_UPTO(LOG_DEBUG)); - return 0; - } - return -1; -} - -int main(int argc, char **argv) { - int retme = 0; - int daemonize = 0, loglevset = 0; - char addr[17], user[32], group[32]; - memset(addr, '\0', sizeof(addr)); - memset(user, '\0', sizeof(user)); - memset(group, '\0', sizeof(group)); - strcpy(addr, "127.0.0.1"); - strcpy(user, "nobody"); - strcpy(group, "nobody"); - int port = 69; - int ch = 0; - while ((ch = getopt(argc, argv, "da:p:u:g:l:h")) != -1) { - switch (ch) { - case 'a': - strncpy(addr, optarg, sizeof(addr) - 1); - break; - case 'p': - port = atoi(optarg); - if ((port <= 0) || (port >= 65536)) { - fprintf(stderr, "invalid port specified.\n"); - return -1; - } - break; - case 'd': - daemonize = 1; - break; - case 'g': - if (daemonize) { - strncpy(group, optarg, sizeof(group) - 1); - } else { - fprintf(stderr, "-g requires -d\n"); - return -1; - } - break; - case 'u': - if (daemonize) { - strncpy(user, optarg, sizeof(user) - 1); - } else { - fprintf(stderr, "-u requires -d\n"); - return -1; - } - break; - case 'l': - loglevset = 1; - if (set_loglevel(optarg)) { - fprintf(stderr, "invalid option for -l\n"); - usage(argv[0]); - return -1; - } - break; - case 'h': case '?': - usage(argv[0]); - return -1; - } - } - if (!loglevset) { - setlogmask(LOG_UPTO(LOG_INFO)); - } -#ifdef __illumos__ - openlog(argv[0], LOG_PID | LOG_NDELAY, LOG_FTP); -#else - openlog(argv[0], LOG_PID | LOG_PERROR | LOG_NDELAY, LOG_FTP); -#endif - syslog(LOG_INFO, "starting up..."); - signal(SIGTERM, &stop_handler); - signal(SIGINT, &stop_handler); - char *buf = NULL; - int s = socket(AF_INET, SOCK_DGRAM, 0); - if (s <= 0) { - syslog(LOG_ERR, "unable to bind socket!"); - return -1; - } - if (daemonize) { - if (daemon(1, 0)) { - syslog(LOG_ERR, "failed to daemonize: %s", strerror(errno)); - retme = -1; - goto cleanup; - } else { - syslog(LOG_INFO, "daemonized"); - } - } - struct timeval timeout = { 30, 0 }; - if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0) { - syslog(LOG_ERR, "unable to set socket timeout: %s", strerror(errno)); - retme = -1; - goto cleanup; - } - struct sockaddr_in saddr; - saddr.sin_family = AF_INET; - saddr.sin_port = htons(port); - saddr.sin_addr.s_addr = inet_addr(addr); - if (bind(s, (struct sockaddr*)&saddr, sizeof(saddr)) < 0) { - syslog(LOG_ERR, "socket bind failed: %s", strerror(errno)); - retme = -1; - goto cleanup; - } - syslog(LOG_DEBUG, "socket bind success"); - if (daemonize) { - //TODO: use getpwnam_r() and getgrnam_r() - struct group *g = getgrnam((const char *)&group); - if (setgid((*g).gr_gid) == -1) { - syslog( - LOG_ERR, - "failed to drop group privileges: %s", - strerror(errno) - ); - retme = -1; - goto cleanup; - } - struct passwd *u = getpwnam((const char *)&user); - if (setuid((*u).pw_uid) == -1) { - syslog( - LOG_ERR, - "failed to drop user privileges: %s", - strerror(errno) - ); - retme = -1; - goto cleanup; - } - } -#ifdef __illumos__ - //TODO: illumos priv.h privdrop -#endif - buf = malloc(1024); - if (buf == NULL) { - syslog(LOG_CRIT, "unable to allocate memory: %s", strerror(errno)); - retme = -1; - goto cleanup; - } - while (!nbtpd_stop) { - struct sockaddr_in caddr; - unsigned int clen = sizeof(caddr); - memset(buf, '\0', 1024); - ssize_t recvd_bytes = 0; - if ((recvd_bytes = recvfrom(s, buf, 1024, 0, - (struct sockaddr *)&caddr, &clen)) < 0) { - continue; - } - if (recvd_bytes < 4) { - syslog( - LOG_ERR, - "ignoring invalid packet from %s.", - inet_ntoa(caddr.sin_addr) - ); - continue; - } - syslog( - LOG_INFO, - "got connection from %s:%d", - inet_ntoa(caddr.sin_addr), - ntohs(caddr.sin_port) - ); - nbd_nbtpd_args *args = malloc(sizeof(nbd_nbtpd_args)); - if (args == NULL) { - syslog( - LOG_CRIT, - "unable to allocate memory: %s", - strerror(errno) - ); - continue; - } - nbd_tftp_opcode oc = ((uint16_t)buf[0] << 8) + buf[1]; - args->client = caddr; - args->err = 0; - memset(args->path, '\0', NBD_NBTPD_ARGS_PATH_MAX); - memset(args->mode, '\0', NBD_NBTPD_ARGS_MODE_MAX); - int i; - for(i = 2; buf[i] != 0 && i < recvd_bytes && (i - 2) < (NBD_NBTPD_ARGS_PATH_MAX - 1); i++) { - args->path[i - 2] = buf[i]; - } - int s = i + 1; - if (s >= recvd_bytes) { - oc = 0; - } else { - for(i = s; buf[i] != 0 && i < recvd_bytes && (i - s) < (NBD_NBTPD_ARGS_MODE_MAX - 1); i++) { - args->mode[i - s] = buf[i]; - } - } - //TODO: use std threads - pthread_t _thread; - void *(*func)(void *); - switch (oc) { - case RRQ: - func = &read_req_resp; - break; - case WRQ: - func = &write_req_resp; - break; - default: - (*args).err = 4; - func = &nbd_nbtpd_resp_error; - } - //TODO: use std threads - int e; - syslog(LOG_ERR, "spawning thread for %s", inet_ntoa(caddr.sin_addr)); - if ((e = pthread_create(&_thread, 0, func, (void *)args)) != 0) { - syslog( - LOG_CRIT, - "unable to spawn thread: %s", - strerror(e) - ); - free(args); - } - } -cleanup: - free(buf); - close(s); - pthread_exit(NULL); - return retme; -} - diff --git a/src/netascii.c b/src/netascii.c deleted file mode 100644 index d061e57..0000000 --- a/src/netascii.c +++ /dev/null @@ -1,53 +0,0 @@ -#include -#include - -#include "netascii.h" - -uint8_t is_netascii_char(char c) { - static const uint64_t LUT[4] = - {0xffffffff00003f81, - 0x7fffffffffffffff, - 0x00,0x00}; - int i = c / 64; - int e = i % 64; - return (LUT[i] >> e) & 1; -} - -/// WARNING! This function is NOT safe. Use only for strings you have already -/// verified are NULL terminated! -uint8_t is_netascii_str(char *str) { - for (uint64_t i = 0; str[i] != 0; i++) { - if (!is_netascii_char(str[i])) { - return 0; - } else { - if (str[i] == '\r') { - if (str[++i] != '\n') { - return 0; - } - } - } - } - return 1; -} - -uint8_t is_netascii_buf(char *buf, size_t len) { - for (uint64_t i = 0; i < len; i++) { - if (!is_netascii_char(buf[i])) { - return 0; - } else { - if (buf[i] == '\r') { - if ((i + 1) < len) { - switch (buf[++i]) { - case 0: case '\n': - break; - default: - return 0; - } - } else { - return 0; - } - } - } - } - return 1; -} diff --git a/src/packet.c b/src/packet.c deleted file mode 100644 index d439ec9..0000000 --- a/src/packet.c +++ /dev/null @@ -1,125 +0,0 @@ -#include -#include -#include -#include -#include "packet.h" - -char *nbd_tftp_error_to_message(nbd_tftp_ecode error) { - switch (error) { - case 0: - return "ERROR"; - case 1: - return "File not Found"; - case 2: - return "Access violation"; - case 3: - return "Disk full or allocation exceeded"; - case 4: - return "Illegal TFTP operation"; - case 5: - return "Unknown Transfer ID"; - case 6: - return "File already exists"; - case 7: - return "No such user"; - } - return "UNKNOWN ERROR"; -} - -char *nbd_tftp_ser_data(nbd_tftp_packet_data d) { - char *buf = malloc(sizeof(d.opcode) + sizeof(d.block_num) + d.datalen); - if (buf != NULL) { - uint16_t netopcode = htons(d.opcode); - uint16_t netbnum = htons(d.block_num); - memcpy(buf, &netopcode, sizeof(netopcode)); - memcpy((buf + sizeof(netopcode)), &netbnum, sizeof(netbnum)); - memcpy((buf + sizeof(netopcode) + sizeof(netbnum)), d.data, d.datalen); - } - return buf; -} - -char *nbd_tftp_ser_data_from_parts(uint16_t blocknum, char *data, size_t datalen) { - char *buf = malloc(sizeof(uint16_t) + sizeof(blocknum) + datalen); - if (buf != NULL) { - uint16_t netopcode = htons(3); - uint16_t netbnum = htons(blocknum); - memcpy(buf, &netopcode, sizeof(netopcode)); - memcpy((buf + sizeof(netopcode)), &netbnum, sizeof(netbnum)); - memcpy((buf + sizeof(netopcode) + sizeof(netbnum)), data, datalen); - } - return buf; -} - -nbd_tftp_packet_data nbd_tftp_de_data(char *data, size_t len) { - nbd_tftp_packet_data ret = { 0, 0, (char *)NULL, (size_t)0 }; - if ((len >= 4) && (data != NULL)) { - ret.opcode = ((uint16_t)data[0] << 8) + data[1]; - ret.block_num = ((uint16_t)data[2] << 8) + data[3]; - ret.datalen = len - 4; - if (ret.datalen > 0) { - if ((ret.data = malloc(ret.datalen)) != NULL) { - memcpy(ret.data, (data + 4), ret.datalen); - } - } - } - return ret; -} - -char *nbd_tftp_ser_error(nbd_tftp_packet_error e) { - char *buf = malloc(sizeof(e.opcode) + sizeof((uint16_t)e.err) + strlen(e.emsg)); - if (buf != NULL) { - uint16_t netopcode = htons(e.opcode); - uint16_t netecode = htons((uint16_t)e.err); - memcpy(buf, &netopcode, sizeof(netopcode)); - memcpy((buf + sizeof(netopcode)), &netecode, sizeof(netecode)); - memcpy((buf + sizeof(netopcode) + sizeof(netecode)), e.emsg, strlen(e.emsg)); - } - return buf; -} - -char *nbd_tftp_ser_error_from_code(nbd_tftp_ecode error) { - char *emsg = nbd_tftp_error_to_message(error); - char *buf = malloc(sizeof(uint16_t) + sizeof(uint16_t) + strlen(emsg)); - if (buf != NULL) { - uint16_t netopcode = htons(5); - uint16_t netecode = htons((uint16_t)error); - memcpy(buf, &netopcode, sizeof(netopcode)); - memcpy((buf + sizeof(netopcode)), &netecode, sizeof(netecode)); - memcpy((buf + sizeof(netopcode) + sizeof(netecode)), emsg, strlen(emsg)); - } - return buf; -} - -char *nbd_tftp_ser_ack(nbd_tftp_packet_ack ack) { - char *buf = malloc(sizeof(ack.opcode) + sizeof(ack.block_num)); - if (buf != NULL) { - uint16_t netopcode = htons(ack.opcode); - uint16_t netbnum = htons(ack.block_num); - memcpy(buf, &netopcode, sizeof(netopcode)); - memcpy((buf + sizeof(netopcode)), &netbnum, sizeof(netbnum)); - } - return buf; -} - -char *nbd_tftp_ser_ack_from_block_num(uint16_t block_num) { - char *buf = malloc(sizeof(uint16_t) + sizeof(block_num)); - if (buf != NULL) { - uint16_t netopcode = htons(4); - uint16_t netbnum = htons(block_num); - memcpy(buf, &netopcode, sizeof(netopcode)); - memcpy((buf + sizeof(netopcode)), &netbnum, sizeof(netbnum)); - } - return buf; -} - -nbd_tftp_packet_ack nbd_tftp_de_ack(char *buf, ssize_t buflen) { - nbd_tftp_packet_ack ack = { 0, 0 }; - if ((buf != NULL) && (buflen == 4)) { - uint16_t opcode = ((uint16_t)buf[0] << 8) + buf[1]; - uint16_t block_num = ((uint16_t)buf[2] << 8) + buf[3]; - ack.opcode = opcode; - ack.block_num = block_num; - } - return ack; -} - -- cgit 1.4.1-2-gfad0