From 1ec8810c510e596ccfd73cf6ad187057a760f85f Mon Sep 17 00:00:00 2001 From: Anton Maminov Date: Tue, 17 Sep 2024 17:21:47 +0300 Subject: [PATCH 1/5] use local IP address by default --- src/ext/lib_c/c/netinet/in.cr | 14 +++++++++++++ src/ext/socket.cr | 37 +++++++++++++++++++++++++++++++++++ src/ext/socket/address.cr | 14 +++++++++++++ src/zipstream.cr | 4 ++++ src/zipstream/config.cr | 13 ++++++++++-- 5 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 src/ext/lib_c/c/netinet/in.cr create mode 100644 src/ext/socket.cr create mode 100644 src/ext/socket/address.cr diff --git a/src/ext/lib_c/c/netinet/in.cr b/src/ext/lib_c/c/netinet/in.cr new file mode 100644 index 0000000..3f0f7f5 --- /dev/null +++ b/src/ext/lib_c/c/netinet/in.cr @@ -0,0 +1,14 @@ +lib LibC + struct Ifaddrs + ifa_next : Pointer(Ifaddrs) + ifa_name : UInt64 + ifa_flags : UInt32 + ifa_addr : Pointer(Void) + ifa_netmask : Pointer(Void) + ifa_broadaddr : Pointer(Void) + ifa_data : Pointer(Void) + end + + fun getifaddrs(addrs : Pointer(Pointer(Ifaddrs))) : Int32 + fun freeifaddrs(addrs : Pointer(Ifaddrs)) : Void +end diff --git a/src/ext/socket.cr b/src/ext/socket.cr new file mode 100644 index 0000000..71a3ab5 --- /dev/null +++ b/src/ext/socket.cr @@ -0,0 +1,37 @@ +class Socket + def self.ip_address_list : Array(Socket::IPAddress) + ptr = Pointer(Pointer(LibC::Ifaddrs)).malloc(1) + ret = LibC.getifaddrs(ptr) + + if ret == -1 + raise raise Socket::Error.new("Failed to get network interfaces") + end + + list = [] of Socket::IPAddress + addr = ptr.value + + while addr + if addr.value.ifa_addr.null? + addr = addr.value.ifa_next + next + end + + sockaddr_in = addr.value.ifa_addr.as(Pointer(LibC::SockaddrIn)) + + unless sockaddr_in.value.sin_family.in?([Socket::Family::INET.to_i, Socket::Family::INET6.to_i]) + addr = addr.value.ifa_next + next + end + + ip_address = Socket::IPAddress.from(sockaddr_in, sizeof(typeof(sockaddr_in))) + + list << ip_address + + addr = addr.value.ifa_next + end + + LibC.freeifaddrs(ptr.value) + + list + end +end diff --git a/src/ext/socket/address.cr b/src/ext/socket/address.cr new file mode 100644 index 0000000..766992e --- /dev/null +++ b/src/ext/socket/address.cr @@ -0,0 +1,14 @@ +class Socket + struct IPAddress + def self.from(sockaddr : LibC::SockaddrIn*, addrlen) : IPAddress + case family = Family.new(sockaddr.value.sin_family) + when Family::INET6 + new(sockaddr.as(LibC::SockaddrIn6*), addrlen.to_i) + when Family::INET + new(sockaddr.as(LibC::SockaddrIn*), addrlen.to_i) + else + raise "Unsupported family type: #{family} (#{family.value})" + end + end + end +end diff --git a/src/zipstream.cr b/src/zipstream.cr index 6d68c18..059b515 100644 --- a/src/zipstream.cr +++ b/src/zipstream.cr @@ -6,6 +6,10 @@ require "crystar" require "zip64" require "qr-code" +require "./ext/lib_c/c/netinet/in" +require "./ext/socket" +require "./ext/socket/address" + require "./zipstream/**" module Zipstream diff --git a/src/zipstream/config.cr b/src/zipstream/config.cr index e7801a7..b4b2a33 100644 --- a/src/zipstream/config.cr +++ b/src/zipstream/config.cr @@ -2,7 +2,7 @@ module Zipstream class Config INSTANCE = Config.new - property host + setter host : String? = nil property port property? log : Bool = false property? web : Bool = false @@ -21,7 +21,6 @@ module Zipstream property? no_banner : Bool = false def initialize - @host = "0.0.0.0" @port = 8090 @format = "zip" @output = "download" @@ -30,6 +29,10 @@ module Zipstream @env = "development" end + def host + @host || local_ip_address.try(&.address) || "0.0.0.0" + end + def filename [output, format].join(".") end @@ -53,5 +56,11 @@ module Zipstream str << url_path end end + + def local_ip_address : Socket::IPAddress? + Socket.ip_address_list.find do |ip_address| + ip_address.family == Socket::Family::INET && ip_address.private? && !ip_address.address.starts_with?("127") + end + end end end From 27fd06fa7970a8a71c746d347d9fab1f54a877fc Mon Sep 17 00:00:00 2001 From: Anton Maminov Date: Tue, 17 Sep 2024 17:31:35 +0300 Subject: [PATCH 2/5] test Config.host --- spec/zipstream/config_spec.cr | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 spec/zipstream/config_spec.cr diff --git a/spec/zipstream/config_spec.cr b/spec/zipstream/config_spec.cr new file mode 100644 index 0000000..ec72fbd --- /dev/null +++ b/spec/zipstream/config_spec.cr @@ -0,0 +1,11 @@ +require "../spec_helper" + +describe Zipstream::Config do + config = Zipstream::Config.new + + context "host" do + it "should has host" do + config.host.should eq("") + end + end +end From b8318e4f79159c2d8dc4f8f03e1b2378e991a249 Mon Sep 17 00:00:00 2001 From: Anton Maminov Date: Tue, 17 Sep 2024 17:52:43 +0300 Subject: [PATCH 3/5] fix Error: expected argument #1 to 'Socket::Family.new' to be UInt8, not Int16 --- src/ext/socket/address.cr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ext/socket/address.cr b/src/ext/socket/address.cr index 766992e..358962d 100644 --- a/src/ext/socket/address.cr +++ b/src/ext/socket/address.cr @@ -1,7 +1,7 @@ class Socket struct IPAddress def self.from(sockaddr : LibC::SockaddrIn*, addrlen) : IPAddress - case family = Family.new(sockaddr.value.sin_family) + case family = Family.new(sockaddr.value.sin_family.to_u8) when Family::INET6 new(sockaddr.as(LibC::SockaddrIn6*), addrlen.to_i) when Family::INET From 87accc58689cf649f82966163f25a2d5e3b7033b Mon Sep 17 00:00:00 2001 From: Anton Maminov Date: Tue, 17 Sep 2024 17:59:48 +0300 Subject: [PATCH 4/5] fix spec on Linux/macOS --- spec/zipstream/config_spec.cr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/zipstream/config_spec.cr b/spec/zipstream/config_spec.cr index ec72fbd..509847f 100644 --- a/spec/zipstream/config_spec.cr +++ b/spec/zipstream/config_spec.cr @@ -4,8 +4,8 @@ describe Zipstream::Config do config = Zipstream::Config.new context "host" do - it "should has host" do - config.host.should eq("") + it "should has host as local IP address" do + config.host.should match(/\d+\.\d+\.\d+\.\d+/) end end end From ee722a8ad93b3c6e92d5b1a76b1be7f08a992653 Mon Sep 17 00:00:00 2001 From: Anton Maminov Date: Fri, 20 Sep 2024 12:16:40 +0300 Subject: [PATCH 5/5] use ip_address_list shard --- shard.lock | 4 ++++ shard.yml | 2 ++ src/ext/lib_c/c/netinet/in.cr | 14 ------------- src/ext/socket.cr | 37 ----------------------------------- src/ext/socket/address.cr | 14 ------------- src/zipstream.cr | 5 +---- 6 files changed, 7 insertions(+), 69 deletions(-) delete mode 100644 src/ext/lib_c/c/netinet/in.cr delete mode 100644 src/ext/socket.cr delete mode 100644 src/ext/socket/address.cr diff --git a/shard.lock b/shard.lock index 9bf16b0..718c38e 100644 --- a/shard.lock +++ b/shard.lock @@ -4,6 +4,10 @@ shards: git: https://github.com/naqvis/crystar.git version: 0.4.0+git.commit.3975502cbe89bca528e1af4b86fbfc0f0bfacce1 + ip_address_list: + git: https://github.com/mamantoha/ip_address_list.git + version: 0.1.0 + qr-code: git: https://github.com/spider-gazelle/qr-code.git version: 1.0.3 diff --git a/shard.yml b/shard.yml index b5741cf..e376e9a 100644 --- a/shard.yml +++ b/shard.yml @@ -13,6 +13,8 @@ dependencies: version: ">= 0.2.0" qr-code: github: spider-gazelle/qr-code + ip_address_list: + github: mamantoha/ip_address_list targets: zipstream: diff --git a/src/ext/lib_c/c/netinet/in.cr b/src/ext/lib_c/c/netinet/in.cr deleted file mode 100644 index 3f0f7f5..0000000 --- a/src/ext/lib_c/c/netinet/in.cr +++ /dev/null @@ -1,14 +0,0 @@ -lib LibC - struct Ifaddrs - ifa_next : Pointer(Ifaddrs) - ifa_name : UInt64 - ifa_flags : UInt32 - ifa_addr : Pointer(Void) - ifa_netmask : Pointer(Void) - ifa_broadaddr : Pointer(Void) - ifa_data : Pointer(Void) - end - - fun getifaddrs(addrs : Pointer(Pointer(Ifaddrs))) : Int32 - fun freeifaddrs(addrs : Pointer(Ifaddrs)) : Void -end diff --git a/src/ext/socket.cr b/src/ext/socket.cr deleted file mode 100644 index 71a3ab5..0000000 --- a/src/ext/socket.cr +++ /dev/null @@ -1,37 +0,0 @@ -class Socket - def self.ip_address_list : Array(Socket::IPAddress) - ptr = Pointer(Pointer(LibC::Ifaddrs)).malloc(1) - ret = LibC.getifaddrs(ptr) - - if ret == -1 - raise raise Socket::Error.new("Failed to get network interfaces") - end - - list = [] of Socket::IPAddress - addr = ptr.value - - while addr - if addr.value.ifa_addr.null? - addr = addr.value.ifa_next - next - end - - sockaddr_in = addr.value.ifa_addr.as(Pointer(LibC::SockaddrIn)) - - unless sockaddr_in.value.sin_family.in?([Socket::Family::INET.to_i, Socket::Family::INET6.to_i]) - addr = addr.value.ifa_next - next - end - - ip_address = Socket::IPAddress.from(sockaddr_in, sizeof(typeof(sockaddr_in))) - - list << ip_address - - addr = addr.value.ifa_next - end - - LibC.freeifaddrs(ptr.value) - - list - end -end diff --git a/src/ext/socket/address.cr b/src/ext/socket/address.cr deleted file mode 100644 index 358962d..0000000 --- a/src/ext/socket/address.cr +++ /dev/null @@ -1,14 +0,0 @@ -class Socket - struct IPAddress - def self.from(sockaddr : LibC::SockaddrIn*, addrlen) : IPAddress - case family = Family.new(sockaddr.value.sin_family.to_u8) - when Family::INET6 - new(sockaddr.as(LibC::SockaddrIn6*), addrlen.to_i) - when Family::INET - new(sockaddr.as(LibC::SockaddrIn*), addrlen.to_i) - else - raise "Unsupported family type: #{family} (#{family.value})" - end - end - end -end diff --git a/src/zipstream.cr b/src/zipstream.cr index 059b515..04639a8 100644 --- a/src/zipstream.cr +++ b/src/zipstream.cr @@ -5,10 +5,7 @@ require "option_parser" require "crystar" require "zip64" require "qr-code" - -require "./ext/lib_c/c/netinet/in" -require "./ext/socket" -require "./ext/socket/address" +require "ip_address_list" require "./zipstream/**"