ethr/plt_darwin.go
Pankaj Garg 945d59c33b
Add support for throttling in Bandwidth tests, ToS and improved external mode. (#135)
* Intermediate checkin

* Last check-in before deleting ACK message in Ethr.

* Support for client port, throttling and tos almost working.

* Most functionality working as expected with code all cleaned up.

* Linux/OSX Fixes.

* Fix handshake mechanism.

* Minor cleanup.

* More improvements for external mode.

* Improve admin-mode, root user permission checking.

* Improve detection of IP version for ICMP.

* Update README.md
2020-11-30 18:20:57 -08:00

403 lines
13 KiB
Go

// +build darwin
//-----------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license.
// See LICENSE.txt file in the project root for full license information.
//-----------------------------------------------------------------------------
package main
import (
"bytes"
"encoding/binary"
"net"
"syscall"
tm "github.com/nsf/termbox-go"
"golang.org/x/sys/unix"
)
func getNetDevStats(stats *ethrNetStat) {
ifs, err := net.Interfaces()
if err != nil {
ui.printErr("%v", err)
return
}
for _, iface := range ifs {
if iface.Flags&net.FlagUp == 0 {
continue
}
ifaceData, err := getIfaceData(iface.Index)
if err != nil {
ui.printErr("Failed to load data for interface %q: %v", iface.Name, err)
continue
}
stats.netDevStats = append(stats.netDevStats, ethrNetDevStat{
interfaceName: iface.Name,
rxBytes: ifaceData.Data.Ibytes,
rxPkts: ifaceData.Data.Ipackets,
txBytes: ifaceData.Data.Obytes,
txPkts: ifaceData.Data.Opackets,
})
}
}
func getTCPStats(stats *ethrNetStat) {
var data tcpStat
rawData, err := unix.SysctlRaw("net.inet.tcp.stats")
if err != nil {
// return EthrTCPStat{}, errors.Wrap(err, "GetTCPStats: could not get net.inet.tcp.stats")
return
}
buf := bytes.NewReader(rawData)
binary.Read(buf, binary.LittleEndian, &data)
// return EthrTCPStat{uint64(data.Sndrexmitpack)}, nil
// return the TCP Retransmits
stats.tcpStats.segRetrans = uint64(data.Sndrexmitpack)
return
}
func hideCursor() {
tm.SetCursor(0, 0)
}
func blockWindowResize() {
}
func getIfaceData(index int) (*ifMsghdr2, error) {
var data ifMsghdr2
rawData, err := unix.SysctlRaw("net", unix.AF_ROUTE, 0, 0, unix.NET_RT_IFLIST2, index)
if err != nil {
return nil, err
}
err = binary.Read(bytes.NewReader(rawData), binary.LittleEndian, &data)
return &data, err
}
type ifMsghdr2 struct {
Msglen uint16
Version uint8
Type uint8
Addrs int32
Flags int32
Index uint16
_ [2]byte
SndLen int32
SndMaxlen int32
SndDrops int32
Timer int32
Data ifData64
}
type ifData64 struct {
Type uint8
Typelen uint8
Physical uint8
Addrlen uint8
Hdrlen uint8
Recvquota uint8
Xmitquota uint8
Unused1 uint8
Mtu uint32
Metric uint32
Baudrate uint64
Ipackets uint64
Ierrors uint64
Opackets uint64
Oerrors uint64
Collisions uint64
Ibytes uint64
Obytes uint64
Imcasts uint64
Omcasts uint64
Iqdrops uint64
Noproto uint64
Recvtiming uint32
Xmittiming uint32
Lastchange unix.Timeval32
}
type tcpStat struct {
Connattempt uint32
Accepts uint32
Connects uint32
Drops uint32
Conndrops uint32
Closed uint32
Segstimed uint32
Rttupdated uint32
Delack uint32
Timeoutdrop uint32
Rexmttimeo uint32
Persisttimeo uint32
Keeptimeo uint32
Keepprobe uint32
Keepdrops uint32
Sndtotal uint32
Sndpack uint32
Sndbyte uint32
Sndrexmitpack uint32
Sndrexmitbyte uint32
Sndacks uint32
Sndprobe uint32
Sndurg uint32
Sndwinup uint32
Sndctrl uint32
Rcvtotal uint32
Rcvpack uint32
Rcvbyte uint32
Rcvbadsum uint32
Rcvbadoff uint32
Rcvmemdrop uint32
Rcvshort uint32
Rcvduppack uint32
Rcvdupbyte uint32
Rcvpartduppack uint32
Rcvpartdupbyte uint32
Rcvoopack uint32
Rcvoobyte uint32
Rcvpackafterwin uint32
Rcvbyteafterwin uint32
Rcvafterclose uint32
Rcvwinprobe uint32
Rcvdupack uint32
Rcvacktoomuch uint32
Rcvackpack uint32
Rcvackbyte uint32
Rcvwinupd uint32
Pawsdrop uint32
Predack uint32
Preddat uint32
Pcbcachemiss uint32
Cachedrtt uint32
Cachedrttvar uint32
Cachedssthresh uint32
Usedrtt uint32
Usedrttvar uint32
Usedssthresh uint32
Persistdrop uint32
Badsyn uint32
Mturesent uint32
Listendrop uint32
Minmssdrops uint32
Sndrexmitbad uint32
Badrst uint32
Sc_added uint32
Sc_retransmitted uint32
Sc_dupsyn uint32
Sc_dropped uint32
Sc_completed uint32
Sc_bucketoverflow uint32
Sc_cacheoverflow uint32
Sc_reset uint32
Sc_stale uint32
Sc_aborted uint32
Sc_badack uint32
Sc_unreach uint32
Sc_zonefail uint32
Sc_sendcookie uint32
Sc_recvcookie uint32
Hc_added uint32
Hc_bucketoverflow uint32
Sack_recovery_episode uint32
Sack_rexmits uint32
Sack_rexmit_bytes uint32
Sack_rcv_blocks uint32
Sack_send_blocks uint32
Sack_sboverflow uint32
Bg_rcvtotal uint32
Rxtfindrop uint32
Fcholdpacket uint32
Coalesced_pack uint32
Flowtbl_full uint32
Flowtbl_collision uint32
Lro_twopack uint32
Lro_multpack uint32
Lro_largepack uint32
Limited_txt uint32
Early_rexmt uint32
Sack_ackadv uint32
Rcv_swcsum uint32
Rcv_swcsum_bytes uint32
Rcv6_swcsum uint32
Rcv6_swcsum_bytes uint32
Snd_swcsum uint32
Snd_swcsum_bytes uint32
Snd6_swcsum uint32
Snd6_swcsum_bytes uint32
Msg_unopkts uint32
Msg_unoappendfail uint32
Msg_sndwaithipri uint32
Invalid_mpcap uint32
Invalid_joins uint32
Mpcap_fallback uint32
Join_fallback uint32
Estab_fallback uint32
Invalid_opt uint32
Mp_outofwin uint32
Mp_reducedwin uint32
Mp_badcsum uint32
Mp_oodata uint32
Mp_switches uint32
Mp_rcvtotal uint32
Mp_rcvbytes uint32
Mp_sndpacks uint32
Mp_sndbytes uint32
Join_rxmts uint32
Tailloss_rto uint32
Reordered_pkts uint32
Recovered_pkts uint32
Pto uint32
Rto_after_pto uint32
Tlp_recovery uint32
Tlp_recoverlastpkt uint32
Ecn_client_success uint32
Ecn_recv_ece uint32
Ecn_sent_ece uint32
Detect_reordering uint32
Delay_recovery uint32
Avoid_rxmt uint32
Unnecessary_rxmt uint32
Nostretchack uint32
Rescue_rxmt uint32
Pto_in_recovery uint32
Pmtudbh_reverted uint32
Dsack_disable uint32
Dsack_ackloss uint32
Dsack_badrexmt uint32
Dsack_sent uint32
Dsack_recvd uint32
Dsack_recvd_old uint32
Mp_sel_symtomsd uint32
Mp_sel_rtt uint32
Mp_sel_rto uint32
Mp_sel_peer uint32
Mp_num_probes uint32
Mp_verdowngrade uint32
Drop_after_sleep uint32
Probe_if uint32
Probe_if_conflict uint32
Ecn_client_setup uint32
Ecn_server_setup uint32
Ecn_server_success uint32
Ecn_lost_synack uint32
Ecn_lost_syn uint32
Ecn_not_supported uint32
Ecn_recv_ce uint32
Ecn_conn_recv_ce uint32
Ecn_conn_recv_ece uint32
Ecn_conn_plnoce uint32
Ecn_conn_pl_ce uint32
Ecn_conn_nopl_ce uint32
Ecn_fallback_synloss uint32
Ecn_fallback_reorder uint32
Ecn_fallback_ce uint32
Tfo_syn_data_rcv uint32
Tfo_cookie_req_rcv uint32
Tfo_cookie_sent uint32
Tfo_cookie_invalid uint32
Tfo_cookie_req uint32
Tfo_cookie_rcv uint32
Tfo_syn_data_sent uint32
Tfo_syn_data_acked uint32
Tfo_syn_loss uint32
Tfo_blackhole uint32
Tfo_cookie_wrong uint32
Tfo_no_cookie_rcv uint32
Tfo_heuristics_disable uint32
Tfo_sndblackhole uint32
Mss_to_default uint32
Mss_to_medium uint32
Mss_to_low uint32
Ecn_fallback_droprst uint32
Ecn_fallback_droprxmt uint32
Ecn_fallback_synrst uint32
Mptcp_rcvmemdrop uint32
Mptcp_rcvduppack uint32
Mptcp_rcvpackafterwin uint32
Timer_drift_le_1_ms uint32
Timer_drift_le_10_ms uint32
Timer_drift_le_20_ms uint32
Timer_drift_le_50_ms uint32
Timer_drift_le_100_ms uint32
Timer_drift_le_200_ms uint32
Timer_drift_le_500_ms uint32
Timer_drift_le_1000_ms uint32
Timer_drift_gt_1000_ms uint32
Mptcp_handover_attempt uint32
Mptcp_interactive_attempt uint32
Mptcp_aggregate_attempt uint32
Mptcp_fp_handover_attempt uint32
Mptcp_fp_interactive_attempt uint32
Mptcp_fp_aggregate_attempt uint32
Mptcp_heuristic_fallback uint32
Mptcp_fp_heuristic_fallback uint32
Mptcp_handover_success_wifi uint32
Mptcp_handover_success_cell uint32
Mptcp_interactive_success uint32
Mptcp_aggregate_success uint32
Mptcp_fp_handover_success_wifi uint32
Mptcp_fp_handover_success_cell uint32
Mptcp_fp_interactive_success uint32
Mptcp_fp_aggregate_success uint32
Mptcp_handover_cell_from_wifi uint32
Mptcp_handover_wifi_from_cell uint32
Mptcp_interactive_cell_from_wifi uint32
_ [4]byte
Mptcp_handover_cell_bytes uint64
Mptcp_interactive_cell_bytes uint64
Mptcp_aggregate_cell_bytes uint64
Mptcp_handover_all_bytes uint64
Mptcp_interactive_all_bytes uint64
Mptcp_aggregate_all_bytes uint64
Mptcp_back_to_wifi uint32
Mptcp_wifi_proxy uint32
Mptcp_cell_proxy uint32
_ [4]byte
}
func setSockOptInt(fd uintptr, level, opt, val int) (err error) {
err = syscall.SetsockoptInt(int(fd), level, opt, val)
if err != nil {
ui.printErr("Failed to set socket option (%v) to value (%v) during Dial. Error: %s", opt, val, err)
}
return
}
func IcmpNewConn(address string) (net.PacketConn, error) {
dialedConn, err := net.Dial(Icmp(), address)
if err != nil {
return nil, err
}
localAddr := dialedConn.LocalAddr()
dialedConn.Close()
conn, err := net.ListenPacket(Icmp(), localAddr.String())
if err != nil {
return nil, err
}
return conn, nil
}
func VerifyPermissionForTest(testID EthrTestID) {
if testID.Protocol == ICMP || (testID.Protocol == TCP &&
(testID.Type == TraceRoute || testID.Type == MyTraceRoute)) {
if !IsAdmin() {
ui.printMsg("Warning: You are not running as administrator. For %s based %s",
protoToString(testID.Protocol), testToString(testID.Type))
ui.printMsg("test, running as administrator is required.\n")
}
}
}
func IsAdmin() bool {
return true
}
func SetTClass(fd uintptr, tos int) {
setSockOptInt(fd, syscall.IPPROTO_IPV6, syscall.IPV6_TCLASS, tos)
}