ICMP ECHOリクエストをビルドしていくつかの異なるIPアドレスに送信するアプリケーションを実行しています。アプリケーションはCrystalで書かれています。クリスタルドッカーコンテナ内からソケットを開くとき、Crystalは例外を発生させます:アクセスが拒否されました。ドッカーコンテナからDGRAMソケットを開くことができません(許可が拒否されました)
コンテナ内からは、ping 8.8.8.8
を実行しても問題ありません。
MacOSでアプリケーションを実行しても問題はありません。 AppArmorのとseccomp上https://docs.docker.com/engine/security/apparmor/とhttps://docs.docker.com/engine/security/seccomp/ページを読ん
は、私は解決策を見つけたと確信していたが、問題は、更新/編集
docker run --rm --security-opt seccomp=unconfined --security-opt apparmor=unconfined socket_permission
として実行している場合でも、未解決のまま:capabilities(7)
に掘りした後、私は私のdockerfileに次の行を追加しました:RUN setcap cap_net_raw+ep bin/ping
ソケットをオープンにすることを試みましたが、変更はありません。 ありがとうございます!
関連結晶ソケットコードは、以下の完全に動作するコードサンプル:
# send request
address = Socket::IPAddress.new host, 0
socket = IPSocket.new Socket::Family::INET, Socket::Type::DGRAM, Socket::Protocol::ICMP
socket.send slice, to: address
Dockerfile:
FROM crystallang/crystal:0.23.1
WORKDIR /opt
COPY src/ping.cr src/
RUN mkdir bin
RUN crystal -v
RUN crystal build -o bin/ping src/ping.cr
ENTRYPOINT ["/bin/sh","-c"]
CMD ["/opt/bin/ping"]
がコードを実行すると、最初のネイティブは、ドッキングウィンドウ経由:
#!/bin/bash
crystal run src/ping.cr
docker build -t socket_permission .
docker run --rm --security-opt seccomp=unconfined --security-opt apparmor=unconfined socket_permission
そして、最後に、ドッカーのソケットを開けない50行のクリスタルスクリプト:
require "socket"
TYPE = 8_u16
IP_HEADER_SIZE_8 = 20
PACKET_LENGTH_8 = 16
PACKET_LENGTH_16 = 8
MESSAGE = " ICMP"
def ping
sequence = 0_u16
sender_id = 0_u16
host = "8.8.8.8"
# initialize packet with MESSAGE
packet = Array(UInt16).new PACKET_LENGTH_16 do |i|
MESSAGE[ i % MESSAGE.size ].ord.to_u16
end
# build out ICMP header
packet[0] = (TYPE.to_u16 << 8)
packet[1] = 0_u16
packet[2] = sender_id
packet[3] = sequence
# calculate checksum
checksum = 0_u32
packet.each do |byte|
checksum += byte
end
checksum += checksum >> 16
checksum = checksum^0xffff_ffff_u32
packet[1] = checksum.to_u16
# convert packet to 8 bit words
slice = Bytes.new(PACKET_LENGTH_8)
eight_bit_packet = packet.map do |word|
[(word >> 8), (word & 0xff)]
end.flatten.map(&.to_u8)
eight_bit_packet.each_with_index do |chr, i|
slice[i] = chr
end
# send request
address = Socket::IPAddress.new host, 0
socket = IPSocket.new Socket::Family::INET, Socket::Type::DGRAM, Socket::Protocol::ICMP
socket.send slice, to: address
# receive response
buffer = Bytes.new(PACKET_LENGTH_8 + IP_HEADER_SIZE_8)
count, address = socket.receive buffer
length = buffer.size
icmp_data = buffer[IP_HEADER_SIZE_8, length-IP_HEADER_SIZE_8]
end
ping