List of commits:
Subject Hash Author Date (UTC)
Added support for connecting clients (socket -> connect or socket -> sendto). 8f94255890a99d4890206e53f031ffad79c55866 Catalin(ux) M. BOIE 2011-08-05 21:15:38
Bump version to 0.7. 1a51b690a50c482c9e727b3e8e129bbc2890f600 Catalin(ux) M. BOIE 2011-06-21 17:06:25
Corrected description and license. 708b98d98bb5704f3bd265928f07cc94c18bd212 Catalin(ux) M. BOIE 2011-06-21 17:06:04
Bump version to 0.6. cb4ef5c142753802f9dcd2410d094f9914e8273c Catalin(ux) M. BOIE 2011-06-21 16:56:15
Added support for separate FORCE_ADDR for IPv4 and IPv6, MSS, TTL etc. e32e97cafe360f192283168d76c327559282e24d Catalin(ux) M. BOIE 2011-06-21 16:55:12
Added TODO to %doc rpm section. 086dbb2e078955dddf83cbfd65998334d6db81e4 Catalin(ux) M. BOIE 2010-12-19 19:46:20
Added MSS. 9a5c3676567cb92e6c0b4106c2b97cd2da2273a5 Catalin(ux) M. BOIE 2010-12-14 17:00:37
Added TOS test script. a4b1b05b27b3eaa06a4a71f656e1b80731d1b8ff Catalin(ux) M. BOIE 2010-12-14 16:55:03
Ignore Changelog-last file. 1bfa5decd11f4fd95e4b002d88e2a2e04c747855 Catalin(ux) M. BOIE 2010-12-14 16:54:36
Added KA. ec9b4556e51ca9a807400910f8ca6d698f9ad670 Catalin(ux) M. BOIE 2010-12-14 16:53:58
Bump up the version to 0.5. f7ba7f0feb49ac4942d85903d31e085f1ffa6149 Catalin(ux) M. BOIE 2010-11-07 23:16:25
Duilder updates. 4d3691f340591f68f9b0ae704da24b4352957f05 Catalin(ux) M. BOIE 2010-11-07 23:15:29
Added support to force TOS by using env var FORCE_NET_TOS. 319cfbee315a0c6889791b122fdb8069aa2ffdf1 Catalin(ux) M. BOIE 2010-11-07 23:14:23
No need for duilder_release. I will use a global one. 15a59294aa3922e58bff8aaa9de7cc06dc44fe1e Catalin(ux) M. BOIE 2010-10-27 20:43:15
TODO in. 9ea8407b8a2767debcf7597bbfc1bddfe44c78eb Catalin(ux) M. BOIE 2010-10-27 20:21:13
Typo. 2282d895e91cf2b02a7b67d933af2c68db5798b6 Catalin(ux) M. BOIE 2010-10-27 19:54:40
Aded license information to README file. fe8071fd2d9f912136fb7fa22f289ddc63cf0f14 Catalin(ux) M. BOIE 2010-10-27 19:46:48
Improved description. 1f17958175bf3f2a656a365fdafca21118737cf1 Catalin(ux) M. BOIE 2010-10-27 19:43:33
Silence compiler useless warning. 117e169b70197ac7e62907f855eb475a0a43fe07 Catalin(ux) M. BOIE 2010-10-27 19:24:45
Bump up the version to 0.4. 59371ee292d38d489719f105a9ff16c923be09d0 Catalin(ux) M. BOIE 2010-10-27 19:16:53
Commit 8f94255890a99d4890206e53f031ffad79c55866 - Added support for connecting clients (socket -> connect or socket -> sendto).
Author: Catalin(ux) M. BOIE
Author date (UTC): 2011-08-05 21:15
Committer name: Catalin(ux) M. BOIE
Committer date (UTC): 2011-08-06 21:07
Parent(s): 1a51b690a50c482c9e727b3e8e129bbc2890f600
Signing key:
Tree: a7604d58cdd9eb38f2eeb846d01b79058b177411
File Lines added Lines deleted
Makefile.in 4 1
README 8 0
force_bind.c 76 30
send_udp.c 12 1
test_client.c 29 15
test_client1.sh 2 4
test_udp_local_bind.sh 13 0
File Makefile.in changed (mode: 100644) (index ce93d8a..ab558a1)
... ... test_bind: test_bind.c
16 16 send_udp: send_udp.c send_udp: send_udp.c
17 17 $(CC) $(CFLAGS) $< -o $@ $(CC) $(CFLAGS) $< -o $@
18 18
19 test_client: test_client.c
20 $(CC) $(CFLAGS) $< -o $@
21
19 22 .PHONY: clean .PHONY: clean
20 23 clean: clean:
21 @rm -f force_bind.so.* test_bind *.a *.o *.so* $(PRJ)-*.rpm $(PRJ)-*-*-*.tgz $(PRJ)-*.tar.gz *.strace
24 @rm -f force_bind.so.* test_bind send_udp test_client *.a *.o *.so* $(PRJ)-*.rpm $(PRJ)-*-*-*.tgz $(PRJ)-*.tar.gz *.strace
22 25
23 26 install: all install: all
24 27 @mkdir -p $(I_USR_LIB) @mkdir -p $(I_USR_LIB)
File README changed (mode: 100644) (index 08bf90a..f0a83e3)
... ... Examples:
68 68 export LD_PRELOAD=${LD_PRELOAD}:/usr/lib/force_bind.so export LD_PRELOAD=${LD_PRELOAD}:/usr/lib/force_bind.so
69 69 your_program_here your_program_here
70 70
71 11. Force client connections (for example 'telnet', 'ssh',
72 'firefox' to connect from a specified address, not the auto
73 selected one:
74 export FORCE_NET_VERBOSE=1
75 export FORCE_BIND_ADDRESS_V4=127.0.0.2
76 export LD_PRELOAD=${LD_PRELOAD}:/usr/lib/force_bind.so
77 your_program_here
78
71 79 Installation: Installation:
72 80 - ./configure - ./configure
73 81 - make - make
File force_bind.c changed (mode: 100644) (index 8967a67..f3118c8)
34 34 #include <netinet/tcp.h> #include <netinet/tcp.h>
35 35
36 36
37 #define FB_FLAGS_NETSOCK 1
37 #define FB_FLAGS_NETSOCK (1 << 0)
38 #define FB_FLAGS_BIND_CALLED (1 << 1)
38 39
39 40 struct private struct private
40 41 { {
 
... ... static ssize_t (*old_send)(int sockfd, const void *buf, size_t len, int flags)
70 71 static ssize_t (*old_sendto)(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen); static ssize_t (*old_sendto)(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
71 72 static ssize_t (*old_sendmsg)(int sockfd, const struct msghdr *msg, int flags); static ssize_t (*old_sendmsg)(int sockfd, const struct msghdr *msg, int flags);
72 73 static int (*old_accept)(int sockfd, struct sockaddr *addr, socklen_t *addrlen); static int (*old_accept)(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
74 static int (*old_connect)(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
73 75
74 76 static char *force_address_v4 = NULL; static char *force_address_v4 = NULL;
75 77 static char *force_address_v6 = NULL; static char *force_address_v6 = NULL;
 
... ... static void init(void)
198 200 if (x != NULL) if (x != NULL)
199 201 verbose = strtol(x, NULL, 10); verbose = strtol(x, NULL, 10);
200 202
203 my_syslog(LOG_INFO, "force_bind: Init started...\n");
204
201 205 x = getenv("FORCE_BIND_ADDRESS_V4"); x = getenv("FORCE_BIND_ADDRESS_V4");
202 206 if (x != NULL) { if (x != NULL) {
203 207 force_address_v4 = x; force_address_v4 = x;
 
... ... static void init(void)
380 384 exit(1); exit(1);
381 385 } }
382 386
383 my_syslog(LOG_INFO, "force_bind: Inited.\n");
387 old_connect = dlsym(RTLD_NEXT, "connect");
388 if (old_connect == NULL) {
389 my_syslog(LOG_ERR, "force_bind: Cannot resolve 'connect'!\n");
390 exit(1);
391 }
392
393 my_syslog(LOG_INFO, "force_bind: Init ended.\n");
384 394 } }
385 395
386 396 static int set_ka(int sockfd) static int set_ka(int sockfd)
 
... ... static int set_nodelay(int sockfd)
482 492 return 0; return 0;
483 493 } }
484 494
485 static void change_things(int sockfd, struct sockaddr *sa)
495 /*
496 * Alters a struct sockaddr, based on environment variables
497 */
498 static void alter_sa(const int sockfd, struct sockaddr *sa)
486 499 { {
487 int err;
488 struct sockaddr_storage tmp;
489 socklen_t tmp_len;
490 500 struct sockaddr_in *sa4; struct sockaddr_in *sa4;
491 501 struct sockaddr_in6 *sa6; struct sockaddr_in6 *sa6;
492 502 unsigned short *pport = NULL; unsigned short *pport = NULL;
493 503 void *p; void *p;
494 struct node *q;
495 504 char *force_address; char *force_address;
496 505 int force_port; int force_port;
497
498 init();
499
500 /* We do not touch non network sockets */
501 q = get(sockfd);
502 if ((q == NULL) || ((q->priv.flags & FB_FLAGS_NETSOCK) == 0))
503 return;
504
505 if (sa == NULL) {
506 tmp_len = sizeof(struct sockaddr_storage);
507 err = getsockname(sockfd, (struct sockaddr *) &tmp, &tmp_len);
508 if (err != 0) {
509 my_syslog(LOG_INFO, "force_bind: Cannot get socket name err=%d (%s) [%d]!\n",
510 err, strerror(errno), sockfd);
511 return;
512 }
513 sa = (struct sockaddr *) &tmp;
514 }
506 int err;
515 507
516 508 switch (sa->sa_family) { switch (sa->sa_family) {
517 509 case AF_INET: case AF_INET:
 
... ... static void change_things(int sockfd, struct sockaddr *sa)
547 539
548 540 if (force_port != -1) if (force_port != -1)
549 541 *pport = htons(force_port); *pport = htons(force_port);
542
543 }
544
545 /*
546 * Alter local binding by doing a forced 'bind' call.
547 * This is called before calling connect and before using sendto/sendmsg.
548 */
549 static void change_local_binding(int sockfd)
550 {
551 int err;
552 struct node *q;
553 struct sockaddr_storage tmp;
554 socklen_t tmp_len;
555
556 init();
557
558 /* We do not touch non network sockets */
559 q = get(sockfd);
560 if ((q == NULL) || ((q->priv.flags & FB_FLAGS_NETSOCK) == 0))
561 return;
562
563 /* We do not touch already binded sockets */
564 if ((q->priv.flags & FB_FLAGS_BIND_CALLED) != 0)
565 return;
566
567 tmp_len = sizeof(struct sockaddr_storage);
568 err = getsockname(sockfd, (struct sockaddr *) &tmp, &tmp_len);
569 if (err != 0) {
570 my_syslog(LOG_INFO, "force_bind: Cannot get socket name err=%d (%s) [%d]!\n",
571 err, strerror(errno), sockfd);
572 return;
573 }
574 alter_sa(sockfd, (struct sockaddr *) &tmp);
575 err = old_bind(sockfd, (struct sockaddr *) &tmp, tmp_len);
576 q->priv.flags |= FB_FLAGS_BIND_CALLED;
577 if (err != 0)
578 my_syslog(LOG_INFO, "force_bind: Cannot bind err=%d (%s) [%d]!\n",
579 err, strerror(errno), sockfd);
550 580 } }
551 581
552 582 int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
553 583 { {
584 struct node *q;
554 585 struct sockaddr_storage new; struct sockaddr_storage new;
555 586
556 587 memcpy(&new, addr, addrlen); memcpy(&new, addr, addrlen);
557 588
558 change_things(sockfd, (struct sockaddr *) &new);
589 init();
590
591 /* We do not touch non network sockets */
592 q = get(sockfd);
593 if ((q != NULL) && ((q->priv.flags & FB_FLAGS_NETSOCK) != 0)) {
594 alter_sa(sockfd, (struct sockaddr *) &new);
595 q->priv.flags |= FB_FLAGS_BIND_CALLED;
596 }
597
559 598 return old_bind(sockfd, (struct sockaddr *) &new, addrlen); return old_bind(sockfd, (struct sockaddr *) &new, addrlen);
560 599 } }
561 600
 
... ... ssize_t write(int fd, const void *buf, size_t len)
730 769 { {
731 770 ssize_t n; ssize_t n;
732 771
733 change_things(fd, NULL);
734 772 n = old_write(fd, buf, len); n = old_write(fd, buf, len);
735 773 bw(fd, n); bw(fd, n);
736 774
 
... ... ssize_t send(int sockfd, const void *buf, size_t len, int flags)
741 779 { {
742 780 ssize_t n; ssize_t n;
743 781
744 change_things(sockfd, NULL);
745 782 n = old_send(sockfd, buf, len, flags); n = old_send(sockfd, buf, len, flags);
746 783 bw(sockfd, n); bw(sockfd, n);
747 784
 
... ... ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
753 790 { {
754 791 ssize_t n; ssize_t n;
755 792
756 change_things(sockfd, NULL);
793 change_local_binding(sockfd);
757 794 n = old_sendto(sockfd, buf, len, flags, dest_addr, addrlen); n = old_sendto(sockfd, buf, len, flags, dest_addr, addrlen);
758 795 bw(sockfd, n); bw(sockfd, n);
759 796
 
... ... ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags)
767 804 { {
768 805 ssize_t n; ssize_t n;
769 806
770 change_things(sockfd, NULL);
807 change_local_binding(sockfd);
771 808 n = old_sendmsg(sockfd, msg, flags); n = old_sendmsg(sockfd, msg, flags);
772 809 bw(sockfd, n); bw(sockfd, n);
773 810
 
... ... int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
785 822 init(); init();
786 823
787 824 new_sock = old_accept(sockfd, addr, addrlen); new_sock = old_accept(sockfd, addr, addrlen);
825 if (new_sock == -1)
826 return -1;
788 827
789 828 socket_create_callback(new_sock, -1, -1); socket_create_callback(new_sock, -1, -1);
790 829
791 830 return new_sock; return new_sock;
792 831 } }
832
833 int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
834 {
835 change_local_binding(sockfd);
836 return old_connect(sockfd, addr, addrlen);
837 }
838
File send_udp.c changed (mode: 100644) (index 96ea103..3977560)
10 10 int main(int argc, char *argv[]) int main(int argc, char *argv[])
11 11 { {
12 12 int sock, err; int sock, err;
13 struct sockaddr_in sa;
13 struct sockaddr_in sa, sa2;
14 socklen_t sa2_len;
14 15 int port = 123; int port = 123;
15 16 unsigned char buf[4096]; unsigned char buf[4096];
16 17 unsigned int bytes = 100000, rest, max; unsigned int bytes = 100000, rest, max;
18 char junk[128];
17 19
18 20 sock = socket(AF_INET, SOCK_DGRAM, 0); sock = socket(AF_INET, SOCK_DGRAM, 0);
19 21 if (sock == -1) { if (sock == -1) {
 
... ... int main(int argc, char *argv[])
49 51 rest -= err; rest -= err;
50 52 } }
51 53
54 err = getsockname(sock, (struct sockaddr *) &sa2, &sa2_len);
55 if (err != 0) {
56 perror("getsockname");
57 return 1;
58 }
59 fprintf(stderr, "Socket bound to %s/%d.\n",
60 inet_ntop(sa2.sin_family, &sa2.sin_addr, junk, sa2_len),
61 ntohs(sa2.sin_port));
62
52 63 close(sock); close(sock);
53 64
54 65 return 0; return 0;
File test_client.c copied from file test_bind.c (similarity 55%) (mode: 100644) (index ef56403..13d4c8b)
1 /*
2 * This program test socket->connect binding
3 * Copyright: Catalin(ux) M. BOIE
4 * Part of force_bind package
5 */
1 6 #include <sys/types.h> #include <sys/types.h>
2 7 #include <sys/socket.h> #include <sys/socket.h>
3 8 #include <sys/un.h> #include <sys/un.h>
 
... ... int main(int argc, char *argv[])
14 19 socklen_t sa_len; socklen_t sa_len;
15 20 int port = 4444; int port = 4444;
16 21 char junk[128]; char junk[128];
17 unsigned char tos;
22 char *dest = "127.0.0.1";
18 23
19 24 sock = socket(AF_INET, SOCK_STREAM, 0); sock = socket(AF_INET, SOCK_STREAM, 0);
20 25 if (sock == -1) { if (sock == -1) {
 
... ... int main(int argc, char *argv[])
23 28 } }
24 29
25 30 if (argc >= 2) if (argc >= 2)
26 port = strtol(argv[1], NULL, 10);
31 dest = argv[1];
32
33 if (argc >= 3)
34 port = strtol(argv[2], NULL, 10);
35
36 err = getsockname(sock, (struct sockaddr *) &sa2, &sa_len);
37 if (err != 0) {
38 perror("getsockname");
39 return 1;
40 }
41 fprintf(stderr, "Socket bound to %s/%d.\n",
42 inet_ntop(sa2.sin_family, &sa2.sin_addr, junk, sa_len),
43 ntohs(sa2.sin_port));
27 44
28 45 memset(&sa, 0, sizeof(struct sockaddr)); memset(&sa, 0, sizeof(struct sockaddr));
29 46 sa.sin_family = AF_INET; sa.sin_family = AF_INET;
30 47 sa.sin_port = htons(port); sa.sin_port = htons(port);
31 sa.sin_addr.s_addr = htonl(INADDR_ANY);
32
33 sa_len = sizeof(struct sockaddr_in);
34 err = bind(sock, (struct sockaddr *) &sa, sa_len);
35 if (err != 0) {
36 perror("bind");
48 err = inet_pton(AF_INET, dest, &sa.sin_addr);
49 if (err != 1) {
50 perror("inet_pton");
37 51 return 1; return 1;
38 52 } }
39 53
54 err = connect(sock, (struct sockaddr *) &sa, sizeof(sa));
55 if (err == -1) {
56 perror("connect");
57 /* ignore error */
58 }
59
40 60 err = getsockname(sock, (struct sockaddr *) &sa2, &sa_len); err = getsockname(sock, (struct sockaddr *) &sa2, &sa_len);
41 61 if (err != 0) { if (err != 0) {
42 62 perror("getsockname"); perror("getsockname");
43 63 return 1; return 1;
44 64 } }
45
46 fprintf(stderr, "Socket bound to %s/%d.\n",
65 fprintf(stderr, "Socket bound to %s/%d (after connect called).\n",
47 66 inet_ntop(sa2.sin_family, &sa2.sin_addr, junk, sa_len), inet_ntop(sa2.sin_family, &sa2.sin_addr, junk, sa_len),
48 67 ntohs(sa2.sin_port)); ntohs(sa2.sin_port));
49 68
50 tos = 0x00;
51 err = setsockopt(sock, IPPROTO_IP, IP_TOS, &tos, 1);
52 if (err != 0)
53 perror("setsockopt");
54
55 69 close(sock); close(sock);
56 70
57 71 return 0; return 0;
File test_client1.sh copied from file test1.sh (similarity 51%) (mode: 100755) (index 69df55f..39bb823)
1 1 #!/bin/sh #!/bin/sh
2 2
3 export FORCE_NET_VERBOSE=1
3 4 export FORCE_BIND_ADDRESS_V4=127.0.0.2 export FORCE_BIND_ADDRESS_V4=127.0.0.2
4 5
5 # use -1 to not change port
6 export FORCE_BIND_PORT_V4=900
7
8 6 export LD_PRELOAD="${LD_PRELOAD}:./force_bind.so" export LD_PRELOAD="${LD_PRELOAD}:./force_bind.so"
9 7
10 strace -o test1.strace -s100 -f "$@"
8 strace -o ${0}.strace -f -s100 ./test_client "$@"
File test_udp_local_bind.sh added (mode: 100755) (index 0000000..cdeba6d)
1 #!/bin/sh
2
3 # Test if we can alter source IP
4
5 ulimit -c2000000
6
7 export FORCE_BIND_ADDRESS_V4=127.0.0.2
8 export FORCE_NET_VERBOSE=1
9
10 export LD_PRELOAD="${LD_PRELOAD}:./force_bind.so"
11
12 make send_udp
13 strace -f -s200 -o ${0}.strace ./send_udp 123 8000
Hints:
Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://rocketgit.com/user/catalinux/force_bind

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@ssh.rocketgit.com/user/catalinux/force_bind

Clone this repository using git:
git clone git://git.rocketgit.com/user/catalinux/force_bind

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a merge request:
... clone the repository ...
... make some changes and some commits ...
git push origin main