我正在尝试发送一条 TTL 仅为 1 的 icmp 消息,并希望收到超时消息。该消息确实出现了(我从 wireshark 看到了它),但我的程序在 syscall.Recvfrom 上阻塞。谁知道为什么?
icmp.go
package main
import (
"bytes"
"encoding/binary"
"fmt"
"net"
"os"
"syscall"
)
type ICMP struct {
Type uint8
Code uint8
Checksum uint16
Identifier uint16
SeqNo uint16
}
func Checksum(data []byte) uint16 {
var (
sum uint32
length int = len(data)
index int
)
for length > 1 {
sum += uint32(data[index])<<8 + uint32(data[index+1])
index += 2
length -= 2
}
if length > 0 {
sum += uint32(data[index])
}
sum += (sum >> 16)
return uint16(^sum)
}
func main() {
h := Header{
Version: 4,
Len: 20,
TotalLen: 20 + 8,
TTL: 1,
Protocol: 1,
// Dst:
}
argc := len(os.Args)
if argc < 2 {
fmt.Println("usage: program + host")
return
}
ipAddr, _ := net.ResolveIPAddr("ip", os.Args[1])
h.Dst = ipAddr.IP
icmpReq := ICMP{
Type: 8,
Code: 0,
Identifier: 0,
SeqNo: 0,
}
out, err := h.Marshal()
if err != nil {
fmt.Println("ip header error", err)
return
}
var icmpBuf bytes.Buffer
binary.Write(&icmpBuf, binary.BigEndian, icmpReq)
icmpReq.Checksum = Checksum(icmpBuf.Bytes())
icmpBuf.Reset()
binary.Write(&icmpBuf, binary.BigEndian, icmpReq)
fd, _ := syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, syscall.IPPROTO_RAW)
addr := syscall.SockaddrInet4{
Port: 0,
}
copy(addr.Addr[:], ipAddr.IP[12:16])
pkg := append(out, icmpBuf.Bytes()...)
fmt.Println("ip length", len(pkg))
if err := syscall.Sendto(fd, pkg, 0, &addr); err != nil {
fmt.Println("Sendto err:", err)
}
var recvBuf []byte
if nBytes, rAddr, err := syscall.Recvfrom(fd, recvBuf, 0); err == nil {
fmt.Printf("recv %d bytes from %v\n", nBytes, rAddr)
}
}
另外,我使用来自 https://github.com/golang/net/tree/master/ipv4 的 header.go 和 helper.go
最佳答案
正如安迪指出的那样,raw(7) man page说:
An IPPROTO_RAW socket is send only. If you really want to receive all IP packets, use a packet(7) socket with the ETH_P_IP protocol. Note that packet sockets don't reassemble IP fragments, unlike raw sockets.
我知道如果我在创建套接字时将 IPPROTO_ICMP 设置为协议(protocol),我可以收到 ICMP 回复,但我需要将 TTL 设置为 1,这必须在IP层。因此,我使用 IPPROTO_RAW 套接字发送 ICMP 请求,之后我使用 net.ListenIP 接收 ICMP 消息。这是代码:
package main
import (
"bytes"
"encoding/binary"
"log"
"net"
"os"
"syscall"
)
const icmpID uint16 = 43565 // use a magic number for now
type ICMP struct {
Type uint8
Code uint8
Checksum uint16
Identifier uint16
SeqNo uint16
}
func Checksum(data []byte) uint16 {
var (
sum uint32
length int = len(data)
index int
)
for length > 1 {
sum += uint32(data[index])<<8 + uint32(data[index+1])
index += 2
length -= 2
}
if length > 0 {
sum += uint32(data[index])
}
sum += (sum >> 16)
return uint16(^sum)
}
func main() {
h := Header{
Version: 4,
Len: 20,
TotalLen: 20 + 8,
TTL: 1,
Protocol: 1,
}
argc := len(os.Args)
if argc < 2 {
log.Println("usage: program + host")
return
}
ipAddr, _ := net.ResolveIPAddr("ip", os.Args[1])
h.Dst = ipAddr.IP
icmpReq := ICMP{
Type: 8,
Code: 0,
Identifier: icmpID,
SeqNo: 1,
}
out, err := h.Marshal()
if err != nil {
log.Println("ip header error", err)
return
}
var icmpBuf bytes.Buffer
binary.Write(&icmpBuf, binary.BigEndian, icmpReq)
icmpReq.Checksum = Checksum(icmpBuf.Bytes())
icmpBuf.Reset()
binary.Write(&icmpBuf, binary.BigEndian, icmpReq)
fd, _ := syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, syscall.IPPROTO_RAW)
addr := syscall.SockaddrInet4{
Port: 0,
}
copy(addr.Addr[:], ipAddr.IP[12:16])
pkg := append(out, icmpBuf.Bytes()...)
if err := syscall.Sendto(fd, pkg, 0, &addr); err != nil {
log.Println("Sendto err:", err)
}
laddr, err := net.ResolveIPAddr("ip4:icmp", "0.0.0.0")
if err != nil {
log.Fatal(err)
}
c, err := net.ListenIP("ip4:icmp", laddr)
if err != nil {
log.Fatal(err)
}
for {
buf := make([]byte, 2048)
n, raddr, err := c.ReadFrom(buf)
if err != nil {
log.Println(err)
continue
}
icmpType := buf[0]
if icmpType == 11 {
if n == 36 { // Time exceeded messages
// A time exceeded message contain IP header(20 bytes) and first 64 bits of the original payload
id := binary.BigEndian.Uint16(buf[32:34])
log.Println("recv id", id)
if id == icmpID {
log.Println("recv Time Exceeded from", raddr)
}
}
}
}
}
实际上,我正在用go写一个traceroute,如果有人对此感兴趣,整个代码在github中。 .
关于sockets - 原始套接字未收到 icmp 响应,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36169890/
我在使用omniauth/openid时遇到了一些麻烦。在尝试进行身份验证时,我在日志中发现了这一点:OpenID::FetchingError:Errorfetchinghttps://www.google.com/accounts/o8/.well-known/host-meta?hd=profiles.google.com%2Fmy_username:undefinedmethod`io'fornil:NilClass重要的是undefinedmethodio'fornil:NilClass来自openid/fetchers.rb,在下面的代码片段中:moduleNetclass
我是Google云的新手,我正在尝试对其进行首次部署。我的第一个部署是RubyonRails项目。我基本上是在关注thisguideinthegoogleclouddocumentation.唯一的区别是我使用的是我自己的项目,而不是他们提供的“helloworld”项目。这是我的app.yaml文件runtime:customvm:trueentrypoint:bundleexecrackup-p8080-Eproductionconfig.ruresources:cpu:0.5memory_gb:1.3disk_size_gb:10当我转到我的项目目录并运行gcloudprevie
简而言之错误:NOTE:Gem::SourceIndex#add_specisdeprecated,useSpecification.add_spec.Itwillberemovedonorafter2011-11-01.Gem::SourceIndex#add_speccalledfrom/opt/local/lib/ruby/site_ruby/1.8/rubygems/source_index.rb:91./opt/local/lib/ruby/gems/1.8/gems/rails-2.3.8/lib/rails/gem_dependency.rb:275:in`==':und
有人知道在发布新版本的Ruby和Rails时收到电子邮件的方法吗?他们有邮件列表,RubyonRails有一个推特,但我不想听到那些随之而来的喧嚣,我只想知道什么时候发布新版本,尤其是那些有安全修复的版本。 最佳答案 从therailsblog获取提要.http://weblog.rubyonrails.org/feed/atom.xml 关于ruby-on-rails-如何在发布新的Ruby或Rails版本时收到通知?,我们在StackOverflow上找到一个类似的问题:
网络编程套接字网络编程基础知识理解源`IP`地址和目的`IP`地址理解源MAC地址和目的MAC地址认识端口号理解端口号和进程ID理解源端口号和目的端口号认识`TCP`协议认识`UDP`协议网络字节序socket编程接口`sockaddr``UDP`网络程序服务器端代码逻辑:需要用到的接口服务器端代码`udp`客户端代码逻辑`udp`客户端代码`TCP`网络程序服务器代码逻辑多个版本服务器单进程版本多进程版本多线程版本线程池版本服务器端代码客户端代码逻辑客户端代码TCP协议通讯流程TCP协议的客户端/服务器程序流程三次握手(建立连接)数据传输四次挥手(断开连接)TCP和UDP对比网络编程基础知识
在我做的一些网络开发中,我有多个操作开始,比如对外部API的GET请求,我希望它们同时开始,因为一个不依赖另一个的结果。我希望事情能够在后台运行。我找到了concurrent-rubylibrary这似乎运作良好。通过将其混合到您创建的类中,该类的方法具有在后台线程上运行的异步版本。这导致我编写如下代码,其中FirstAsyncWorker和SecondAsyncWorker是我编写的类,我在其中混合了Concurrent::Async模块,并编写了一个名为“work”的方法来发送HTTP请求:defindexop1_result=FirstAsyncWorker.new.async.
s=Socket.new(Socket::AF_INET,Socket::SOCK_STREAM,0)s.connect(Socket.pack_sockaddr_in('port','hostname'))ssl=OpenSSL::SSL::SSLSocket.new(s,sslcert)ssl.connect从这里开始,如果ssl连接和底层套接字仍然是ESTABLISHED,或者它是否在默认值7200之后进入CLOSE_WAIT,我想检查一个线程几秒钟甚至更糟的是在实际上不需要.write()或.read()的情况下关闭。是用select()、IO.select()还是其他方法完成
一段时间以来,我一直在使用open_uri下拉ftp路径作为数据源,但突然发现我几乎连续不断地收到“530抱歉,允许的最大客户端数(95)已经连接。”我不确定我的代码是否有问题,或者是否是其他人在访问服务器,不幸的是,我无法真正确定谁有问题。本质上,我正在读取FTPURI:defself.read_uri(uri)beginuri=open(uri).readuri=="Error"?nil:urirescueOpenURI::HTTPErrornilendend我猜我需要在这里添加一些额外的错误处理代码...我想确保我采取一切预防措施来关闭所有连接,这样我的连接就不是问题所在,但是我
我有一个super简单的脚本,它几乎包含了FayeWebSocketGitHub页面上用于处理关闭连接的内容:ws=Faye::WebSocket::Client.new(url,nil,:headers=>headers)ws.on:opendo|event|p[:open]#sendpingcommand#sendtestcommand#ws.send({command:'test'}.to_json)endws.on:messagedo|event|#hereistheentrypointfordatacomingfromtheserver.pJSON.parse(event.d
这个问题在这里已经有了答案:关闭10年前。PossibleDuplicate:'passparameterbyreference'inRuby?在这个例子中:deftestverb='nothing'yieldverbputsverbendtest{|verb|verb='something'}它将打印“无”。是否可以将其更改为“某物”?谢谢