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
그리고 마침내, docker에서 소켓을 열지 못하는 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