Как установить опцию сокета IP_DONTFRAG в python?
Как я могу установить флаг DONT_FRAGMENT в заголовке IP с помощью сокетов Python?
Следующий код
socket.setsockopt(socket.IPPROTO_IP, socket.IP_DONTFRAG, 1)
дает мне эту ошибку:
AttributeError: 'module' object has no attribute 'IP_DONTFRAG'
У кого-нибудь есть идея?
2 ответа
def create_sender_session(self):
logging.debug("Create Sender Session")
if (self.send_ip_ver == 6 or self.resp_ip_ver == 6):
self.sender_socket = socket.socket(
socket.AF_INET6, socket.SOCK_DGRAM)
self.sender_socket.setsockopt(
socket.IPPROTO_IPV6, socket.IPV6_TCLASS, self.tos)
self.sender_socket.setsockopt(
socket.IPPROTO_IPV6, socket.IPV6_UNICAST_HOPS, self.ttl)
else:
self.sender_socket = socket.socket(
socket.AF_INET, socket.SOCK_DGRAM)
self.sender_socket.setsockopt(
socket.SOL_IP, socket.IP_TTL, self.ttl)
self.sender_socket.setsockopt(
socket.IPPROTO_IP, socket.IP_TOS, self.tos)
self.sender_socket.setsockopt(
socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.sender_socket.bind((self.send_addr, self.send_port))
logging.info('Sender started: {}:{}'.format(
self.send_addr, self.send_port))
Документацию по некоторым параметрам сокета найти сложнее, чем по другим. *DONTFRAG , похоже, относится ко второй категории.
Некоторые ссылки:
[FreeBSD]: IP(4) (курсив мой):
IP_DONTFRAG может использоваться для установки флага «Не фрагментировать» пакеты IP. В настоящее время этот параметр используется только для сокетов udp(4) и raw ip(4) , если не установлен параметр IP_HDRINCL. В сокетах tcp(4) флаг «Не фрагментировать» управляется параметром Path MTU Discovery . Отправка пакета, превышающего размер MTU выходного интерфейса, определяемый адресом назначения, возвращает ошибку EMSGSIZE.
(qaic-env) [cfati@cfati-5510-0:/mnt/e/Work/Dev/StackOverflow/q049051558]> ~/sopr.sh
### Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ###
[064bit prompt]> uname -a
Linux cfati-5510-0 5.10.60.1-microsoft-standard-WSL2 #1 SMP Wed Aug 25 23:20:18 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
[064bit prompt]> head -n 2 /etc/os-release
NAME="Ubuntu"
VERSION="20.04.4 LTS (Focal Fossa)"
[064bit prompt]>
[064bit prompt]> python2 -c "import socket;print([e for e in dir(socket) if \"DONTFRAG\" in e])"
['IPV6_DONTFRAG']
В качестве примечания, Python 2 больше не поддерживается ( EndOfLife ), хотя на момент задания вопроса он все еще был, поэтому перейдем на Python 3 .
[064bit prompt]> python -c "import socket;print([e for e in dir(socket) if \"DONTFRAG\" in e])"
['IPV6_DONTFRAG']
[Python.Docs]: сокет — низкоуровневый сетевой интерфейс их не упоминает. Однако существует только IPV6_DONTFRAG .
И это не относится к Python .
[064bit prompt]> python -c "import socket, sys;print(\"{:s}\n{:s}\n{:d}\n\".format(sys.version, sys.platform, socket.IPV6_DONTFRAG))"
3.8.10 (default, Nov 26 2021, 20:14:08)
[GCC 9.3.0]
linux
62
[064bit prompt]> grep -r DONTFRAG /usr/include
/usr/include/linux/in6.h:#define IPV6_DONTFRAG 62
/usr/include/x86_64-linux-gnu/bits/in.h:#define IPV6_DONTFRAG 62
Как следует из имени IPV6_DONTFRAG , оно предназначено для сокетов IPv6 (и, скорее всего, не будет работать для IPv4):
[064bit prompt]> python
Python 3.8.10 (default, Nov 26 2021, 20:14:08)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> import socket
>>>
>>> s6d = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
>>> s6d.getsockopt(socket.IPPROTO_IPV6, socket.IPV6_DONTFRAG)
0
>>> s6d.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_DONTFRAG, 1)
>>> s6d.getsockopt(socket.IPPROTO_IPV6, socket.IPV6_DONTFRAG)
1
>>> s6d.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_DONTFRAG, 2)
>>> s6d.getsockopt(socket.IPPROTO_IPV6, socket.IPV6_DONTFRAG)
1
>>> s6d.close()
>>>
>>> s6s = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
>>> s6s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_DONTFRAG, 1)
>>> s6s.close()
>>>
>>> s4d = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
>>> s4d.getsockopt(socket.IPPROTO_IPV6, socket.IPV6_DONTFRAG)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OSError: [Errno 95] Operation not supported
>>> s4d.getsockopt(socket.IPPROTO_IP, socket.IPV6_DONTFRAG)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OSError: [Errno 92] Protocol not available
>>>
>>> s4d.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_DONTFRAG, 1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OSError: [Errno 92] Protocol not available
>>> s4d.setsockopt(socket.IPPROTO_IP, socket.IPV6_DONTFRAG, 1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OSError: [Errno 92] Protocol not available
>>> s4d.close()
Итак, для сокетов IPv6 он не вызвал исключения (требуются тесты, чтобы установить, делал ли он под капотом то, что должен).
Для IPv4 можно попробовать параметр Path MTU Discovery ( [ SO ]: Path MTU Discovery с использованием параметра Socket — IP_MTU и IP_MTU_DISCOVER ).
Не знаю, насколько это актуально, но, похоже, работает на Win:
[cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q049051558]> "e:\Work\Dev\VEnvs\py_pc064_03.09_test0\Scripts\python.exe"
Python 3.9.9 (tags/v3.9.9:ccb0e6a, Nov 15 2021, 18:08:50) [MSC v.1929 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> import socket
>>>
>>> s4d = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
>>> s4d.getsockopt(socket.IPPROTO_IP, socket.IPV6_DONTFRAG), s4d.getsockopt(socket.IPPROTO_IPV6, socket.IPV6_DONTFRAG)
(0, 0)
>>> s4d.setsockopt(socket.IPPROTO_IP, socket.IPV6_DONTFRAG, 1)
>>> s4d.getsockopt(socket.IPPROTO_IP, socket.IPV6_DONTFRAG), s4d.getsockopt(socket.IPPROTO_IPV6, socket.IPV6_DONTFRAG)
(1, 1)
>>> s4d.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_DONTFRAG, 1)
>>> s4d.getsockopt(socket.IPPROTO_IP, socket.IPV6_DONTFRAG), s4d.getsockopt(socket.IPPROTO_IPV6, socket.IPV6_DONTFRAG)
(1, 1)
>>> s4d.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_DONTFRAG, 0)
>>> s4d.getsockopt(socket.IPPROTO_IP, socket.IPV6_DONTFRAG), s4d.getsockopt(socket.IPPROTO_IPV6, socket.IPV6_DONTFRAG)
(0, 0)
>>> s4d.close()
>>>
>>> s4s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>>> s4s.getsockopt(socket.IPPROTO_IP, socket.IPV6_DONTFRAG), s4s.getsockopt(socket.IPPROTO_IPV6, socket.IPV6_DONTFRAG)
(1, 1)
>>> s4s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_DONTFRAG, 0)
>>> s4s.getsockopt(socket.IPPROTO_IP, socket.IPV6_DONTFRAG), s4s.getsockopt(socket.IPPROTO_IPV6, socket.IPV6_DONTFRAG)
(0, 0)
>>> s4s.close()