Giter Site home page Giter Site logo

force_bind's Introduction

Name:		force_bind

Author:		Catali(ux) M. BOIE - catab at embedromix dot ro

Start date:	2010-10-26

Description:	Force binding on a specific IP and/or port.
		Works with both IPv4 and IPv6.
		It is useful if you have a binary application without sources
		and without the possibility to configure address or port to
		bind to.

License:	GPLv3

How it works:	force_bind is a shared object that is loaded with LD_PRELOAD and hooks 'bind' function.
		Forcing an IP/port to bind to is done with environments variables.

Examples:
		0. Output debug stuff in a log file (for debugging):
		export FORCE_NET_VERBOSE=999
		export FORCE_NET_LOG="xxx.log"
		your_program_here

		1. Force bind to 127.0.0.1, port 33, verbose operations:
		export FORCE_NET_VERBOSE=1
		export FORCE_BIND_ADDRESS_V4=127.0.0.1
		export FORCE_BIND_PORT_V4=33
		export LD_PRELOAD=${LD_PRELOAD}:/usr/lib/force_bind.so
		your_program_here

		2. Force binding to 127.0.0.2, port unchanged
		export FORCE_BIND_ADDRESS_V4=127.0.0.2
		export LD_PRELOAD=${LD_PRELOAD}:/usr/lib/force_bind.so
		your_program_here

		3. Force binding to ::1 (IPv6), port unchanged
		export FORCE_BIND_ADDRESS_V6=::1
		export LD_PRELOAD=${LD_PRELOAD}:/usr/lib/force_bind.so
		your_program_here

		4. Changing TOS on all sockets to 30
		export FORCE_NET_TOS=30
		export LD_PRELOAD=${LD_PRELOAD}:/usr/lib/force_bind.so
		your_program_here

		5. Force Keep alive to 60 seconds:
		export FORCE_NET_KA=60
		export LD_PRELOAD=${LD_PRELOAD}:/usr/lib/force_bind.so
		your_program_here

		6. Force MSS to 1400
		export FORCE_NET_MSS=1400
		export LD_PRELOAD=${LD_PRELOAD}:/usr/lib/force_bind.so
		your_program_here

		7. Force bandwidth to 1000 bytes/s for _all_ connections, cumulated
		export FORCE_NET_BW=1000
		export LD_PRELOAD=${LD_PRELOAD}:/usr/lib/force_bind.so
		your_program_here

		8. Force bandwidth to 20000 bytes/s per socket
		export FORCE_NET_BW_PER_SOCKET=20000
		export LD_PRELOAD=${LD_PRELOAD}:/usr/lib/force_bind.so
		scp root@machine1:/image.iso .

		9. Force REUSEADDR
		export FORCE_NET_REUSEADDR=1
		export LD_PRELOAD=${LD_PRELOAD}:/usr/lib/force_bind.so
		your_program_here

		10. Force NODELAY
		export FORCE_NET_NODELAY=1
		export LD_PRELOAD=${LD_PRELOAD}:/usr/lib/force_bind.so
		your_program_here

		11. Force client connections (for example 'telnet', 'ssh',
		'firefox') to connect from a specified address, not the auto
		selected one:
		export FORCE_NET_VERBOSE=1
		export FORCE_BIND_ADDRESS_V4=127.0.0.2
		export LD_PRELOAD=${LD_PRELOAD}:/usr/lib/force_bind.so
		your_program_here

		12. Set a FLOWINFO (flow label + class) for a client connection:
		export FORCE_NET_VERBOSE=1
		export FORCE_NET_FLOWINFO=0x7812345 # class 0x78, label 0x12345
		export LD_PRELOAD=${LD_PRELOAD}:/usr/lib/force_bind.so
		your_program_here
		A tcpdump of a connection will look like:
		00:00:00:00:00:00 > 00:00:00:00:00:00, ethertype IPv6 (0x86dd),
		length 94: (class 0x78, flowlabel 0x12345, hlim 64, next-header TCP (6) payload length: 40)
		::1.56981 > ::1.krb524: Flags [S], cksum 0x0030 (incorrect -> 0x91cf),
		seq 1154252590, win 32752, options [mss 16376,sackOK,TS val 28395104 ecr 0,nop,wscale 4], length 0

		13. Force FWMARK on a connection (only root is allowed):
		export FORCE_NET_VERBOSE=1
		export FORCE_NET_FWMARK=0x1234
		export LD_PRELOAD=${LD_PRELOAD}:/usr/lib/force_bind.so
		your_program_here

		14: Force priority (between 0 and 6 for non-root users). You can
		use 'tc' command from iproute to set-up 'prio' qdisc and to
		assign prio to queues:
		# 0. setup
		export FORCE_NET_VERBOSE=1
		export LD_PRELOAD=${LD_PRELOAD}:/usr/lib/force_bind.so
		# 1. Make sure you have a 'prio' qdisc attached to eth0, for example:
		tc qdisc add ev eth0 root handle 1: prio
		# 2. Assign applications to classed (bands):
		export FORCE_NET_PRIO=6 # interactive, band 0
		your_voip_program_here
		export FORCE_NET_PRIO=0 # best effort, band 1
		your_mail_program_here
		export FORCE_NET_PRIO=2 # bulk, band 2
		your_remote_backup_program_here
		# 3. Run tc statistics so you can see the classification:
		tc -s class show dev eth0

		15: Deny binding to any IPv4 sockets. The bind syscall
		will return -1 and errno will be set to EACCES.
		export FORCE_NET_VERBOSE=1
		export FORCE_BIND_ADDRESS_V4=deny
		export LD_PRELOAD=${LD_PRELOAD}:/usr/lib/force_bind.so
		your_program_here

		16: Silent fake binding to any IPv6 sockets. The bind will
		return success, but will never accept any connection.
		export FORCE_NET_VERBOSE=1
		export FORCE_BIND_ADDRESS_V6=fake
		export LD_PRELOAD=${LD_PRELOAD}:/usr/lib/force_bind.so
		your_program_here

