1 | 1 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,15 @@ |
1 |
+# so_priority.so |
|
2 |
+ |
|
3 |
+Set `SO_PRIORITY` (aka `skb->priority` on Linux) right after each `socket()` call. |
|
4 |
+ |
|
5 |
+Compile with: |
|
6 |
+ |
|
7 |
+``` |
|
8 |
+gcc -shared -ldl -fPIC so_priority.c -o so_priority.so |
|
9 |
+``` |
|
10 |
+ |
|
11 |
+Usage: |
|
12 |
+ |
|
13 |
+``` |
|
14 |
+SO_PRIORITY_DEBUG=1 SO_PRIORITY_VALUE=6 LD_PRELOAD=/path/to/so_priority.so program arg1 arg2 |
|
15 |
+``` |
0 | 16 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,100 @@ |
1 |
+/* |
|
2 |
+ Set SO_PRIORITY right after each socket() call. |
|
3 |
+ Compile with: gcc -shared -ldl -fPIC so_priority.c -o so_priority.so |
|
4 |
+ Usage: SO_PRIORITY_DEBUG=1 SO_PRIORITY_VALUE=6 LD_PRELOAD=/path/to/so_priority.so program arg1 arg2 |
|
5 |
+ |
|
6 |
+ (c) 2020 - Xavier Guerrin |
|
7 |
+ This program is free software. It comes without any warranty, to |
|
8 |
+ the extent permitted by applicable law. You can redistribute it |
|
9 |
+ and/or modify it under the terms of the Do What The Fuck You Want |
|
10 |
+ To Public License, Version 2, as published by Sam Hocevar. See |
|
11 |
+ http://www.wtfpl.net/ for more details. |
|
12 |
+*/ |
|
13 |
+ |
|
14 |
+#define _GNU_SOURCE /* RTLD_NEXT */ |
|
15 |
+#include <dlfcn.h> /* dlsym, dlerror */ |
|
16 |
+#include <errno.h> /* errno */ |
|
17 |
+#include <stdio.h> /* dprintf */ |
|
18 |
+#include <stdlib.h> /* atoi, getenv */ |
|
19 |
+#include <string.h> /* strerror */ |
|
20 |
+#include <sys/types.h> /* setsockopt */ |
|
21 |
+#include <sys/socket.h> /* setsockopt */ |
|
22 |
+ |
|
23 |
+#ifndef SOPRIORITY_SO_NAME |
|
24 |
+#define SOPRIORITY_SO_NAME "so_priority.so" |
|
25 |
+#endif |
|
26 |
+#ifndef SOPRIORITY_VALUE_EV |
|
27 |
+#define SOPRIORITY_VALUE_EV "SO_PRIORITY_VALUE" |
|
28 |
+#endif |
|
29 |
+#ifndef SOPRIORITY_DEBUG_EV |
|
30 |
+#define SOPRIORITY_DEBUG_EV "SO_PRIORITY_DEBUG" |
|
31 |
+#endif |
|
32 |
+ |
|
33 |
+typedef int (*socket_function_type)(int, int, int); |
|
34 |
+ |
|
35 |
+/* Pointer to the actual scoket symbol. */ |
|
36 |
+socket_function_type so_priority_socket = NULL; |
|
37 |
+ |
|
38 |
+/* SO_PRIORITY value to set; can be configured using the SO_PRIORITY_VALUE environment variable. */ |
|
39 |
+int so_priority_value = 0; |
|
40 |
+/* Debug level; can be configured using the SO_PRIORITY_DEBUG environment variable. */ |
|
41 |
+int so_priority_debug = 0; |
|
42 |
+int so_priority_known = 0; |
|
43 |
+ |
|
44 |
+/* Ask the linker to provide the actual "socket" symbol: */ |
|
45 |
+static int so_priority_get_socket() { |
|
46 |
+ char *error_string; |
|
47 |
+ so_priority_socket = (socket_function_type)dlsym(RTLD_NEXT, "socket"); |
|
48 |
+ if (!so_priority_socket) { |
|
49 |
+ error_string = dlerror(); |
|
50 |
+ if (error_string) { |
|
51 |
+ dprintf(2, "%s: unable to find the actual socket symbol: %s\n", SOPRIORITY_SO_NAME, error_string); |
|
52 |
+ } |
|
53 |
+ else { |
|
54 |
+ dprintf(2, "%s: unable to find the actual socket symbol\n", SOPRIORITY_SO_NAME); |
|
55 |
+ } |
|
56 |
+ return 0; |
|
57 |
+ } |
|
58 |
+ return 1; |
|
59 |
+} |
|
60 |
+ |
|
61 |
+/* Read the priority value from the environment. */ |
|
62 |
+static void so_priority_set_options() { |
|
63 |
+ char *str; |
|
64 |
+ str = getenv(SOPRIORITY_VALUE_EV); |
|
65 |
+ if (str) so_priority_value = atoi(str); |
|
66 |
+ str = getenv(SOPRIORITY_DEBUG_EV); |
|
67 |
+ if (str) so_priority_debug = atoi(str); |
|
68 |
+ so_priority_known = 1; |
|
69 |
+} |
|
70 |
+ |
|
71 |
+/* Wrapper around the actual socket() function that sets SO_PRIORITY by calling setsockopt(). */ |
|
72 |
+int socket(int domain, int type, int protocol) { |
|
73 |
+ int ret, setsockopt_errno, socket_errno, sockfd; |
|
74 |
+ |
|
75 |
+ if (!so_priority_socket && !so_priority_get_socket()) { |
|
76 |
+ errno = ENOENT; |
|
77 |
+ return -1; |
|
78 |
+ } |
|
79 |
+ /* Actually call socket(): */ |
|
80 |
+ sockfd = so_priority_socket(domain, type, protocol); |
|
81 |
+ /* Do not call setsockopt() if socket() failed: */ |
|
82 |
+ if (sockfd < 0) return sockfd; |
|
83 |
+ |
|
84 |
+ /* Time for the actual work: */ |
|
85 |
+ socket_errno = errno; |
|
86 |
+ |
|
87 |
+ if (!so_priority_known) so_priority_set_options(); |
|
88 |
+ ret = setsockopt(sockfd, SOL_SOCKET, SO_PRIORITY, &so_priority_value, sizeof(so_priority_value)); |
|
89 |
+ /* Ignore setsockopt() errors, except for debugging purposes. */ |
|
90 |
+ if (so_priority_debug) { |
|
91 |
+ setsockopt_errno = errno; |
|
92 |
+ dprintf(2, "%s: setsockopt(%d, SOL_SOCKET, SO_PRIORITY, %d, %zu) returned %d", |
|
93 |
+ SOPRIORITY_SO_NAME, sockfd, so_priority_value, sizeof(so_priority_value), ret); |
|
94 |
+ if (ret < 0) dprintf(2, "; errno is %d: %s", setsockopt_errno, strerror(setsockopt_errno)); |
|
95 |
+ dprintf(2, "\n"); |
|
96 |
+ } |
|
97 |
+ |
|
98 |
+ errno = socket_errno; |
|
99 |
+ return sockfd; |
|
100 |
+} |