Полное название tcp — это протокол управления передачей.Протокол tcp добавляет механизм обеспечения целостности передачи, такой как проверка целостности пакетов на основе протокола ip, что делает его широко используемым в текущей области данных.
Выполните следующие шаги, чтобы быстро понять информацию, содержащуюся в пакете tcp.
Интерпретация документа rfc протокола tcp
ссылка на рфк:tools.ietf.org/html/rfc793
Базовая структура пакета tcp выглядит следующим образом.
Видно, что пакет TCP состоит из более чем десяти полей.Последнее поле данных представляет данные, переносимые пакетом данных TCP.Эти данные обычно являются данными прикладного уровня.Например,данные пакета http представляют собой данные в этом tcp пакете в полеОбычно используемые поля следующие:
поле | эффект |
---|---|
Source Port | Номер порта отправляющей машины |
Destination Port | Номер порта принимающей машины |
Sequence Number | номер пакета |
Acknowledgment Number | Подтвердить номер пакета |
urg/ack/psh/rst/syn/fin | Бит флага, установка флага операции да/нет |
Window | Окно управления потоком |
Checksum | Проверка целостности пакетов |
Примечание. Клиент и сервер используют отдельные счетчики количества пакетов. Контрольная сумма сервера и клиента будет рассчитываться отдельно, и клиент будет полагаться на это значение, чтобы определить, был ли пакет tcp ненормально изменен/подделан в процессе передачи.
Получить пакеты дел
Вы можете использовать wireshark для получения tcp-пакета, щелкните правой кнопкой мыши на tcp-слое -> скопировать -> как шестнадцатеричный поток
Данные пакета уровня tcp, полученные здесь, выглядят следующим образом.
1f90f04f3747d146dcae23f3801831bf14ef00000101080a3176450b31764503
Теперь вы можете написать программу для разбора конкретных данных сообщения из шестнадцатеричной части этого tcp.
Разбирать пакеты данных tcp
Отношение преобразования между двоичными цифрами и шестнадцатеричными цифрами: 1 шестнадцатеричное число может представлять 4 двоичных цифры Например, двоичное: 00011111 10010000 может быть выражено в шестнадцатеричном виде как: 1f90
Вы можете использовать следующий код для преобразования шестнадцатеричной строки в двоичную.
func hex2bin(hex string) string {
var bin string
for i := 0; i < len(hex); i++ {
hex2int, _ := strconv.ParseInt(string(hex[i]), 16, 64)
bin = bin + fmt.Sprintf("%04b", hex2int)
}
return bin
}
Затем вы можете прочитать информацию о дейтаграмме tcp в двоичных битах, справочный код выглядит следующим образом.
func main() {
atcp := "1f90f04f3747d146dcae23f3801831bf14ef00000101080a3176450b31764503"
bintcp := hex2bin(atcp)
sourcePort, _ := strconv.ParseInt(bintcp[0:16], 2, 64)
fmt.Printf("sourcePort is %d \n", sourcePort)
destinationPort, _ := strconv.ParseInt(bintcp[16:32], 2, 64)
fmt.Printf("destinationPort is %d \n", destinationPort)
sequenceNumber, _ := strconv.ParseInt(bintcp[32:64], 2, 64)
fmt.Printf("sequenceNumber is %d \n", sequenceNumber)
acknowledgmentNumber, _ := strconv.ParseInt(bintcp[64:96], 2, 64)
fmt.Printf("acknowledgmentNumber is %d \n", acknowledgmentNumber)
dataOffset, _ := strconv.ParseInt(bintcp[96:100], 2, 64)
fmt.Printf("dataOffset is %d \n", dataOffset)
reserved, _ := strconv.ParseInt(bintcp[100:106], 2, 64)
fmt.Printf("reserved is %d \n", reserved)
// Control Bits 控制位,从106-1012共有6位,每位表示一个控制位的开关
urg, _ := strconv.ParseInt(bintcp[106:107], 2, 64)
ack, _ := strconv.ParseInt(bintcp[107:108], 2, 64)
psh, _ := strconv.ParseInt(bintcp[108:109], 2, 64)
rst, _ := strconv.ParseInt(bintcp[109:110], 2, 64)
syn, _ := strconv.ParseInt(bintcp[110:111], 2, 64)
fin, _ := strconv.ParseInt(bintcp[111:112], 2, 64)
fmt.Printf("控制位标识如下:\n")
fmt.Printf(" urg: %d\n", urg)
fmt.Printf(" ack: %d\n", ack)
fmt.Printf(" psh: %d\n", psh)
fmt.Printf(" rst: %d\n", rst)
fmt.Printf(" syn: %d\n", syn)
fmt.Printf(" fin: %d\n", fin)
// 数据窗口 16位
window, _ := strconv.ParseInt(bintcp[112:128], 2, 64)
fmt.Printf("window is %d \n", window)
// checksum 16位
checksum, _ := strconv.ParseInt(bintcp[128:144], 2, 64)
fmt.Printf("checksum is %d \n", checksum)
// urgentPointer
urgentPointer, _ := strconv.ParseInt(bintcp[144:160], 2, 64)
fmt.Printf("urgentPointer is %d \n", urgentPointer)
// options and padding
optionsAndPaddings := bintcp[160:]
fmt.Printf("optionsAndPaddings is %s \n", optionsAndPaddings)
fmt.Printf("tcp raw data is %s \n", atcp)
fmt.Printf("tcp bin data is %s \n", bintcp)
fmt.Printf("tcp bin data length is %d\n", len(bintcp))
}
Эффект от исполнения следующий
Результаты парсинга Wireshark следующие
Вы можете видеть, что анализ в порядке
некоторые замечания
Данные tcp-пакета, скопированные в wireshark, представлены в шестнадцатеричном формате, но в протоколе tcp некоторые поля занимают только один бит, а шестнадцатеричный формат — это целое число, кратное 4 в двоичном формате. Поле невозможно получить, и его необходимо преобразовать в двоичный формат для обработки.
Данные пакета tcp в конечном итоге будут выровнены по 32 битам.Если весь размер пакета tcp не является целым числом, кратным 32-битной длине, он будет дополнен 0 в конце до 32-битного целого числа.
Протокол tcp добавил флаги cwr и ece в rfc3168, вы можете обратиться к:tools.I ETF.org/HTML/RFC316…
Вы можете использовать tcpdump для захвата пакетов: tcpdump -n -XX -i lo0 -s0 'tcp port 8080'