Installation:
		- ./configure
		- make
		- make install

force_bind's People

Contributors

meebey avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

force_bind's Issues

Segfaults when using force_bind

Hi,

I have some segfaults when using some basic commands (less, man, cat), while having force_bind.so in LD_PRELOAD.

This produces segfault :

user@host:~$ cd /tmp/
user@host:/tmp$ export LD_PRELOAD=force_bind.so:
user@host:/tmp$ touch foo
user@host:/tmp$ less foo
Segmentation fault
user@host:/tmp$ 

Here is an strace when running less foo :

execve("/usr/bin/less", ["less", "foo"], [/* 19 vars */]) = 0
brk(0)                                  = 0xad6000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f4c31a57000
open("/etc/ld.so.cache", O_RDONLY)      = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=21754, ...}) = 0
mmap(NULL, 21754, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f4c31a51000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/tls/x86_64/force_bind.so", O_RDONLY) = -1 ENOENT (No such file or directory)
stat("/lib/x86_64-linux-gnu/tls/x86_64", 0x7fff7b7724b0) = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/tls/force_bind.so", O_RDONLY) = -1 ENOENT (No such file or directory)
stat("/lib/x86_64-linux-gnu/tls", 0x7fff7b7724b0) = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/x86_64/force_bind.so", O_RDONLY) = -1 ENOENT (No such file or directory)
stat("/lib/x86_64-linux-gnu/x86_64", 0x7fff7b7724b0) = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/force_bind.so", O_RDONLY) = -1 ENOENT (No such file or directory)
stat("/lib/x86_64-linux-gnu", {st_mode=S_IFDIR|0755, st_size=12288, ...}) = 0
open("/usr/lib/x86_64-linux-gnu/tls/x86_64/force_bind.so", O_RDONLY) = -1 ENOENT (No such file or directory)
stat("/usr/lib/x86_64-linux-gnu/tls/x86_64", 0x7fff7b7724b0) = -1 ENOENT (No such file or directory)
open("/usr/lib/x86_64-linux-gnu/tls/force_bind.so", O_RDONLY) = -1 ENOENT (No such file or directory)
stat("/usr/lib/x86_64-linux-gnu/tls", 0x7fff7b7724b0) = -1 ENOENT (No such file or directory)
open("/usr/lib/x86_64-linux-gnu/x86_64/force_bind.so", O_RDONLY) = -1 ENOENT (No such file or directory)
stat("/usr/lib/x86_64-linux-gnu/x86_64", 0x7fff7b7724b0) = -1 ENOENT (No such file or directory)
open("/usr/lib/x86_64-linux-gnu/force_bind.so", O_RDONLY) = -1 ENOENT (No such file or directory)
stat("/usr/lib/x86_64-linux-gnu", {st_mode=S_IFDIR|0755, st_size=12288, ...}) = 0
open("/lib/tls/x86_64/force_bind.so", O_RDONLY) = -1 ENOENT (No such file or directory)
stat("/lib/tls/x86_64", 0x7fff7b7724b0) = -1 ENOENT (No such file or directory)
open("/lib/tls/force_bind.so", O_RDONLY) = -1 ENOENT (No such file or directory)
stat("/lib/tls", 0x7fff7b7724b0)        = -1 ENOENT (No such file or directory)
open("/lib/x86_64/force_bind.so", O_RDONLY) = -1 ENOENT (No such file or directory)
stat("/lib/x86_64", 0x7fff7b7724b0)     = -1 ENOENT (No such file or directory)
open("/lib/force_bind.so", O_RDONLY)    = -1 ENOENT (No such file or directory)
stat("/lib", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
open("/usr/lib/tls/x86_64/force_bind.so", O_RDONLY) = -1 ENOENT (No such file or directory)
stat("/usr/lib/tls/x86_64", 0x7fff7b7724b0) = -1 ENOENT (No such file or directory)
open("/usr/lib/tls/force_bind.so", O_RDONLY) = -1 ENOENT (No such file or directory)
stat("/usr/lib/tls", 0x7fff7b7724b0)    = -1 ENOENT (No such file or directory)
open("/usr/lib/x86_64/force_bind.so", O_RDONLY) = -1 ENOENT (No such file or directory)
stat("/usr/lib/x86_64", 0x7fff7b7724b0) = -1 ENOENT (No such file or directory)
open("/usr/lib/force_bind.so", O_RDONLY) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\300\16\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|S_ISUID|S_ISGID|0755, st_size=127107, ...}) = 0
mmap(NULL, 2116864, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f4c31635000
mprotect(0x7f4c3163a000, 2093056, PROT_NONE) = 0
mmap(0x7f4c31839000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x4000) = 0x7f4c31839000
close(3)                                = 0
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libtinfo.so.5", O_RDONLY) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\300\323\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0644, st_size=167952, ...}) = 0
mmap(NULL, 2264608, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f4c3140c000
mprotect(0x7f4c31431000, 2093056, PROT_NONE) = 0
mmap(0x7f4c31630000, 20480, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x24000) = 0x7f4c31630000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\300\357\1\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1595408, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f4c31a50000
mmap(NULL, 3709016, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f4c31082000
mprotect(0x7f4c31202000, 2097152, PROT_NONE) = 0
mmap(0x7f4c31402000, 20480, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x180000) = 0x7f4c31402000
mmap(0x7f4c31407000, 18520, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f4c31407000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libdl.so.2", O_RDONLY) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\340\r\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0644, st_size=14768, ...}) = 0
mmap(NULL, 2109696, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f4c30e7e000
mprotect(0x7f4c30e80000, 2097152, PROT_NONE) = 0
mmap(0x7f4c31080000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x2000) = 0x7f4c31080000
close(3)                                = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f4c31a4f000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f4c31a4e000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f4c31a4d000
arch_prctl(ARCH_SET_FS, 0x7f4c31a4e700) = 0
mprotect(0x7f4c31080000, 4096, PROT_READ) = 0
mprotect(0x7f4c31402000, 16384, PROT_READ) = 0
mprotect(0x7f4c31630000, 16384, PROT_READ) = 0
mprotect(0x620000, 4096, PROT_READ)     = 0
mprotect(0x7f4c31a59000, 4096, PROT_READ) = 0
munmap(0x7f4c31a51000, 21754)           = 0
ioctl(1, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(1, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
brk(0)                                  = 0xad6000
brk(0xaf7000)                           = 0xaf7000
stat("/home/nicolas/.terminfo", 0x7fff7b771290) = -1 ENOENT (No such file or directory)
stat("/etc/terminfo", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
access("/etc/terminfo/x/xterm", R_OK)   = -1 ENOENT (No such file or directory)
stat("/lib/terminfo", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
access("/lib/terminfo/x/xterm", R_OK)   = 0
open("/lib/terminfo/x/xterm", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=3315, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f4c31a56000
read(3, "\32\1)\0&\0\17\0\235\1Z\5xterm|xterm-debian|X"..., 4096) = 3315
read(3, "", 4096)                       = 0
close(3)                                = 0
munmap(0x7f4c31a56000, 4096)            = 0
ioctl(1, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(1, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(1, TIOCGWINSZ, {ws_row=72, ws_col=270, ws_xpixel=0, ws_ypixel=0}) = 0
ioctl(2, TIOCGWINSZ, {ws_row=72, ws_col=270, ws_xpixel=0, ws_ypixel=0}) = 0
open("/usr/bin/.sysless", O_RDONLY)     = -1 ENOENT (No such file or directory)
open("/etc/sysless", O_RDONLY)          = -1 ENOENT (No such file or directory)
open("/home/nicolas/.less", O_RDONLY)   = -1 ENOENT (No such file or directory)
open("/usr/lib/locale/locale-archive", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=2031648, ...}) = 0
mmap(NULL, 2031648, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f4c3185c000
close(3)                                = 0
open("/home/nicolas/.lesshst", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0600, st_size=277, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f4c31a56000
read(3, ".less-history-file:\n.search\n\"log"..., 4096) = 277
read(3, "", 4096)                       = 0
close(3)                                = 0
munmap(0x7f4c31a56000, 4096)            = 0
open("/dev/tty", O_RDONLY)              = 3
ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
fsync(3)                                = -1 EINVAL (Invalid argument)
ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(3, SNDCTL_TMR_STOP or TCSETSW, {B38400 opost isig -icanon -echo ...}) = 0
ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig -icanon -echo ...}) = 0
rt_sigaction(SIGINT, {0x414760, [INT], SA_RESTORER|SA_RESTART, 0x7f4c310b44f0}, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGTSTP, {0x4146e0, [TSTP], SA_RESTORER|SA_RESTART, 0x7f4c310b44f0}, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGWINCH, {0x414720, [WINCH], SA_RESTORER|SA_RESTART, 0x7f4c310b44f0}, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGQUIT, {SIG_IGN, [QUIT], SA_RESTORER|SA_RESTART, 0x7f4c310b44f0}, {SIG_DFL, [], 0}, 8) = 0
stat("foo", {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
stat("foo", {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
open("foo", O_RDONLY)                   = 4
lseek(4, 1, SEEK_SET)                   = 1
lseek(4, 0, SEEK_SET)                   = 0
read(4, "", 256)                        = 0
lseek(4, 1, SEEK_SET)                   = 1
fstat(4, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
lseek(4, 0, SEEK_SET)                   = 0
stat("foo", {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
--- SIGSEGV (Segmentation fault) @ 0 (0) ---
+++ killed by SIGSEGV +++
Segmentation fault

Force bind is compiled from latest git, on a machine running Debian Wheezy amd64.

Regards,

N-Mi.

undefined symbol: dlsym

I am trying to run here with firefox/chromium browser @ Ubuntu 16.04 but after compile and try to run the first time I only got this message:

LD_PRELOAD="${LD_PRELOAD}:./force_bind.so"
export FORCE_BIND_ADDRESS_V6=2001:xxxx

firefox
/bin/sh: symbol lookup error: ./force_bind.so: undefined symbol: dlsym

Any idea/suggestion ?

force_bind doesn't work with UDP

Hi,

I don't know if you still maintain this code, but in doubt I fill this issue here.

I just compiled and installed force_bind from latest git, and could successfully use telnet and ping (after setuid the .so file).

I then tried to do some snmpget/snmpwalk on an equipment, and this doesn't work, while telnet and ping use the bind address configured in force_bind variables.

I checked with tcpdump and can observe that outgoing traffic for snmp requests are sourced with default interface IP, instead of the one declared in FORCE_BIND_ADDRESS_V4.

Here is the content of log file using verbose level 999 :

Init started...
Version: 0.11
Force bind to IPv4 address "172.21.17.38".
Init ended.
close(fd=3)
del(fd=3)
list...
socket(domain=IPv4, type=dgram, protocol=0)
socket_create_callback(3, IPv4, dgram)
add(fd=3, ...)
list...
    fd=   3 type=dgram flags=0001 limit=0 rest=0 last=0.000000 dest=0/?/?
sendmsg(sockfd=3, ..., flags=0x4040)
change_local_binding(sockfd=3)
alter_sa(sockfd=3, ...)
bw(sockfd=3, bytes=45)
sendmsg(sockfd=3, ..., flags=0x4040)
change_local_binding(sockfd=3)
bw(sockfd=3, bytes=45)
sendmsg(sockfd=3, ..., flags=0x4040)
change_local_binding(sockfd=3)
bw(sockfd=3, bytes=45)
sendmsg(sockfd=3, ..., flags=0x4040)
change_local_binding(sockfd=3)
bw(sockfd=3, bytes=45)
sendmsg(sockfd=3, ..., flags=0x4040)
change_local_binding(sockfd=3)
bw(sockfd=3, bytes=45)
sendmsg(sockfd=3, ..., flags=0x4040)
change_local_binding(sockfd=3)
bw(sockfd=3, bytes=45)
close(fd=3)
del(fd=3)
list...

We can see in this trace that force_bind is loaded, and tries to bind on given address, but traffic is actually sent with another address.

I had the same behaviour trying to perform a DNS request using nslookup, so I believe the problem is with UDP in general.

Regard,

N-Mi.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.