Popular New Releases in Web Servers
No Popular Releases are available at this moment for Web Servers
Popular Libraries in Web Servers
No Trending Libraries are available at this moment for Web Servers
Trending New libraries in Web Servers
No Trending Libraries are available at this moment for Web Servers
Top Authors in Web Servers
No Top Authors are available at this moment for Web Servers.
Trending Kits in Web Servers
No Trending Kits are available at this moment for Web Servers
Trending Discussions on Web Servers
Can't connect front-end (vue) to API (nodeJS), using nginx, EC2 AWS 20.04 Ubuntu
Is there an archive file format that supports being split in multiple parts and can be unpacked natively on MS Windows?
HAProxy doesn't connect to MariaDB Galera cluster backend
How to Configure Pfsense HAProxy HTTP HealthCheck Failover
Ansible Tower for Configuration Drift
Which port of localhost can I select in order to create a docker container?
MongoDB Rust Driver weird behavior
How use multiple socket.io servers with different library version on the same Node.js application
Azure Front Door to Website on IIS VM Host
Why is my non blocking raw sockets program running so slowly?
QUESTION
Can't connect front-end (vue) to API (nodeJS), using nginx, EC2 AWS 20.04 Ubuntu
Asked 2022-Apr-03 at 13:47I want to set up web servers. First I chose NodeJS with Express for backend, listening in port 3002.
Ok, next I set up ubuntu firewall allowing port 3002. Then I've tested with curl a login Endpoint to be sure that backend is working fine;
1curl -d '{"email":"adriel@admin.com","password":"{{mypass}}"}' -H 'Content-Type: application/json' http://{{my-ip}}:3002/user/login
2
then I got a token response, therefore API is working fine as expected.
Ubuntu firewall, pm2 start app.js, curl API request
Then I moved to front-end (vueJS), cloned vue repository, then I ran:
1curl -d '{"email":"adriel@admin.com","password":"{{mypass}}"}' -H 'Content-Type: application/json' http://{{my-ip}}:3002/user/login
2sudo npm i
3sudo npm run build
4
I installed Nginx and move dist folder (vue build files) to default nginx folder "/var/www"
and renamed package:
1curl -d '{"email":"adriel@admin.com","password":"{{mypass}}"}' -H 'Content-Type: application/json' http://{{my-ip}}:3002/user/login
2sudo npm i
3sudo npm run build
4sudo mv ./dist ./html
5
Then I set up nginx config at:
1curl -d '{"email":"adriel@admin.com","password":"{{mypass}}"}' -H 'Content-Type: application/json' http://{{my-ip}}:3002/user/login
2sudo npm i
3sudo npm run build
4sudo mv ./dist ./html
5sudo nano /etc/nginx/sites-availabe/default
6
1curl -d '{"email":"adriel@admin.com","password":"{{mypass}}"}' -H 'Content-Type: application/json' http://{{my-ip}}:3002/user/login
2sudo npm i
3sudo npm run build
4sudo mv ./dist ./html
5sudo nano /etc/nginx/sites-availabe/default
6 server {
7 listen 80 default_server;
8 listen [::]:80 default_server;
9
10 root /var/www/html;
11 index index.html index.htm index.nginx-debian.html;
12
13 server_name _;
14
15 location /api/ {
16 proxy_pass http://{{my-ip}}:3002;
17 proxy_http_version 1.1;
18 proxy_set_header Upgrade $http_upgrade;
19 proxy_set_header Connection 'upgrade';
20 proxy_set_header Host $host;
21 proxy_cache_bypass $http_upgrade;
22 }
23
24}
25
1curl -d '{"email":"adriel@admin.com","password":"{{mypass}}"}' -H 'Content-Type: application/json' http://{{my-ip}}:3002/user/login
2sudo npm i
3sudo npm run build
4sudo mv ./dist ./html
5sudo nano /etc/nginx/sites-availabe/default
6 server {
7 listen 80 default_server;
8 listen [::]:80 default_server;
9
10 root /var/www/html;
11 index index.html index.htm index.nginx-debian.html;
12
13 server_name _;
14
15 location /api/ {
16 proxy_pass http://{{my-ip}}:3002;
17 proxy_http_version 1.1;
18 proxy_set_header Upgrade $http_upgrade;
19 proxy_set_header Connection 'upgrade';
20 proxy_set_header Host $host;
21 proxy_cache_bypass $http_upgrade;
22 }
23
24}
25sudo netstat -plant | grep 80
26sudo systemctl stop apache2
27sudo nginx -t
28sudo systemctl start nginx
29
It should work fine but when I send a login response in the front-end, happens a 404 to my /api/, I even changed the base url to http://localhost:3002 but din't work as well. What should I do ? I don't know how to send a request in front-end, but curl works fine. Any tips?
ANSWER
Answered 2021-Sep-13 at 16:25I could solve the problem with API connection, using this Nginx configuration at /etc/nginx/sites-available/default
1curl -d '{"email":"adriel@admin.com","password":"{{mypass}}"}' -H 'Content-Type: application/json' http://{{my-ip}}:3002/user/login
2sudo npm i
3sudo npm run build
4sudo mv ./dist ./html
5sudo nano /etc/nginx/sites-availabe/default
6 server {
7 listen 80 default_server;
8 listen [::]:80 default_server;
9
10 root /var/www/html;
11 index index.html index.htm index.nginx-debian.html;
12
13 server_name _;
14
15 location /api/ {
16 proxy_pass http://{{my-ip}}:3002;
17 proxy_http_version 1.1;
18 proxy_set_header Upgrade $http_upgrade;
19 proxy_set_header Connection 'upgrade';
20 proxy_set_header Host $host;
21 proxy_cache_bypass $http_upgrade;
22 }
23
24}
25sudo netstat -plant | grep 80
26sudo systemctl stop apache2
27sudo nginx -t
28sudo systemctl start nginx
29server {
30 listen 80 default_server;
31 server_name _;
32
33 # front end
34 location / {
35 root /myprojects/front-end/dist;
36 try_files $uri /index.html;
37 }
38
39 # node api reverse proxy
40 location /api/ {
41 proxy_pass http://localhost:3002/;
42 }
43}
44
This is the right away to use nodeJS as a proxy reverse server
QUESTION
Is there an archive file format that supports being split in multiple parts and can be unpacked natively on MS Windows?
Asked 2022-Mar-27 at 02:18Some archive file formats, e.g. ZIP (see Section 8 in https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT), support being split into multiple parts of a limited size. ZIP files can be opened natively on recent versions of Microsoft Windows, but it seems that Windows cannot open split ZIP files natively, only with special tools like 7-Zip. I would like to use this "split archive" functionality in a web app that I'm writing in which the created archives should be opened by a large audience of "average" computer users, so my question is: Is there an archive file format (like ZIP) that supports being split in multiple parts and can be unpacked without installing additional software on recent versions of Microsoft Windows? And ideally on other widely used operating systems as well.
Background: My final goal is to export a directory structure that is split over multiple web servers to a single local directory tree. My current idea is to have each web server produce one part of the split archive, provide all of them as some sort of Javascript multi-file download and then have one archive (in multiple parts) on the user's computer that just needs to be unpacked. An alternative idea for this final goal was to use Javascript's File System Access API (https://developer.mozilla.org/en-US/docs/Web/API/File_System_Access_API), but it is not supported on Firefox, which is a showstopper.
ANSWER
Answered 2022-Mar-27 at 02:18CAB
archives meet this purpose a bit (see this library's page for example, it says that through it, archives can even be extracted directly from a HTTP(S)/FTP server). Since the library relies on .NET, it could even be used on Linux through Mono/Wine, which is a crucial part if your servers aren't running Windows... Because archive must be created on server, right?.
Your major problem is more that a split archive can't be created in parallel on multiple servers, at least because of LZx's dictionnary. Each server should create the whole set of archives and send only the ones it should send, and you don't have ANY guarantee that all these archives' sets would be identical on each server.
Best way is probably to create the whole archive on ONE server, then distribute each part (or the whole splitted archive...) on your various servers, through a replication-like interface.
Otherwise, you can also make individual archives that contains only a subset of the directory tree (you'll have to partition the files across servers), but it won't meet your requirements since it would be a collection of individual archives, and not a big splitted archive.
Some precisions may be required:
- Do you absolutely need a system without any client besides the browser? Or can you use other protocols, as long as they natively exist on Windows (like FTP / SSH client that are now provided by default)?
- What is the real purpose behind this request? Distribute load across all servers? Or to avoid too big single file downloads (i.e. a 30 GB archive) in case of transfer failure? Or both?
- In case of a file size problem, why don't rely on resuming download?
QUESTION
HAProxy doesn't connect to MariaDB Galera cluster backend
Asked 2022-Mar-25 at 20:05I'm new to MariaDB galera cluster load balancing and I'm trying to use HAProxy to do the load balancing. I have set up the MariaDB Galera cluster and it works perfectly.
In Haproxy, I have created a VIP for the DB cluster and if I look at the HAProxy statistics page it shows the VIP and all three nodes are green. This is how I have it configured:
1#---------------------------------------------------------------------
2# frontend_db_domain.com
3#---------------------------------------------------------------------
4frontend db_domain.com
5
6 bind ip:3306
7 mode tcp
8 option mysql-check user haproxy_check
9 default_backend back_db_domain.com
10
11#---------------------------------------------------------------------
12# backend_db_domain.com
13#---------------------------------------------------------------------
14backend back_db_domain.com
15 balance roundrobin
16 server db01.domain.com ip:3306 check
17 server db02.domain.com ip:3306 check
18 server db03.domain.com ip:3306 check
19
I configured a wordpress site to use the VIP address which is db.domain.com and wordpress shows Error establishing a database connection
. If I use the db hostname or ip that hits the nodes directly everything works fine.
This is what shows in the HAProxy logs:
1#---------------------------------------------------------------------
2# frontend_db_domain.com
3#---------------------------------------------------------------------
4frontend db_domain.com
5
6 bind ip:3306
7 mode tcp
8 option mysql-check user haproxy_check
9 default_backend back_db_domain.com
10
11#---------------------------------------------------------------------
12# backend_db_domain.com
13#---------------------------------------------------------------------
14backend back_db_domain.com
15 balance roundrobin
16 server db01.domain.com ip:3306 check
17 server db02.domain.com ip:3306 check
18 server db03.domain.com ip:3306 check
19Mar 24 04:07:27 localhost haproxy[22096]: 1.2.3.4:56022 [24/Mar/2022:04:07:16.987] domain.com~ back_domain.com/nginx01.domain.com 68/0/1/10095/10164 500 2842 - - ---- 3/1/0/0/0 0/0 "GET /webdesigns/website1/ HTTP/1.1"
20
This is the nginx logs:
1#---------------------------------------------------------------------
2# frontend_db_domain.com
3#---------------------------------------------------------------------
4frontend db_domain.com
5
6 bind ip:3306
7 mode tcp
8 option mysql-check user haproxy_check
9 default_backend back_db_domain.com
10
11#---------------------------------------------------------------------
12# backend_db_domain.com
13#---------------------------------------------------------------------
14backend back_db_domain.com
15 balance roundrobin
16 server db01.domain.com ip:3306 check
17 server db02.domain.com ip:3306 check
18 server db03.domain.com ip:3306 check
19Mar 24 04:07:27 localhost haproxy[22096]: 1.2.3.4:56022 [24/Mar/2022:04:07:16.987] domain.com~ back_domain.com/nginx01.domain.com 68/0/1/10095/10164 500 2842 - - ---- 3/1/0/0/0 0/0 "GET /webdesigns/website1/ HTTP/1.1"
2045.77.206.174 - - [24/Mar/2022:04:07:27 +0000] "GET /webdesigns/website1/ HTTP/1.1" 500 2539 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:98.0) Gecko/20100101 Firefox/98.0" "1.2.3.4"
21
There is no firewall in place that would block anything between all these hosts. They can all connect to each other. This is how the db nodes are configured:
1#---------------------------------------------------------------------
2# frontend_db_domain.com
3#---------------------------------------------------------------------
4frontend db_domain.com
5
6 bind ip:3306
7 mode tcp
8 option mysql-check user haproxy_check
9 default_backend back_db_domain.com
10
11#---------------------------------------------------------------------
12# backend_db_domain.com
13#---------------------------------------------------------------------
14backend back_db_domain.com
15 balance roundrobin
16 server db01.domain.com ip:3306 check
17 server db02.domain.com ip:3306 check
18 server db03.domain.com ip:3306 check
19Mar 24 04:07:27 localhost haproxy[22096]: 1.2.3.4:56022 [24/Mar/2022:04:07:16.987] domain.com~ back_domain.com/nginx01.domain.com 68/0/1/10095/10164 500 2842 - - ---- 3/1/0/0/0 0/0 "GET /webdesigns/website1/ HTTP/1.1"
2045.77.206.174 - - [24/Mar/2022:04:07:27 +0000] "GET /webdesigns/website1/ HTTP/1.1" 500 2539 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:98.0) Gecko/20100101 Firefox/98.0" "1.2.3.4"
21[mysqld]
22binlog_format=ROW
23default-storage-engine=innodb
24innodb_autoinc_lock_mode=2
25#bind-address=0.0.0.0
26
27# Galera Provider Configuration
28wsrep_on=ON
29wsrep_provider=/usr/lib64/galera-4/libgalera_smm.so
30
31# Galera Cluster Configuration
32wsrep_cluster_name="test_cluster"
33wsrep_cluster_address="gcomm://10.1.96.12,10.1.96.13,10.1.96.14"
34
35# Galera Synchronization Configuration
36wsrep_sst_method=rsync
37
38# Galera Node Configuration
39wsrep_node_address="10.1.96.14"
40wsrep_node_name="db03"
41
Not sure what I am missing but I think I have a misconfiguration on the HAProxy side but not sure what it can be. I have other VIPs but they're for web servers and stuff like that which all work fine. This the first VIP I have issues with. I would appreciate any and all help.
Thank you!
ANSWER
Answered 2022-Mar-24 at 06:09cli ip a check your vip is work on haproxy hosts\
QUESTION
How to Configure Pfsense HAProxy HTTP HealthCheck Failover
Asked 2022-Mar-02 at 18:12I have two backend web servers, and i need to monitor them using httpcheck by checking the URL and looking for a string to be present in the response of the request. if the string is not available switch the backend to another server.
Status:
- Server1 - Active
- Server2 - Backup
Configuration Details:
- Health Check Method : HTTP
- HTTP Check Method : GET
- Url used by http check requests:
/jsonp/FreeForm&maxrecords=10&format=XML&ff=223
- Http check version : HTTP/1.0\r\nAccept:\ XS01
Result of the http Request is
1{"d":{"__type":"Response","Version":"4.5.23.1160","ResultCode":"XS01","ErrorString":"","Results":[{"__type":"Result",
2
so, I am expecting the string ResultCode":"XS01"
in the response from the server, if the string found the server1 is up, if not bring the Server2 from the backup.
how can i achieve this in HAProxy Backend Health Check?
ANSWER
Answered 2022-Mar-02 at 18:12This can be done under Advanced Settings--> Backend Pass thru using the expect string,
http-check expect string XS01
QUESTION
Ansible Tower for Configuration Drift
Asked 2022-Feb-24 at 12:34We've set up an Ansible Tower and have written several job templates and jobs, created our hosts and groups, all of that. Right now we're scheduling jobs to run to apply the playbooks assigned to groups, such as our web servers, to keep them from running into configuration drift. But we've been told not to use Tower for configuration drift, but if we don't do that, what's the best practice on how to use Ansible to ensure the playbooks run on a regular basis?
ANSWER
Answered 2022-Feb-24 at 12:34But we've been told not to use Tower for configuration drift
Probably because of infrastructure and resource consumption since i.e. Control with Ansible Tower or verify compliance is a common use case.
but if we don't do that, what's the best practice on how to use Ansible to ensure the playbooks run on a regular basis?
This will highly depend on your environment, amount of hosts and groups, the content and runtime of playbooks, (configuration) change rate in your environment, network utilization, amount of data transferd and so on.
Except from general available Ansible documentation recommendations some more Best Practices might be
- Cache facts
- Have playbooks as simple as possible
- Make playbooks have a short runtime,
profile_tasks
to achieve this goal - Use Clustering, Execution Environments and Instance Groups for certain tasks, roles, hosts and groups
- Use Resource Profiling
In other words, it is most about Ansible Performance Tuning. You may have also a look into Strategy plugins like Mitogen .
QUESTION
Which port of localhost can I select in order to create a docker container?
Asked 2022-Feb-05 at 21:38I'm learning Kurbernetes and Docker at the moment, KinD in particular. To start with, I just want to run docker run --rm --name <container's name> -p 8080:80 -d <image name>
to create a container from the image.
I know that ports are used in the TCP/IP protocol (or Internet Protocol) to address a specific program (software). Port 80 is a default port to run web servers.
Now, my question is why 8080 or why 5000? How to determine which port should be an OUTSIDE port in this case? Is it just random or are there any rule/restrictions?
ANSWER
Answered 2022-Feb-05 at 15:12port 8080 is normally used to host your personal webserver/service and it is alternate of port 80 you can also use other ports instead of 8080. when some one try to connect to your webserver from outside, and if you use port 8080, they don't need to specify port number because by default it will look for port 8080.
If you use any other port number, when someone try to connect to your webservice/server from outside, they should specify the custom port number you specified to access your webservice/server
QUESTION
MongoDB Rust Driver weird behavior
Asked 2022-Jan-31 at 16:32There is this weird thing, I have installed the MongoDB Compass and made a aggregation query that works in the Aggregation tab but now when I use the same query in my rust web server it behaves very weirdly
Original message:
1{"_id":{"$oid":"61efd41c56ffe6b1b4a15c7a"},"time":{"$date":"2022-01-25T10:42:36.175Z"},"edited_time":{"$date":"2022-01-30T14:29:54.361Z"},"changes":[],"content":"LORA","author":{"$oid":"61df3cab3087579f8767a38d"}}
2
Message in MongoDB compass after the query:
1{"_id":{"$oid":"61efd41c56ffe6b1b4a15c7a"},"time":{"$date":"2022-01-25T10:42:36.175Z"},"edited_time":{"$date":"2022-01-30T14:29:54.361Z"},"changes":[],"content":"LORA","author":{"$oid":"61df3cab3087579f8767a38d"}}
2{
3 "_id": {
4 "$oid": "61efd41c56ffe6b1b4a15c7a"
5 },
6 "time": {
7 "$date": "2022-01-25T10:42:36.175Z"
8 },
9 "edited_time": {
10 "$date": "2021-12-17T09:55:45.856Z"
11 },
12 "changes": [{
13 "time": {
14 "$date": "2021-12-17T09:55:45.856Z"
15 },
16 "change": {
17 "ChangedContent": "LORA"
18 }
19 }],
20 "content": "LMAO",
21 "author": {
22 "$oid": "61df3cab3087579f8767a38d"
23 }
24}
25
Message after the Web Servers query:
1{"_id":{"$oid":"61efd41c56ffe6b1b4a15c7a"},"time":{"$date":"2022-01-25T10:42:36.175Z"},"edited_time":{"$date":"2022-01-30T14:29:54.361Z"},"changes":[],"content":"LORA","author":{"$oid":"61df3cab3087579f8767a38d"}}
2{
3 "_id": {
4 "$oid": "61efd41c56ffe6b1b4a15c7a"
5 },
6 "time": {
7 "$date": "2022-01-25T10:42:36.175Z"
8 },
9 "edited_time": {
10 "$date": "2021-12-17T09:55:45.856Z"
11 },
12 "changes": [{
13 "time": {
14 "$date": "2021-12-17T09:55:45.856Z"
15 },
16 "change": {
17 "ChangedContent": "LORA"
18 }
19 }],
20 "content": "LMAO",
21 "author": {
22 "$oid": "61df3cab3087579f8767a38d"
23 }
24}
25{
26 "_id": {
27 "$oid": "61efd41c56ffe6b1b4a15c7a"
28 },
29 "time": {
30 "$date": "2022-01-25T10:42:36.175Z"
31 },
32 "edited_time": {
33 "$date": "2022-01-30T14:40:57.152Z"
34 },
35 "changes": {
36 "$concatArrays": ["$changes", [{
37 "time": {
38 "$date": "2022-01-30T14:40:57.152Z"
39 },
40 "change": {
41 "ChangedContent": "$content"
42 }
43 }]]
44 },
45 "content": "LMAO",
46 "author": {
47 "$oid": "61df3cab3087579f8767a38d"
48 }
49}
50
Pure query in MongoDB Compass: $set stage
1{"_id":{"$oid":"61efd41c56ffe6b1b4a15c7a"},"time":{"$date":"2022-01-25T10:42:36.175Z"},"edited_time":{"$date":"2022-01-30T14:29:54.361Z"},"changes":[],"content":"LORA","author":{"$oid":"61df3cab3087579f8767a38d"}}
2{
3 "_id": {
4 "$oid": "61efd41c56ffe6b1b4a15c7a"
5 },
6 "time": {
7 "$date": "2022-01-25T10:42:36.175Z"
8 },
9 "edited_time": {
10 "$date": "2021-12-17T09:55:45.856Z"
11 },
12 "changes": [{
13 "time": {
14 "$date": "2021-12-17T09:55:45.856Z"
15 },
16 "change": {
17 "ChangedContent": "LORA"
18 }
19 }],
20 "content": "LMAO",
21 "author": {
22 "$oid": "61df3cab3087579f8767a38d"
23 }
24}
25{
26 "_id": {
27 "$oid": "61efd41c56ffe6b1b4a15c7a"
28 },
29 "time": {
30 "$date": "2022-01-25T10:42:36.175Z"
31 },
32 "edited_time": {
33 "$date": "2022-01-30T14:40:57.152Z"
34 },
35 "changes": {
36 "$concatArrays": ["$changes", [{
37 "time": {
38 "$date": "2022-01-30T14:40:57.152Z"
39 },
40 "change": {
41 "ChangedContent": "$content"
42 }
43 }]]
44 },
45 "content": "LMAO",
46 "author": {
47 "$oid": "61df3cab3087579f8767a38d"
48 }
49}
50{
51 "changes": { $concatArrays: [ "$changes", [ { "time": ISODate('2021-12-17T09:55:45.856+00:00'), "change": { "ChangedContent": "$content" } } ] ] },
52 "edited_time": ISODate('2021-12-17T09:55:45.856+00:00'),
53 "content": "LMAO",
54}
55
Pure query in Web Server:
1{"_id":{"$oid":"61efd41c56ffe6b1b4a15c7a"},"time":{"$date":"2022-01-25T10:42:36.175Z"},"edited_time":{"$date":"2022-01-30T14:29:54.361Z"},"changes":[],"content":"LORA","author":{"$oid":"61df3cab3087579f8767a38d"}}
2{
3 "_id": {
4 "$oid": "61efd41c56ffe6b1b4a15c7a"
5 },
6 "time": {
7 "$date": "2022-01-25T10:42:36.175Z"
8 },
9 "edited_time": {
10 "$date": "2021-12-17T09:55:45.856Z"
11 },
12 "changes": [{
13 "time": {
14 "$date": "2021-12-17T09:55:45.856Z"
15 },
16 "change": {
17 "ChangedContent": "LORA"
18 }
19 }],
20 "content": "LMAO",
21 "author": {
22 "$oid": "61df3cab3087579f8767a38d"
23 }
24}
25{
26 "_id": {
27 "$oid": "61efd41c56ffe6b1b4a15c7a"
28 },
29 "time": {
30 "$date": "2022-01-25T10:42:36.175Z"
31 },
32 "edited_time": {
33 "$date": "2022-01-30T14:40:57.152Z"
34 },
35 "changes": {
36 "$concatArrays": ["$changes", [{
37 "time": {
38 "$date": "2022-01-30T14:40:57.152Z"
39 },
40 "change": {
41 "ChangedContent": "$content"
42 }
43 }]]
44 },
45 "content": "LMAO",
46 "author": {
47 "$oid": "61df3cab3087579f8767a38d"
48 }
49}
50{
51 "changes": { $concatArrays: [ "$changes", [ { "time": ISODate('2021-12-17T09:55:45.856+00:00'), "change": { "ChangedContent": "$content" } } ] ] },
52 "edited_time": ISODate('2021-12-17T09:55:45.856+00:00'),
53 "content": "LMAO",
54}
55 let update_doc = doc! {
56 "$set": {
57 "changes": {
58 "$concatArrays": [
59 "$changes", [
60 {
61 "time": now,
62 "change": {
63 "ChangedContent": "$content"
64 }
65 }
66 ]
67 ]
68 },
69 "edited_time": now,
70 "content": content
71 }
72 };
73
I am using update_one method, like this
1{"_id":{"$oid":"61efd41c56ffe6b1b4a15c7a"},"time":{"$date":"2022-01-25T10:42:36.175Z"},"edited_time":{"$date":"2022-01-30T14:29:54.361Z"},"changes":[],"content":"LORA","author":{"$oid":"61df3cab3087579f8767a38d"}}
2{
3 "_id": {
4 "$oid": "61efd41c56ffe6b1b4a15c7a"
5 },
6 "time": {
7 "$date": "2022-01-25T10:42:36.175Z"
8 },
9 "edited_time": {
10 "$date": "2021-12-17T09:55:45.856Z"
11 },
12 "changes": [{
13 "time": {
14 "$date": "2021-12-17T09:55:45.856Z"
15 },
16 "change": {
17 "ChangedContent": "LORA"
18 }
19 }],
20 "content": "LMAO",
21 "author": {
22 "$oid": "61df3cab3087579f8767a38d"
23 }
24}
25{
26 "_id": {
27 "$oid": "61efd41c56ffe6b1b4a15c7a"
28 },
29 "time": {
30 "$date": "2022-01-25T10:42:36.175Z"
31 },
32 "edited_time": {
33 "$date": "2022-01-30T14:40:57.152Z"
34 },
35 "changes": {
36 "$concatArrays": ["$changes", [{
37 "time": {
38 "$date": "2022-01-30T14:40:57.152Z"
39 },
40 "change": {
41 "ChangedContent": "$content"
42 }
43 }]]
44 },
45 "content": "LMAO",
46 "author": {
47 "$oid": "61df3cab3087579f8767a38d"
48 }
49}
50{
51 "changes": { $concatArrays: [ "$changes", [ { "time": ISODate('2021-12-17T09:55:45.856+00:00'), "change": { "ChangedContent": "$content" } } ] ] },
52 "edited_time": ISODate('2021-12-17T09:55:45.856+00:00'),
53 "content": "LMAO",
54}
55 let update_doc = doc! {
56 "$set": {
57 "changes": {
58 "$concatArrays": [
59 "$changes", [
60 {
61 "time": now,
62 "change": {
63 "ChangedContent": "$content"
64 }
65 }
66 ]
67 ]
68 },
69 "edited_time": now,
70 "content": content
71 }
72 };
73 messages.update_one(message_filter, update_doc, None).await?;
74
I don't really understand, and this happens often, sometimes it fixes it self when I add somewhere randomly some scope in the doc eg.: { } but this time I couldn't figure it out, I had version of the query with $push but that didn't work too Is there some fault in the rust driver or am I doing something wrong, are there some rules about formatting when using rust driver that I am missing?
ANSWER
Answered 2022-Jan-31 at 16:32The $set
aggregation pipeline stage is different from the $set
update operator. And the only difference that I can tell, is the pipeline stage handles $concatArrays
while the update operator does not.
$set
Aggregation Pipeline Stage
$set
appends new fields to existing documents. You can include one or more$set
stages in an aggregation operation.To add field or fields to embedded documents (including documents in arrays) use the dot notation.
To add an element to an existing array field with
$set
, use with$concatArrays
.
$set
Update Operator
Starting in MongoDB 5.0, update operators process document fields with string-based names in lexicographic order. Fields with numeric names are processed in numeric order.
If the field does not exist,
$set
will add a new field with the specified value, provided that the new field does not violate a type constraint. If you specify a dotted path for a non-existent field,$set
will create the embedded documents as needed to fulfill the dotted path to the field.If you specify multiple field-value pairs,
$set
will update or create each field.
So if you want to update an existing document by inserting elements into an array field, use the $push
update operator (potentially with $each
if you're inserting multiple elements):
1{"_id":{"$oid":"61efd41c56ffe6b1b4a15c7a"},"time":{"$date":"2022-01-25T10:42:36.175Z"},"edited_time":{"$date":"2022-01-30T14:29:54.361Z"},"changes":[],"content":"LORA","author":{"$oid":"61df3cab3087579f8767a38d"}}
2{
3 "_id": {
4 "$oid": "61efd41c56ffe6b1b4a15c7a"
5 },
6 "time": {
7 "$date": "2022-01-25T10:42:36.175Z"
8 },
9 "edited_time": {
10 "$date": "2021-12-17T09:55:45.856Z"
11 },
12 "changes": [{
13 "time": {
14 "$date": "2021-12-17T09:55:45.856Z"
15 },
16 "change": {
17 "ChangedContent": "LORA"
18 }
19 }],
20 "content": "LMAO",
21 "author": {
22 "$oid": "61df3cab3087579f8767a38d"
23 }
24}
25{
26 "_id": {
27 "$oid": "61efd41c56ffe6b1b4a15c7a"
28 },
29 "time": {
30 "$date": "2022-01-25T10:42:36.175Z"
31 },
32 "edited_time": {
33 "$date": "2022-01-30T14:40:57.152Z"
34 },
35 "changes": {
36 "$concatArrays": ["$changes", [{
37 "time": {
38 "$date": "2022-01-30T14:40:57.152Z"
39 },
40 "change": {
41 "ChangedContent": "$content"
42 }
43 }]]
44 },
45 "content": "LMAO",
46 "author": {
47 "$oid": "61df3cab3087579f8767a38d"
48 }
49}
50{
51 "changes": { $concatArrays: [ "$changes", [ { "time": ISODate('2021-12-17T09:55:45.856+00:00'), "change": { "ChangedContent": "$content" } } ] ] },
52 "edited_time": ISODate('2021-12-17T09:55:45.856+00:00'),
53 "content": "LMAO",
54}
55 let update_doc = doc! {
56 "$set": {
57 "changes": {
58 "$concatArrays": [
59 "$changes", [
60 {
61 "time": now,
62 "change": {
63 "ChangedContent": "$content"
64 }
65 }
66 ]
67 ]
68 },
69 "edited_time": now,
70 "content": content
71 }
72 };
73 messages.update_one(message_filter, update_doc, None).await?;
74let update_doc = doc! {
75 "$set": {
76 "edited_time": now,
77 "content": content
78 },
79 "$push": {
80 "changes": {
81 "time": now,
82 "change": {
83 "ChangedContent": "$content"
84 }
85 }
86 }
87};
88
Edit: I missed that $content
was supposed to be mapped from the existing field as well. That is not supported by an update document, however MongoDB has support for using an aggregation pipeline to update the document. See: Update MongoDB field using value of another field So you can use the original $set
just in a different way:
1{"_id":{"$oid":"61efd41c56ffe6b1b4a15c7a"},"time":{"$date":"2022-01-25T10:42:36.175Z"},"edited_time":{"$date":"2022-01-30T14:29:54.361Z"},"changes":[],"content":"LORA","author":{"$oid":"61df3cab3087579f8767a38d"}}
2{
3 "_id": {
4 "$oid": "61efd41c56ffe6b1b4a15c7a"
5 },
6 "time": {
7 "$date": "2022-01-25T10:42:36.175Z"
8 },
9 "edited_time": {
10 "$date": "2021-12-17T09:55:45.856Z"
11 },
12 "changes": [{
13 "time": {
14 "$date": "2021-12-17T09:55:45.856Z"
15 },
16 "change": {
17 "ChangedContent": "LORA"
18 }
19 }],
20 "content": "LMAO",
21 "author": {
22 "$oid": "61df3cab3087579f8767a38d"
23 }
24}
25{
26 "_id": {
27 "$oid": "61efd41c56ffe6b1b4a15c7a"
28 },
29 "time": {
30 "$date": "2022-01-25T10:42:36.175Z"
31 },
32 "edited_time": {
33 "$date": "2022-01-30T14:40:57.152Z"
34 },
35 "changes": {
36 "$concatArrays": ["$changes", [{
37 "time": {
38 "$date": "2022-01-30T14:40:57.152Z"
39 },
40 "change": {
41 "ChangedContent": "$content"
42 }
43 }]]
44 },
45 "content": "LMAO",
46 "author": {
47 "$oid": "61df3cab3087579f8767a38d"
48 }
49}
50{
51 "changes": { $concatArrays: [ "$changes", [ { "time": ISODate('2021-12-17T09:55:45.856+00:00'), "change": { "ChangedContent": "$content" } } ] ] },
52 "edited_time": ISODate('2021-12-17T09:55:45.856+00:00'),
53 "content": "LMAO",
54}
55 let update_doc = doc! {
56 "$set": {
57 "changes": {
58 "$concatArrays": [
59 "$changes", [
60 {
61 "time": now,
62 "change": {
63 "ChangedContent": "$content"
64 }
65 }
66 ]
67 ]
68 },
69 "edited_time": now,
70 "content": content
71 }
72 };
73 messages.update_one(message_filter, update_doc, None).await?;
74let update_doc = doc! {
75 "$set": {
76 "edited_time": now,
77 "content": content
78 },
79 "$push": {
80 "changes": {
81 "time": now,
82 "change": {
83 "ChangedContent": "$content"
84 }
85 }
86 }
87};
88let update_pipeline = vec![
89 doc! {
90 "$set": {
91 "changes": {
92 "$concatArrays": [
93 "$changes", [
94 {
95 "time": now,
96 "change": {
97 "ChangedContent": "$content"
98 }
99 }
100 ]
101 ]
102 },
103 "edited_time": now,
104 "content": content
105 }
106 }
107];
108
109messages.update_one(message_filter, update_pipeline, None).await?;
110
QUESTION
How use multiple socket.io servers with different library version on the same Node.js application
Asked 2022-Jan-29 at 12:35As the title suggests I'm trying to use in the same application two different socket.io servers, one with socket.ioV4 and the other with socket.ioV2, the servers go up but I fail to get the sockets to connect.
A bit of context: the reason I'm trying to do this is because two clients need to exchange data using the Node.js application as a bridge, and each of them requires a different version of the socket.io package (as mentioned, V4 vs V2).
What I managed to do: I installed the V4 version as usual and the V2 version using an alias
1npm install socket.io@^4.4.1
2
3npm install socket.io-v2@npm:socket.io@2.0.1
4
and I created the two servers with
1npm install socket.io@^4.4.1
2
3npm install socket.io-v2@npm:socket.io@2.0.1
4const express = require('express');
5const http = require('http');
6const { Server } = require('socket.io');
7
8const app = express();
9const server = http.createServer(app);
10const io = new Server(server);
11
12const v2_server = require('http').Server(app);
13const iov2 = require('socket.io-v2')(v2_server);
14
The socket.io servers are defined as such
1npm install socket.io@^4.4.1
2
3npm install socket.io-v2@npm:socket.io@2.0.1
4const express = require('express');
5const http = require('http');
6const { Server } = require('socket.io');
7
8const app = express();
9const server = http.createServer(app);
10const io = new Server(server);
11
12const v2_server = require('http').Server(app);
13const iov2 = require('socket.io-v2')(v2_server);
14io.on('connection', (socket) => {
15 // DEBUG
16 console.log("V4 data received");
17})
18
19iov2.on('connection', (socket) => {
20 // DEBUG
21 console.log("V2 data received");
22})
23
Then I spin up the two servers on two different ports
1npm install socket.io@^4.4.1
2
3npm install socket.io-v2@npm:socket.io@2.0.1
4const express = require('express');
5const http = require('http');
6const { Server } = require('socket.io');
7
8const app = express();
9const server = http.createServer(app);
10const io = new Server(server);
11
12const v2_server = require('http').Server(app);
13const iov2 = require('socket.io-v2')(v2_server);
14io.on('connection', (socket) => {
15 // DEBUG
16 console.log("V4 data received");
17})
18
19iov2.on('connection', (socket) => {
20 // DEBUG
21 console.log("V2 data received");
22})
23app.get("", (req, res)=>{
24res.sendFile(__dirname + '/static/test.html')
25})
26
27
28server.listen(conn_port, () => {
29 console.log("V4 server started.")
30})
31
32
33v2_server.listen(v2_conn_port, () => {
34 console.log("V2 server started.")
35})
36
and they do appear running as both logs are printed.
However, as I try to connect to the localhost on both ports, while I do see the html page provided, the socket.io connection doesn't seem to go through, as neither of the "Vx data received" logs appear (and buttons on the test page used to exchange data are unresponsive).
I'm pretty sure there might be a plethora of misplaced or misunderstood things here, as I'm just moving my first steps on node.js and web servers in general, so thanks in advance for the help and the patience!
ANSWER
Answered 2022-Jan-28 at 07:27You cannot create two servers on the same HTTP port. However you can do something like this without attaching it to HTTP port:
1npm install socket.io@^4.4.1
2
3npm install socket.io-v2@npm:socket.io@2.0.1
4const express = require('express');
5const http = require('http');
6const { Server } = require('socket.io');
7
8const app = express();
9const server = http.createServer(app);
10const io = new Server(server);
11
12const v2_server = require('http').Server(app);
13const iov2 = require('socket.io-v2')(v2_server);
14io.on('connection', (socket) => {
15 // DEBUG
16 console.log("V4 data received");
17})
18
19iov2.on('connection', (socket) => {
20 // DEBUG
21 console.log("V2 data received");
22})
23app.get("", (req, res)=>{
24res.sendFile(__dirname + '/static/test.html')
25})
26
27
28server.listen(conn_port, () => {
29 console.log("V4 server started.")
30})
31
32
33v2_server.listen(v2_conn_port, () => {
34 console.log("V2 server started.")
35})
36const { Server } = require('socket.io');
37const firstServer = new Server();
38firstServer.listen(3000);
39
40const secondServer = new Server();
41firstServer.listen(4000);
42
QUESTION
Azure Front Door to Website on IIS VM Host
Asked 2022-Jan-25 at 19:14I've got an Azure Front Door that has been set up to link to 2 Windows VM's running IIS, I'm trying to add a Frontend Domain that I can then use to access websites on the VM's. Azure Frontend Domain
Then I have the backend pool which links to the 2 servers. Back End Pool
I then have a route to the web servers, which should (as far as I can tell) just forward the request onwards. Routing Rule
Then I have my web servers which I have set up the bindings on for the website Website Bindings
However whenever I try to browse to the website I just see the IIS landing page rather than the website I have setup. How do I get to my actual website?
ANSWER
Answered 2022-Jan-17 at 05:10if you get the IIS landing page it means the traffic is forwarded correctly from the AFD, your problem is likely with the local IIS setup like the default page or something like that.
QUESTION
Why is my non blocking raw sockets program running so slowly?
Asked 2022-Jan-11 at 20:59I have a program which uses PF_PACKET
raw sockets to send TCP SYN
packets to a list of web servers. The program reads in a file which has an IPv4 address on each line of a web server. The program is the beginnings of an attempt to connect to multiple servers in a high performance manner. However, currently the program is only sending about 10 packets/second. This despite the program using non blocking socket. It should be running orders of magnitude faster. Any ideas why it could be running so slowly.
I include a full code listing below. Warning - the code is quite long. That's because it takes a surprisingly large amount of code to get the IP and MAC address of the gateway router. The good news is you can skip all the functions before main because they just do the necessary work of getting the IP and MAC address of the router as well as the local IP address. Anyway, here's the code:
1#include <sys/types.h>
2#include <sys/socket.h>
3#include <arpa/inet.h>
4#include <linux/if_packet.h>
5#include <net/ethernet.h>
6#include <stdlib.h>
7#include <stdio.h>
8#include <errno.h>
9#include <string.h>
10#include <sys/mman.h>
11#include <unistd.h>
12#include <sys/ioctl.h>
13#include <net/if.h>
14#include <netinet/tcp.h> //Provides declarations for tcp header
15#include <netinet/ip.h> //Provides declarations for ip header
16#include <netinet/ether.h>
17#include <ifaddrs.h>
18#include <asm/types.h>
19#include <linux/if_ether.h>
20//#include <linux/if_arp.h>
21#include <arpa/inet.h> //htons etc
22#include <time.h>
23#include <linux/rtnetlink.h>
24#include <sys/resource.h>
25
26#define PROTO_ARP 0x0806
27#define ETH2_HEADER_LEN 14
28#define HW_TYPE 1
29#define MAC_LENGTH 6
30#define IPV4_LENGTH 4
31#define ARP_REQUEST 0x01
32#define ARP_REPLY 0x02
33#define BUF_SIZE 60
34#define MAX_CONNECTIONS 10000
35
36#define debug(x...) printf(x);printf("\n");
37#define info(x...) printf(x);printf("\n");
38#define warn(x...) printf(x);printf("\n");
39#define err(x...) printf(x);printf("\n");
40
41static char * str_devname= NULL;
42static int mode_loss = 0;
43static int c_packet_sz = 150;
44static int c_buffer_sz = 1024*8;
45static int c_buffer_nb = 1024;
46static int c_sndbuf_sz = 0;
47static int c_send_mask = 127;
48static int c_error = 0;
49static int c_mtu = 0;
50static int mode_thread = 0;
51
52volatile int fd_socket;
53volatile int data_offset = 0;
54volatile struct tpacket_hdr * ps_header_start;
55volatile struct sockaddr_ll *ps_sockaddr = NULL;
56volatile int shutdown_flag = 0;
57int done = 0;
58struct tpacket_req s_packet_req;
59unsigned char buffer[BUF_SIZE];
60struct arp_header *arp_resp = (struct arp_header *) (buffer + ETH2_HEADER_LEN);
61char ifname[512];
62char ip[512];
63
64/*
65 96 bit (12 bytes) pseudo header needed for tcp header checksum calculation
66*/
67struct pseudo_header
68{
69 u_int32_t source_address;
70 u_int32_t dest_address;
71 u_int8_t placeholder;
72 u_int8_t protocol;
73 u_int16_t tcp_length;
74};
75
76
77struct arp_header {
78 unsigned short hardware_type;
79 unsigned short protocol_type;
80 unsigned char hardware_len;
81 unsigned char protocol_len;
82 unsigned short opcode;
83 unsigned char sender_mac[MAC_LENGTH];
84 unsigned char sender_ip[IPV4_LENGTH];
85 unsigned char target_mac[MAC_LENGTH];
86 unsigned char target_ip[IPV4_LENGTH];
87};
88
89int rtnl_receive(int fd, struct msghdr *msg, int flags)
90{
91 int len;
92
93 do {
94 len = recvmsg(fd, msg, flags);
95 } while (len < 0 && (errno == EINTR || errno == EAGAIN));
96
97 if (len < 0) {
98 perror("Netlink receive failed");
99 return -errno;
100 }
101
102 if (len == 0) {
103 perror("EOF on netlink");
104 return -ENODATA;
105 }
106
107 return len;
108}
109
110static int rtnl_recvmsg(int fd, struct msghdr *msg, char **answer)
111{
112 struct iovec *iov = msg->msg_iov;
113 char *buf;
114 int len;
115
116 iov->iov_base = NULL;
117 iov->iov_len = 0;
118
119 len = rtnl_receive(fd, msg, MSG_PEEK | MSG_TRUNC);
120
121 if (len < 0) {
122 return len;
123 }
124
125 buf = malloc(len);
126
127 if (!buf) {
128 perror("malloc failed");
129 return -ENOMEM;
130 }
131
132 iov->iov_base = buf;
133 iov->iov_len = len;
134
135 len = rtnl_receive(fd, msg, 0);
136
137 if (len < 0) {
138 free(buf);
139 return len;
140 }
141
142 *answer = buf;
143
144 return len;
145}
146
147void parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
148{
149 memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
150
151 while (RTA_OK(rta, len)) {
152 if (rta->rta_type <= max) {
153 tb[rta->rta_type] = rta;
154 }
155
156 rta = RTA_NEXT(rta,len);
157 }
158}
159
160static inline int rtm_get_table(struct rtmsg *r, struct rtattr **tb)
161{
162 __u32 table = r->rtm_table;
163
164 if (tb[RTA_TABLE]) {
165 table = *(__u32 *)RTA_DATA(tb[RTA_TABLE]);
166 }
167
168 return table;
169}
170
171void print_route(struct nlmsghdr* nl_header_answer)
172{
173 struct rtmsg* r = NLMSG_DATA(nl_header_answer);
174 int len = nl_header_answer->nlmsg_len;
175 struct rtattr* tb[RTA_MAX+1];
176 int table;
177 char buf[256];
178
179 len -= NLMSG_LENGTH(sizeof(*r));
180
181 if (len < 0) {
182 perror("Wrong message length");
183 return;
184 }
185
186 parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
187
188 table = rtm_get_table(r, tb);
189
190 if (r->rtm_family != AF_INET && table != RT_TABLE_MAIN) {
191 return;
192 }
193
194 if (tb[RTA_DST]) {
195 if ((r->rtm_dst_len != 24) && (r->rtm_dst_len != 16)) {
196 return;
197 }
198
199 printf("%s/%u ", inet_ntop(r->rtm_family, RTA_DATA(tb[RTA_DST]), buf, sizeof(buf)), r->rtm_dst_len);
200
201 } else if (r->rtm_dst_len) {
202 printf("0/%u ", r->rtm_dst_len);
203 } else {
204 printf("default ");
205 }
206
207 if (tb[RTA_GATEWAY]) {
208 printf("via %s", inet_ntop(r->rtm_family, RTA_DATA(tb[RTA_GATEWAY]), buf, sizeof(buf)));
209 strcpy(ip, inet_ntop(r->rtm_family, RTA_DATA(tb[RTA_GATEWAY]), buf, sizeof(buf)));
210 }
211
212 if (tb[RTA_OIF]) {
213 char if_nam_buf[IF_NAMESIZE];
214 int ifidx = *(__u32 *)RTA_DATA(tb[RTA_OIF]);
215
216 printf(" dev %s", if_indextoname(ifidx, if_nam_buf));
217 }
218
219 if (tb[RTA_GATEWAY] && tb[RTA_OIF]) {
220 char if_nam_buf[IF_NAMESIZE];
221 int ifidx = *(__u32 *)RTA_DATA(tb[RTA_OIF]);
222
223 strcpy(ifname, if_indextoname(ifidx, if_nam_buf));
224 }
225
226 if (tb[RTA_SRC]) {
227 printf("src %s", inet_ntop(r->rtm_family, RTA_DATA(tb[RTA_SRC]), buf, sizeof(buf)));
228 }
229
230 printf("\n");
231}
232
233int open_netlink()
234{
235 struct sockaddr_nl saddr;
236
237 int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
238
239 if (sock < 0) {
240 perror("Failed to open netlink socket");
241 return -1;
242 }
243
244 memset(&saddr, 0, sizeof(saddr));
245
246 saddr.nl_family = AF_NETLINK;
247 saddr.nl_pid = getpid();
248
249 if (bind(sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
250 perror("Failed to bind to netlink socket");
251 close(sock);
252 return -1;
253 }
254
255 return sock;
256}
257
258int do_route_dump_requst(int sock)
259{
260 struct {
261 struct nlmsghdr nlh;
262 struct rtmsg rtm;
263 } nl_request;
264
265 nl_request.nlh.nlmsg_type = RTM_GETROUTE;
266 nl_request.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
267 nl_request.nlh.nlmsg_len = sizeof(nl_request);
268 nl_request.nlh.nlmsg_seq = time(NULL);
269 nl_request.rtm.rtm_family = AF_INET;
270
271 return send(sock, &nl_request, sizeof(nl_request), 0);
272}
273
274int get_route_dump_response(int sock)
275{
276 struct sockaddr_nl nladdr;
277 struct iovec iov;
278 struct msghdr msg = {
279 .msg_name = &nladdr,
280 .msg_namelen = sizeof(nladdr),
281 .msg_iov = &iov,
282 .msg_iovlen = 1,
283 };
284
285 char *buf;
286 int dump_intr = 0;
287
288 int status = rtnl_recvmsg(sock, &msg, &buf);
289
290 struct nlmsghdr *h = (struct nlmsghdr *)buf;
291 int msglen = status;
292
293 printf("Main routing table IPv4\n");
294
295 while (NLMSG_OK(h, msglen)) {
296 if (h->nlmsg_flags & NLM_F_DUMP_INTR) {
297 fprintf(stderr, "Dump was interrupted\n");
298 free(buf);
299 return -1;
300 }
301
302 if (nladdr.nl_pid != 0) {
303 continue;
304 }
305
306 if (h->nlmsg_type == NLMSG_ERROR) {
307 perror("netlink reported error");
308 free(buf);
309 }
310
311 print_route(h);
312
313 h = NLMSG_NEXT(h, msglen);
314 }
315
316 free(buf);
317
318 return status;
319}
320
321
322/*
323 * Converts struct sockaddr with an IPv4 address to network byte order uin32_t.
324 * Returns 0 on success.
325 */
326int int_ip4(struct sockaddr *addr, uint32_t *ip)
327{
328 if (addr->sa_family == AF_INET) {
329 struct sockaddr_in *i = (struct sockaddr_in *) addr;
330 *ip = i->sin_addr.s_addr;
331 return 0;
332 } else {
333 err("Not AF_INET");
334 return 1;
335 }
336}
337
338/*
339 * Formats sockaddr containing IPv4 address as human readable string.
340 * Returns 0 on success.
341 */
342int format_ip4(struct sockaddr *addr, char *out)
343{
344 if (addr->sa_family == AF_INET) {
345 struct sockaddr_in *i = (struct sockaddr_in *) addr;
346 const char *ip = inet_ntoa(i->sin_addr);
347 if (!ip) {
348 return -2;
349 } else {
350 strcpy(out, ip);
351 return 0;
352 }
353 } else {
354 return -1;
355 }
356}
357
358/*
359 * Writes interface IPv4 address as network byte order to ip.
360 * Returns 0 on success.
361 */
362int get_if_ip4(int fd, const char *ifname, uint32_t *ip) {
363 int err = -1;
364 struct ifreq ifr;
365 memset(&ifr, 0, sizeof(struct ifreq));
366 if (strlen(ifname) > (IFNAMSIZ - 1)) {
367 err("Too long interface name");
368 goto out;
369 }
370
371 strcpy(ifr.ifr_name, ifname);
372 if (ioctl(fd, SIOCGIFADDR, &ifr) == -1) {
373 perror("SIOCGIFADDR");
374 goto out;
375 }
376
377 if (int_ip4(&ifr.ifr_addr, ip)) {
378 goto out;
379 }
380 err = 0;
381out:
382 return err;
383}
384
385/*
386 * Sends an ARP who-has request to dst_ip
387 * on interface ifindex, using source mac src_mac and source ip src_ip.
388 */
389int send_arp(int fd, int ifindex, const unsigned char *src_mac, uint32_t src_ip, uint32_t dst_ip)
390{
391 int err = -1;
392 unsigned char buffer[BUF_SIZE];
393 memset(buffer, 0, sizeof(buffer));
394
395 struct sockaddr_ll socket_address;
396 socket_address.sll_family = AF_PACKET;
397 socket_address.sll_protocol = htons(ETH_P_ARP);
398 socket_address.sll_ifindex = ifindex;
399 socket_address.sll_hatype = htons(ARPHRD_ETHER);
400 socket_address.sll_pkttype = (PACKET_BROADCAST);
401 socket_address.sll_halen = MAC_LENGTH;
402 socket_address.sll_addr[6] = 0x00;
403 socket_address.sll_addr[7] = 0x00;
404
405 struct ethhdr *send_req = (struct ethhdr *) buffer;
406 struct arp_header *arp_req = (struct arp_header *) (buffer + ETH2_HEADER_LEN);
407 int index;
408 ssize_t ret, length = 0;
409
410 //Broadcast
411 memset(send_req->h_dest, 0xff, MAC_LENGTH);
412
413 //Target MAC zero
414 memset(arp_req->target_mac, 0x00, MAC_LENGTH);
415
416 //Set source mac to our MAC address
417 memcpy(send_req->h_source, src_mac, MAC_LENGTH);
418 memcpy(arp_req->sender_mac, src_mac, MAC_LENGTH);
419 memcpy(socket_address.sll_addr, src_mac, MAC_LENGTH);
420
421 /* Setting protocol of the packet */
422 send_req->h_proto = htons(ETH_P_ARP);
423
424 /* Creating ARP request */
425 arp_req->hardware_type = htons(HW_TYPE);
426 arp_req->protocol_type = htons(ETH_P_IP);
427 arp_req->hardware_len = MAC_LENGTH;
428 arp_req->protocol_len = IPV4_LENGTH;
429 arp_req->opcode = htons(ARP_REQUEST);
430
431 debug("Copy IP address to arp_req");
432 memcpy(arp_req->sender_ip, &src_ip, sizeof(uint32_t));
433 memcpy(arp_req->target_ip, &dst_ip, sizeof(uint32_t));
434
435 ret = sendto(fd, buffer, 42, 0, (struct sockaddr *) &socket_address, sizeof(socket_address));
436 if (ret == -1) {
437 perror("sendto():");
438 goto out;
439 }
440 err = 0;
441out:
442 return err;
443}
444
445/*
446 * Gets interface information by name:
447 * IPv4
448 * MAC
449 * ifindex
450 */
451int get_if_info(const char *ifname, uint32_t *ip, char *mac, int *ifindex)
452{
453 debug("get_if_info for %s", ifname);
454 int err = -1;
455 struct ifreq ifr;
456 int sd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ARP));
457 if (sd <= 0) {
458 perror("socket()");
459 goto out;
460 }
461 if (strlen(ifname) > (IFNAMSIZ - 1)) {
462 printf("Too long interface name, MAX=%i\n", IFNAMSIZ - 1);
463 goto out;
464 }
465
466 strcpy(ifr.ifr_name, ifname);
467
468 //Get interface index using name
469 if (ioctl(sd, SIOCGIFINDEX, &ifr) == -1) {
470 perror("SIOCGIFINDEX");
471 goto out;
472 }
473 *ifindex = ifr.ifr_ifindex;
474 printf("interface index is %d\n", *ifindex);
475
476 //Get MAC address of the interface
477 if (ioctl(sd, SIOCGIFHWADDR, &ifr) == -1) {
478 perror("SIOCGIFINDEX");
479 goto out;
480 }
481
482 //Copy mac address to output
483 memcpy(mac, ifr.ifr_hwaddr.sa_data, MAC_LENGTH);
484
485 if (get_if_ip4(sd, ifname, ip)) {
486 goto out;
487 }
488 debug("get_if_info OK");
489
490 err = 0;
491out:
492 if (sd > 0) {
493 debug("Clean up temporary socket");
494 close(sd);
495 }
496 return err;
497}
498
499/*
500 * Creates a raw socket that listens for ARP traffic on specific ifindex.
501 * Writes out the socket's FD.
502 * Return 0 on success.
503 */
504int bind_arp(int ifindex, int *fd)
505{
506 debug("bind_arp: ifindex=%i", ifindex);
507 int ret = -1;
508
509 // Submit request for a raw socket descriptor.
510 *fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ARP));
511 if (*fd < 1) {
512 perror("socket()");
513 goto out;
514 }
515
516 debug("Binding to ifindex %i", ifindex);
517 struct sockaddr_ll sll;
518 memset(&sll, 0, sizeof(struct sockaddr_ll));
519 sll.sll_family = AF_PACKET;
520 sll.sll_ifindex = ifindex;
521 if (bind(*fd, (struct sockaddr*) &sll, sizeof(struct sockaddr_ll)) < 0) {
522 perror("bind");
523 goto out;
524 }
525
526 ret = 0;
527out:
528 if (ret && *fd > 0) {
529 debug("Cleanup socket");
530 close(*fd);
531 }
532 return ret;
533}
534
535/*
536 * Reads a single ARP reply from fd.
537 * Return 0 on success.
538 */
539int read_arp(int fd)
540{
541 debug("read_arp");
542 int ret = -1;
543 ssize_t length = recvfrom(fd, buffer, BUF_SIZE, 0, NULL, NULL);
544 int index;
545 if (length == -1) {
546 perror("recvfrom()");
547 goto out;
548 }
549 struct ethhdr *rcv_resp = (struct ethhdr *) buffer;
550 if (ntohs(rcv_resp->h_proto) != PROTO_ARP) {
551 debug("Not an ARP packet");
552 goto out;
553 }
554 if (ntohs(arp_resp->opcode) != ARP_REPLY) {
555 debug("Not an ARP reply");
556 goto out;
557 }
558 debug("received ARP len=%ld", length);
559 struct in_addr sender_a;
560 memset(&sender_a, 0, sizeof(struct in_addr));
561 memcpy(&sender_a.s_addr, arp_resp->sender_ip, sizeof(uint32_t));
562 debug("Sender IP: %s", inet_ntoa(sender_a));
563
564 debug("Sender MAC: %02X:%02X:%02X:%02X:%02X:%02X",
565 arp_resp->sender_mac[0],
566 arp_resp->sender_mac[1],
567 arp_resp->sender_mac[2],
568 arp_resp->sender_mac[3],
569 arp_resp->sender_mac[4],
570 arp_resp->sender_mac[5]);
571
572 ret = 0;
573
574out:
575 return ret;
576}
577
578/*
579 *
580 * Sample code that sends an ARP who-has request on
581 * interface <ifname> to IPv4 address <ip>.
582 * Returns 0 on success.
583 */
584int test_arping(const char *ifname, const char *ip) {
585 int ret = -1;
586 uint32_t dst = inet_addr(ip);
587 if (dst == 0 || dst == 0xffffffff) {
588 printf("Invalid source IP\n");
589 return 1;
590 }
591
592 int src;
593 int ifindex;
594 char mac[MAC_LENGTH];
595 if (get_if_info(ifname, &src, mac, &ifindex)) {
596 err("get_if_info failed, interface %s not found or no IP set?", ifname);
597 goto out;
598 }
599 int arp_fd;
600 if (bind_arp(ifindex, &arp_fd)) {
601 err("Failed to bind_arp()");
602 goto out;
603 }
604
605 if (send_arp(arp_fd, ifindex, mac, src, dst)) {
606 err("Failed to send_arp");
607 goto out;
608 }
609
610 while(1) {
611 int r = read_arp(arp_fd);
612 if (r == 0) {
613 info("Got reply, break out");
614 break;
615 }
616 }
617
618 ret = 0;
619out:
620 if (arp_fd) {
621 close(arp_fd);
622 arp_fd = 0;
623 }
624 return ret;
625}
626
627unsigned short checksum2(const char *buf, unsigned size)
628{
629 unsigned long long sum = 0;
630 const unsigned long long *b = (unsigned long long *) buf;
631
632 unsigned t1, t2;
633 unsigned short t3, t4;
634
635 /* Main loop - 8 bytes at a time */
636 while (size >= sizeof(unsigned long long))
637 {
638 unsigned long long s = *b++;
639 sum += s;
640 if (sum < s) sum++;
641 size -= 8;
642 }
643
644 /* Handle tail less than 8-bytes long */
645 buf = (const char *) b;
646 if (size & 4)
647 {
648 unsigned s = *(unsigned *)buf;
649 sum += s;
650 if (sum < s) sum++;
651 buf += 4;
652 }
653
654 if (size & 2)
655 {
656 unsigned short s = *(unsigned short *) buf;
657 sum += s;
658 if (sum < s) sum++;
659 buf += 2;
660 }
661
662 if (size)
663 {
664 unsigned char s = *(unsigned char *) buf;
665 sum += s;
666 if (sum < s) sum++;
667 }
668
669 /* Fold down to 16 bits */
670 t1 = sum;
671 t2 = sum >> 32;
672 t1 += t2;
673 if (t1 < t2) t1++;
674 t3 = t1;
675 t4 = t1 >> 16;
676 t3 += t4;
677 if (t3 < t4) t3++;
678
679 return ~t3;
680}
681
682int main( int argc, char ** argv )
683{
684 uint32_t size;
685 size_t len;
686 struct sockaddr_ll my_addr, peer_addr;
687 int i_ifindex;
688 int ec;
689 struct ifreq s_ifr; /* points to one interface returned from ioctl */
690 int tmp;
691 FILE * fp;
692 char server[254];
693 int count = 0;
694 int first_time = 1;
695 int z;
696 int first_mmap = 1;
697
698 #define HWADDR_len 6
699 #define IP_len 4
700 int s,s2,i;
701 struct ifreq ifr,ifr2;
702 int ret = -1;
703 struct rlimit lim;
704
705 if (argc != 2) {
706 printf("Usage: %s <INPUT_FILE>\n", argv[0]);
707 return 1;
708 }
709
710 getrlimit(RLIMIT_NOFILE, &lim);
711 printf("Soft: %d Hard: %d\n", (int)lim.rlim_cur, (int)lim.rlim_max);
712 lim.rlim_cur = lim.rlim_max;
713
714
715 if (setrlimit(RLIMIT_NOFILE, &lim) == -1) {
716 printf("rlimit failed\n");
717 return -1;
718 }
719 getrlimit(RLIMIT_NOFILE, &lim);
720 printf("New Soft: %d New Hard: %d\n", (int)lim.rlim_cur, (int)lim.rlim_max);
721
722 int nl_sock = open_netlink();
723
724 if (do_route_dump_requst(nl_sock) < 0) {
725 perror("Failed to perfom request");
726 close(nl_sock);
727 return -1;
728 }
729
730 get_route_dump_response(nl_sock);
731
732 close (nl_sock);
733
734 test_arping(ifname, ip);
735
736
737 s = socket(AF_INET, SOCK_DGRAM, 0);
738 s2 = socket(AF_INET, SOCK_DGRAM, 0);
739 strcpy(ifr.ifr_name, ifname);
740 strcpy(ifr2.ifr_name, ifname);
741 ioctl(s, SIOCGIFHWADDR, &ifr);
742 ioctl(s2, SIOCGIFADDR, &ifr2);
743 struct sockaddr_in* ipaddr = (struct sockaddr_in*)&ifr2.ifr_addr;
744 close(s);
745
746 fp = fopen(argv[1], "r");
747 if (!fp)
748 exit(EXIT_FAILURE);
749
750
751 while (!done)
752 {
753 fd_socket = socket(PF_PACKET, SOCK_RAW|SOCK_NONBLOCK, htons(ETH_P_ALL));
754 if(fd_socket == -1)
755 {
756 perror("socket");
757 return EXIT_FAILURE;
758 }
759
760 /* clear structure */
761 memset(&my_addr, 0, sizeof(struct sockaddr_ll));
762 my_addr.sll_family = PF_PACKET;
763 my_addr.sll_protocol = htons(ETH_P_ALL);
764
765 str_devname = ifname;
766 //strcpy (str_devname, ifname);
767
768 /* initialize interface struct */
769 strncpy (s_ifr.ifr_name, str_devname, sizeof(s_ifr.ifr_name));
770
771 /* Get the broad cast address */
772 ec = ioctl(fd_socket, SIOCGIFINDEX, &s_ifr);
773 if(ec == -1)
774 {
775 perror("iotcl");
776 return EXIT_FAILURE;
777 }
778
779 /* update with interface index */
780 i_ifindex = s_ifr.ifr_ifindex;
781
782 s_ifr.ifr_mtu = 7200;
783 /* update the mtu through ioctl */
784 ec = ioctl(fd_socket, SIOCSIFMTU, &s_ifr);
785 if(ec == -1)
786 {
787 perror("iotcl");
788 return EXIT_FAILURE;
789 }
790
791 /* set sockaddr info */
792 memset(&my_addr, 0, sizeof(struct sockaddr_ll));
793 my_addr.sll_family = AF_PACKET;
794 my_addr.sll_protocol = ETH_P_ALL;
795 my_addr.sll_ifindex = i_ifindex;
796
797 /* bind port */
798 if (bind(fd_socket, (struct sockaddr *)&my_addr, sizeof(struct sockaddr_ll)) == -1)
799 {
800 perror("bind");
801 return EXIT_FAILURE;
802 }
803
804 /* prepare Tx ring request */
805 s_packet_req.tp_block_size = c_buffer_sz;
806 s_packet_req.tp_frame_size = c_buffer_sz;
807 s_packet_req.tp_block_nr = c_buffer_nb;
808 s_packet_req.tp_frame_nr = c_buffer_nb;
809
810 /* calculate memory to mmap in the kernel */
811 size = s_packet_req.tp_block_size * s_packet_req.tp_block_nr;
812
813 /* set packet loss option */
814 tmp = mode_loss;
815 if (setsockopt(fd_socket, SOL_PACKET, PACKET_LOSS, (char *)&tmp, sizeof(tmp))<0)
816 {
817 perror("setsockopt: PACKET_LOSS");
818 return EXIT_FAILURE;
819 }
820
821 /* send TX ring request */
822 if (setsockopt(fd_socket, SOL_PACKET, PACKET_TX_RING, (char *)&s_packet_req, sizeof(s_packet_req))<0)
823 {
824 perror("setsockopt: PACKET_TX_RING");
825 return EXIT_FAILURE;
826 }
827
828 /* change send buffer size */
829 if(c_sndbuf_sz) {
830 printf("send buff size = %d\n", c_sndbuf_sz);
831 if (setsockopt(fd_socket, SOL_SOCKET, SO_SNDBUF, &c_sndbuf_sz, sizeof(c_sndbuf_sz))< 0)
832 {
833 perror("getsockopt: SO_SNDBUF");
834 return EXIT_FAILURE;
835 }
836 }
837
838 /* get data offset */
839 data_offset = TPACKET_HDRLEN - sizeof(struct sockaddr_ll);
840
841 /* mmap Tx ring buffers memory */
842 ps_header_start = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd_socket, 0);
843 if (ps_header_start == (void*)-1)
844 {
845 perror("mmap");
846 return EXIT_FAILURE;
847 }
848
849
850 int i,j;
851 int i_index = 0;
852 char * data;
853 int first_loop = 1;
854 struct tpacket_hdr * ps_header;
855 int ec_send = 0;
856
857 int i_index_start = i_index;
858
859 ps_header = ((struct tpacket_hdr *)((void *)ps_header_start + (c_buffer_sz*i_index)));
860 data = ((void*) ps_header) + data_offset;
861 //Datagram to represent the packet
862 char datagram[4096] , source_ip[32] , *pseudogram;
863
864 //zero out the packet buffer
865 memset (datagram, 0, 4096);
866
867 //Ethernet header
868 struct ether_header *eh = (struct ether_header *) datagram;
869
870 //IP header
871 struct iphdr *iph = (struct iphdr *) (datagram + sizeof (struct ether_header));
872
873 //TCP header
874 struct tcphdr *tcph = (struct tcphdr *) (datagram + sizeof (struct ether_header) + sizeof (struct ip));
875 struct sockaddr_in sin;
876 struct pseudo_header psh;
877
878 //some address resolution
879 strcpy(source_ip , inet_ntoa(ipaddr->sin_addr));
880 sin.sin_family = AF_INET;
881 sin.sin_port = htons(80);
882 if (fscanf(fp, "%253s", server) == 1)
883 sin.sin_addr.s_addr = inet_addr (server);
884 else
885 {
886 done = 1;
887 break;
888 }
889
890 //Fill in the Ethernet Header
891 eh->ether_dhost[0] = arp_resp->sender_mac[0];
892 eh->ether_dhost[1] = arp_resp->sender_mac[1];
893 eh->ether_dhost[2] = arp_resp->sender_mac[2];
894 eh->ether_dhost[3] = arp_resp->sender_mac[3];
895 eh->ether_dhost[4] = arp_resp->sender_mac[4];
896 eh->ether_dhost[5] = arp_resp->sender_mac[5];
897
898 memcpy(eh->ether_shost, ifr.ifr_hwaddr.sa_data, HWADDR_len);
899 eh->ether_type = htons(0x0800);
900
901 //Fill in the IP Header
902 iph->ihl = 5;
903 iph->version = 4;
904 iph->tos = 0;
905 iph->tot_len = htons(sizeof (struct iphdr) + sizeof (struct tcphdr));
906 iph->id = htons (54321); //Id of this packet
907 iph->frag_off = 0;
908 iph->ttl = 255;
909 iph->protocol = IPPROTO_TCP;
910 iph->check = 0; //Set to 0 before calculating checksum
911 iph->saddr = inet_addr ( source_ip );
912 iph->daddr = sin.sin_addr.s_addr;
913
914 //Ip checksum
915 iph->check = checksum2 (datagram + sizeof (struct ether_header), sizeof (struct iphdr));
916
917 //TCP Header
918 tcph->source = htons (1234);
919 tcph->dest = htons (80);
920 tcph->seq = 0;
921 tcph->ack_seq = 0;
922 tcph->doff = 5; //tcp header size
923 tcph->fin=0;
924 tcph->syn=1;
925 tcph->rst=0;
926 tcph->psh=0;
927 tcph->ack=0;
928 tcph->urg=0;
929 tcph->window = htons (5840); // maximum allowed window size
930 tcph->check = 0; //leave checksum 0 now, filled later by pseudo header
931 tcph->urg_ptr = 0;
932
933 //Now the TCP checksum
934 psh.source_address = inet_addr( source_ip );
935 psh.dest_address = sin.sin_addr.s_addr;
936 psh.placeholder = 0;
937 psh.protocol = IPPROTO_TCP;
938 psh.tcp_length = htons(sizeof(struct tcphdr));
939
940 int psize = sizeof(struct pseudo_header) + sizeof(struct tcphdr);
941 pseudogram = malloc(psize);
942
943 memcpy(pseudogram , (char*) &psh , sizeof (struct pseudo_header));
944 memcpy(pseudogram + sizeof(struct pseudo_header) , tcph , sizeof(struct tcphdr));
945
946 tcph->check = checksum2(pseudogram , psize);
947
948 memcpy(data, datagram, (sizeof(struct ether_header) + sizeof(struct iphdr) + sizeof(struct tcphdr)));
949 free(pseudogram);
950 len = sizeof(struct ether_header) + sizeof(struct iphdr) + sizeof(struct tcphdr);
951
952 i_index ++;
953 if(i_index >= c_buffer_nb)
954 {
955 i_index = 0;
956 first_loop = 0;
957 }
958
959 /* update packet len */
960 //ps_header->tp_len = c_packet_sz;
961 ps_header->tp_len = len;
962 /* set header flag to USER (trigs xmit)*/
963 ps_header->tp_status = TP_STATUS_SEND_REQUEST;
964
965 //int ec_send;
966 static int total=0;
967 //int blocking = 1;
968
969 /* send all buffers with TP_STATUS_SEND_REQUEST */
970 /* Wait end of transfer */
971 //ec_send = sendto(fd_socket,NULL,0,(blocking? 0 : MSG_DONTWAIT),(struct sockaddr *) ps_sockaddr,sizeof(struct sockaddr_ll));
972 ec_send = sendto(fd_socket,NULL,len,MSG_DONTWAIT,(struct sockaddr *) ps_sockaddr,sizeof(struct sockaddr_ll));
973
974 if(ec_send < 0) {
975 perror("sendto");
976 }
977 else if ( ec_send == 0 ) {
978 /* nothing to do => schedule : useful if no SMP */
979 printf("Sleeping\n");
980 usleep(0);
981 }
982 else {
983 total += ec_send/(len);
984 printf("send %d packets (+%d bytes)\n",total, ec_send);
985 fflush(0);
986 }
987 //ps_header_start = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd_socket, 0);
988 if (munmap(ps_header_start, size) == -1)
989 {
990 perror("munmap");
991 exit(EXIT_FAILURE);
992 }
993
994 close(fd_socket);
995 }
996 return 1;
997}
998
Here is the output of strace -c
for just over 5,000 packets sent:
1#include <sys/types.h>
2#include <sys/socket.h>
3#include <arpa/inet.h>
4#include <linux/if_packet.h>
5#include <net/ethernet.h>
6#include <stdlib.h>
7#include <stdio.h>
8#include <errno.h>
9#include <string.h>
10#include <sys/mman.h>
11#include <unistd.h>
12#include <sys/ioctl.h>
13#include <net/if.h>
14#include <netinet/tcp.h> //Provides declarations for tcp header
15#include <netinet/ip.h> //Provides declarations for ip header
16#include <netinet/ether.h>
17#include <ifaddrs.h>
18#include <asm/types.h>
19#include <linux/if_ether.h>
20//#include <linux/if_arp.h>
21#include <arpa/inet.h> //htons etc
22#include <time.h>
23#include <linux/rtnetlink.h>
24#include <sys/resource.h>
25
26#define PROTO_ARP 0x0806
27#define ETH2_HEADER_LEN 14
28#define HW_TYPE 1
29#define MAC_LENGTH 6
30#define IPV4_LENGTH 4
31#define ARP_REQUEST 0x01
32#define ARP_REPLY 0x02
33#define BUF_SIZE 60
34#define MAX_CONNECTIONS 10000
35
36#define debug(x...) printf(x);printf("\n");
37#define info(x...) printf(x);printf("\n");
38#define warn(x...) printf(x);printf("\n");
39#define err(x...) printf(x);printf("\n");
40
41static char * str_devname= NULL;
42static int mode_loss = 0;
43static int c_packet_sz = 150;
44static int c_buffer_sz = 1024*8;
45static int c_buffer_nb = 1024;
46static int c_sndbuf_sz = 0;
47static int c_send_mask = 127;
48static int c_error = 0;
49static int c_mtu = 0;
50static int mode_thread = 0;
51
52volatile int fd_socket;
53volatile int data_offset = 0;
54volatile struct tpacket_hdr * ps_header_start;
55volatile struct sockaddr_ll *ps_sockaddr = NULL;
56volatile int shutdown_flag = 0;
57int done = 0;
58struct tpacket_req s_packet_req;
59unsigned char buffer[BUF_SIZE];
60struct arp_header *arp_resp = (struct arp_header *) (buffer + ETH2_HEADER_LEN);
61char ifname[512];
62char ip[512];
63
64/*
65 96 bit (12 bytes) pseudo header needed for tcp header checksum calculation
66*/
67struct pseudo_header
68{
69 u_int32_t source_address;
70 u_int32_t dest_address;
71 u_int8_t placeholder;
72 u_int8_t protocol;
73 u_int16_t tcp_length;
74};
75
76
77struct arp_header {
78 unsigned short hardware_type;
79 unsigned short protocol_type;
80 unsigned char hardware_len;
81 unsigned char protocol_len;
82 unsigned short opcode;
83 unsigned char sender_mac[MAC_LENGTH];
84 unsigned char sender_ip[IPV4_LENGTH];
85 unsigned char target_mac[MAC_LENGTH];
86 unsigned char target_ip[IPV4_LENGTH];
87};
88
89int rtnl_receive(int fd, struct msghdr *msg, int flags)
90{
91 int len;
92
93 do {
94 len = recvmsg(fd, msg, flags);
95 } while (len < 0 && (errno == EINTR || errno == EAGAIN));
96
97 if (len < 0) {
98 perror("Netlink receive failed");
99 return -errno;
100 }
101
102 if (len == 0) {
103 perror("EOF on netlink");
104 return -ENODATA;
105 }
106
107 return len;
108}
109
110static int rtnl_recvmsg(int fd, struct msghdr *msg, char **answer)
111{
112 struct iovec *iov = msg->msg_iov;
113 char *buf;
114 int len;
115
116 iov->iov_base = NULL;
117 iov->iov_len = 0;
118
119 len = rtnl_receive(fd, msg, MSG_PEEK | MSG_TRUNC);
120
121 if (len < 0) {
122 return len;
123 }
124
125 buf = malloc(len);
126
127 if (!buf) {
128 perror("malloc failed");
129 return -ENOMEM;
130 }
131
132 iov->iov_base = buf;
133 iov->iov_len = len;
134
135 len = rtnl_receive(fd, msg, 0);
136
137 if (len < 0) {
138 free(buf);
139 return len;
140 }
141
142 *answer = buf;
143
144 return len;
145}
146
147void parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
148{
149 memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
150
151 while (RTA_OK(rta, len)) {
152 if (rta->rta_type <= max) {
153 tb[rta->rta_type] = rta;
154 }
155
156 rta = RTA_NEXT(rta,len);
157 }
158}
159
160static inline int rtm_get_table(struct rtmsg *r, struct rtattr **tb)
161{
162 __u32 table = r->rtm_table;
163
164 if (tb[RTA_TABLE]) {
165 table = *(__u32 *)RTA_DATA(tb[RTA_TABLE]);
166 }
167
168 return table;
169}
170
171void print_route(struct nlmsghdr* nl_header_answer)
172{
173 struct rtmsg* r = NLMSG_DATA(nl_header_answer);
174 int len = nl_header_answer->nlmsg_len;
175 struct rtattr* tb[RTA_MAX+1];
176 int table;
177 char buf[256];
178
179 len -= NLMSG_LENGTH(sizeof(*r));
180
181 if (len < 0) {
182 perror("Wrong message length");
183 return;
184 }
185
186 parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
187
188 table = rtm_get_table(r, tb);
189
190 if (r->rtm_family != AF_INET && table != RT_TABLE_MAIN) {
191 return;
192 }
193
194 if (tb[RTA_DST]) {
195 if ((r->rtm_dst_len != 24) && (r->rtm_dst_len != 16)) {
196 return;
197 }
198
199 printf("%s/%u ", inet_ntop(r->rtm_family, RTA_DATA(tb[RTA_DST]), buf, sizeof(buf)), r->rtm_dst_len);
200
201 } else if (r->rtm_dst_len) {
202 printf("0/%u ", r->rtm_dst_len);
203 } else {
204 printf("default ");
205 }
206
207 if (tb[RTA_GATEWAY]) {
208 printf("via %s", inet_ntop(r->rtm_family, RTA_DATA(tb[RTA_GATEWAY]), buf, sizeof(buf)));
209 strcpy(ip, inet_ntop(r->rtm_family, RTA_DATA(tb[RTA_GATEWAY]), buf, sizeof(buf)));
210 }
211
212 if (tb[RTA_OIF]) {
213 char if_nam_buf[IF_NAMESIZE];
214 int ifidx = *(__u32 *)RTA_DATA(tb[RTA_OIF]);
215
216 printf(" dev %s", if_indextoname(ifidx, if_nam_buf));
217 }
218
219 if (tb[RTA_GATEWAY] && tb[RTA_OIF]) {
220 char if_nam_buf[IF_NAMESIZE];
221 int ifidx = *(__u32 *)RTA_DATA(tb[RTA_OIF]);
222
223 strcpy(ifname, if_indextoname(ifidx, if_nam_buf));
224 }
225
226 if (tb[RTA_SRC]) {
227 printf("src %s", inet_ntop(r->rtm_family, RTA_DATA(tb[RTA_SRC]), buf, sizeof(buf)));
228 }
229
230 printf("\n");
231}
232
233int open_netlink()
234{
235 struct sockaddr_nl saddr;
236
237 int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
238
239 if (sock < 0) {
240 perror("Failed to open netlink socket");
241 return -1;
242 }
243
244 memset(&saddr, 0, sizeof(saddr));
245
246 saddr.nl_family = AF_NETLINK;
247 saddr.nl_pid = getpid();
248
249 if (bind(sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
250 perror("Failed to bind to netlink socket");
251 close(sock);
252 return -1;
253 }
254
255 return sock;
256}
257
258int do_route_dump_requst(int sock)
259{
260 struct {
261 struct nlmsghdr nlh;
262 struct rtmsg rtm;
263 } nl_request;
264
265 nl_request.nlh.nlmsg_type = RTM_GETROUTE;
266 nl_request.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
267 nl_request.nlh.nlmsg_len = sizeof(nl_request);
268 nl_request.nlh.nlmsg_seq = time(NULL);
269 nl_request.rtm.rtm_family = AF_INET;
270
271 return send(sock, &nl_request, sizeof(nl_request), 0);
272}
273
274int get_route_dump_response(int sock)
275{
276 struct sockaddr_nl nladdr;
277 struct iovec iov;
278 struct msghdr msg = {
279 .msg_name = &nladdr,
280 .msg_namelen = sizeof(nladdr),
281 .msg_iov = &iov,
282 .msg_iovlen = 1,
283 };
284
285 char *buf;
286 int dump_intr = 0;
287
288 int status = rtnl_recvmsg(sock, &msg, &buf);
289
290 struct nlmsghdr *h = (struct nlmsghdr *)buf;
291 int msglen = status;
292
293 printf("Main routing table IPv4\n");
294
295 while (NLMSG_OK(h, msglen)) {
296 if (h->nlmsg_flags & NLM_F_DUMP_INTR) {
297 fprintf(stderr, "Dump was interrupted\n");
298 free(buf);
299 return -1;
300 }
301
302 if (nladdr.nl_pid != 0) {
303 continue;
304 }
305
306 if (h->nlmsg_type == NLMSG_ERROR) {
307 perror("netlink reported error");
308 free(buf);
309 }
310
311 print_route(h);
312
313 h = NLMSG_NEXT(h, msglen);
314 }
315
316 free(buf);
317
318 return status;
319}
320
321
322/*
323 * Converts struct sockaddr with an IPv4 address to network byte order uin32_t.
324 * Returns 0 on success.
325 */
326int int_ip4(struct sockaddr *addr, uint32_t *ip)
327{
328 if (addr->sa_family == AF_INET) {
329 struct sockaddr_in *i = (struct sockaddr_in *) addr;
330 *ip = i->sin_addr.s_addr;
331 return 0;
332 } else {
333 err("Not AF_INET");
334 return 1;
335 }
336}
337
338/*
339 * Formats sockaddr containing IPv4 address as human readable string.
340 * Returns 0 on success.
341 */
342int format_ip4(struct sockaddr *addr, char *out)
343{
344 if (addr->sa_family == AF_INET) {
345 struct sockaddr_in *i = (struct sockaddr_in *) addr;
346 const char *ip = inet_ntoa(i->sin_addr);
347 if (!ip) {
348 return -2;
349 } else {
350 strcpy(out, ip);
351 return 0;
352 }
353 } else {
354 return -1;
355 }
356}
357
358/*
359 * Writes interface IPv4 address as network byte order to ip.
360 * Returns 0 on success.
361 */
362int get_if_ip4(int fd, const char *ifname, uint32_t *ip) {
363 int err = -1;
364 struct ifreq ifr;
365 memset(&ifr, 0, sizeof(struct ifreq));
366 if (strlen(ifname) > (IFNAMSIZ - 1)) {
367 err("Too long interface name");
368 goto out;
369 }
370
371 strcpy(ifr.ifr_name, ifname);
372 if (ioctl(fd, SIOCGIFADDR, &ifr) == -1) {
373 perror("SIOCGIFADDR");
374 goto out;
375 }
376
377 if (int_ip4(&ifr.ifr_addr, ip)) {
378 goto out;
379 }
380 err = 0;
381out:
382 return err;
383}
384
385/*
386 * Sends an ARP who-has request to dst_ip
387 * on interface ifindex, using source mac src_mac and source ip src_ip.
388 */
389int send_arp(int fd, int ifindex, const unsigned char *src_mac, uint32_t src_ip, uint32_t dst_ip)
390{
391 int err = -1;
392 unsigned char buffer[BUF_SIZE];
393 memset(buffer, 0, sizeof(buffer));
394
395 struct sockaddr_ll socket_address;
396 socket_address.sll_family = AF_PACKET;
397 socket_address.sll_protocol = htons(ETH_P_ARP);
398 socket_address.sll_ifindex = ifindex;
399 socket_address.sll_hatype = htons(ARPHRD_ETHER);
400 socket_address.sll_pkttype = (PACKET_BROADCAST);
401 socket_address.sll_halen = MAC_LENGTH;
402 socket_address.sll_addr[6] = 0x00;
403 socket_address.sll_addr[7] = 0x00;
404
405 struct ethhdr *send_req = (struct ethhdr *) buffer;
406 struct arp_header *arp_req = (struct arp_header *) (buffer + ETH2_HEADER_LEN);
407 int index;
408 ssize_t ret, length = 0;
409
410 //Broadcast
411 memset(send_req->h_dest, 0xff, MAC_LENGTH);
412
413 //Target MAC zero
414 memset(arp_req->target_mac, 0x00, MAC_LENGTH);
415
416 //Set source mac to our MAC address
417 memcpy(send_req->h_source, src_mac, MAC_LENGTH);
418 memcpy(arp_req->sender_mac, src_mac, MAC_LENGTH);
419 memcpy(socket_address.sll_addr, src_mac, MAC_LENGTH);
420
421 /* Setting protocol of the packet */
422 send_req->h_proto = htons(ETH_P_ARP);
423
424 /* Creating ARP request */
425 arp_req->hardware_type = htons(HW_TYPE);
426 arp_req->protocol_type = htons(ETH_P_IP);
427 arp_req->hardware_len = MAC_LENGTH;
428 arp_req->protocol_len = IPV4_LENGTH;
429 arp_req->opcode = htons(ARP_REQUEST);
430
431 debug("Copy IP address to arp_req");
432 memcpy(arp_req->sender_ip, &src_ip, sizeof(uint32_t));
433 memcpy(arp_req->target_ip, &dst_ip, sizeof(uint32_t));
434
435 ret = sendto(fd, buffer, 42, 0, (struct sockaddr *) &socket_address, sizeof(socket_address));
436 if (ret == -1) {
437 perror("sendto():");
438 goto out;
439 }
440 err = 0;
441out:
442 return err;
443}
444
445/*
446 * Gets interface information by name:
447 * IPv4
448 * MAC
449 * ifindex
450 */
451int get_if_info(const char *ifname, uint32_t *ip, char *mac, int *ifindex)
452{
453 debug("get_if_info for %s", ifname);
454 int err = -1;
455 struct ifreq ifr;
456 int sd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ARP));
457 if (sd <= 0) {
458 perror("socket()");
459 goto out;
460 }
461 if (strlen(ifname) > (IFNAMSIZ - 1)) {
462 printf("Too long interface name, MAX=%i\n", IFNAMSIZ - 1);
463 goto out;
464 }
465
466 strcpy(ifr.ifr_name, ifname);
467
468 //Get interface index using name
469 if (ioctl(sd, SIOCGIFINDEX, &ifr) == -1) {
470 perror("SIOCGIFINDEX");
471 goto out;
472 }
473 *ifindex = ifr.ifr_ifindex;
474 printf("interface index is %d\n", *ifindex);
475
476 //Get MAC address of the interface
477 if (ioctl(sd, SIOCGIFHWADDR, &ifr) == -1) {
478 perror("SIOCGIFINDEX");
479 goto out;
480 }
481
482 //Copy mac address to output
483 memcpy(mac, ifr.ifr_hwaddr.sa_data, MAC_LENGTH);
484
485 if (get_if_ip4(sd, ifname, ip)) {
486 goto out;
487 }
488 debug("get_if_info OK");
489
490 err = 0;
491out:
492 if (sd > 0) {
493 debug("Clean up temporary socket");
494 close(sd);
495 }
496 return err;
497}
498
499/*
500 * Creates a raw socket that listens for ARP traffic on specific ifindex.
501 * Writes out the socket's FD.
502 * Return 0 on success.
503 */
504int bind_arp(int ifindex, int *fd)
505{
506 debug("bind_arp: ifindex=%i", ifindex);
507 int ret = -1;
508
509 // Submit request for a raw socket descriptor.
510 *fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ARP));
511 if (*fd < 1) {
512 perror("socket()");
513 goto out;
514 }
515
516 debug("Binding to ifindex %i", ifindex);
517 struct sockaddr_ll sll;
518 memset(&sll, 0, sizeof(struct sockaddr_ll));
519 sll.sll_family = AF_PACKET;
520 sll.sll_ifindex = ifindex;
521 if (bind(*fd, (struct sockaddr*) &sll, sizeof(struct sockaddr_ll)) < 0) {
522 perror("bind");
523 goto out;
524 }
525
526 ret = 0;
527out:
528 if (ret && *fd > 0) {
529 debug("Cleanup socket");
530 close(*fd);
531 }
532 return ret;
533}
534
535/*
536 * Reads a single ARP reply from fd.
537 * Return 0 on success.
538 */
539int read_arp(int fd)
540{
541 debug("read_arp");
542 int ret = -1;
543 ssize_t length = recvfrom(fd, buffer, BUF_SIZE, 0, NULL, NULL);
544 int index;
545 if (length == -1) {
546 perror("recvfrom()");
547 goto out;
548 }
549 struct ethhdr *rcv_resp = (struct ethhdr *) buffer;
550 if (ntohs(rcv_resp->h_proto) != PROTO_ARP) {
551 debug("Not an ARP packet");
552 goto out;
553 }
554 if (ntohs(arp_resp->opcode) != ARP_REPLY) {
555 debug("Not an ARP reply");
556 goto out;
557 }
558 debug("received ARP len=%ld", length);
559 struct in_addr sender_a;
560 memset(&sender_a, 0, sizeof(struct in_addr));
561 memcpy(&sender_a.s_addr, arp_resp->sender_ip, sizeof(uint32_t));
562 debug("Sender IP: %s", inet_ntoa(sender_a));
563
564 debug("Sender MAC: %02X:%02X:%02X:%02X:%02X:%02X",
565 arp_resp->sender_mac[0],
566 arp_resp->sender_mac[1],
567 arp_resp->sender_mac[2],
568 arp_resp->sender_mac[3],
569 arp_resp->sender_mac[4],
570 arp_resp->sender_mac[5]);
571
572 ret = 0;
573
574out:
575 return ret;
576}
577
578/*
579 *
580 * Sample code that sends an ARP who-has request on
581 * interface <ifname> to IPv4 address <ip>.
582 * Returns 0 on success.
583 */
584int test_arping(const char *ifname, const char *ip) {
585 int ret = -1;
586 uint32_t dst = inet_addr(ip);
587 if (dst == 0 || dst == 0xffffffff) {
588 printf("Invalid source IP\n");
589 return 1;
590 }
591
592 int src;
593 int ifindex;
594 char mac[MAC_LENGTH];
595 if (get_if_info(ifname, &src, mac, &ifindex)) {
596 err("get_if_info failed, interface %s not found or no IP set?", ifname);
597 goto out;
598 }
599 int arp_fd;
600 if (bind_arp(ifindex, &arp_fd)) {
601 err("Failed to bind_arp()");
602 goto out;
603 }
604
605 if (send_arp(arp_fd, ifindex, mac, src, dst)) {
606 err("Failed to send_arp");
607 goto out;
608 }
609
610 while(1) {
611 int r = read_arp(arp_fd);
612 if (r == 0) {
613 info("Got reply, break out");
614 break;
615 }
616 }
617
618 ret = 0;
619out:
620 if (arp_fd) {
621 close(arp_fd);
622 arp_fd = 0;
623 }
624 return ret;
625}
626
627unsigned short checksum2(const char *buf, unsigned size)
628{
629 unsigned long long sum = 0;
630 const unsigned long long *b = (unsigned long long *) buf;
631
632 unsigned t1, t2;
633 unsigned short t3, t4;
634
635 /* Main loop - 8 bytes at a time */
636 while (size >= sizeof(unsigned long long))
637 {
638 unsigned long long s = *b++;
639 sum += s;
640 if (sum < s) sum++;
641 size -= 8;
642 }
643
644 /* Handle tail less than 8-bytes long */
645 buf = (const char *) b;
646 if (size & 4)
647 {
648 unsigned s = *(unsigned *)buf;
649 sum += s;
650 if (sum < s) sum++;
651 buf += 4;
652 }
653
654 if (size & 2)
655 {
656 unsigned short s = *(unsigned short *) buf;
657 sum += s;
658 if (sum < s) sum++;
659 buf += 2;
660 }
661
662 if (size)
663 {
664 unsigned char s = *(unsigned char *) buf;
665 sum += s;
666 if (sum < s) sum++;
667 }
668
669 /* Fold down to 16 bits */
670 t1 = sum;
671 t2 = sum >> 32;
672 t1 += t2;
673 if (t1 < t2) t1++;
674 t3 = t1;
675 t4 = t1 >> 16;
676 t3 += t4;
677 if (t3 < t4) t3++;
678
679 return ~t3;
680}
681
682int main( int argc, char ** argv )
683{
684 uint32_t size;
685 size_t len;
686 struct sockaddr_ll my_addr, peer_addr;
687 int i_ifindex;
688 int ec;
689 struct ifreq s_ifr; /* points to one interface returned from ioctl */
690 int tmp;
691 FILE * fp;
692 char server[254];
693 int count = 0;
694 int first_time = 1;
695 int z;
696 int first_mmap = 1;
697
698 #define HWADDR_len 6
699 #define IP_len 4
700 int s,s2,i;
701 struct ifreq ifr,ifr2;
702 int ret = -1;
703 struct rlimit lim;
704
705 if (argc != 2) {
706 printf("Usage: %s <INPUT_FILE>\n", argv[0]);
707 return 1;
708 }
709
710 getrlimit(RLIMIT_NOFILE, &lim);
711 printf("Soft: %d Hard: %d\n", (int)lim.rlim_cur, (int)lim.rlim_max);
712 lim.rlim_cur = lim.rlim_max;
713
714
715 if (setrlimit(RLIMIT_NOFILE, &lim) == -1) {
716 printf("rlimit failed\n");
717 return -1;
718 }
719 getrlimit(RLIMIT_NOFILE, &lim);
720 printf("New Soft: %d New Hard: %d\n", (int)lim.rlim_cur, (int)lim.rlim_max);
721
722 int nl_sock = open_netlink();
723
724 if (do_route_dump_requst(nl_sock) < 0) {
725 perror("Failed to perfom request");
726 close(nl_sock);
727 return -1;
728 }
729
730 get_route_dump_response(nl_sock);
731
732 close (nl_sock);
733
734 test_arping(ifname, ip);
735
736
737 s = socket(AF_INET, SOCK_DGRAM, 0);
738 s2 = socket(AF_INET, SOCK_DGRAM, 0);
739 strcpy(ifr.ifr_name, ifname);
740 strcpy(ifr2.ifr_name, ifname);
741 ioctl(s, SIOCGIFHWADDR, &ifr);
742 ioctl(s2, SIOCGIFADDR, &ifr2);
743 struct sockaddr_in* ipaddr = (struct sockaddr_in*)&ifr2.ifr_addr;
744 close(s);
745
746 fp = fopen(argv[1], "r");
747 if (!fp)
748 exit(EXIT_FAILURE);
749
750
751 while (!done)
752 {
753 fd_socket = socket(PF_PACKET, SOCK_RAW|SOCK_NONBLOCK, htons(ETH_P_ALL));
754 if(fd_socket == -1)
755 {
756 perror("socket");
757 return EXIT_FAILURE;
758 }
759
760 /* clear structure */
761 memset(&my_addr, 0, sizeof(struct sockaddr_ll));
762 my_addr.sll_family = PF_PACKET;
763 my_addr.sll_protocol = htons(ETH_P_ALL);
764
765 str_devname = ifname;
766 //strcpy (str_devname, ifname);
767
768 /* initialize interface struct */
769 strncpy (s_ifr.ifr_name, str_devname, sizeof(s_ifr.ifr_name));
770
771 /* Get the broad cast address */
772 ec = ioctl(fd_socket, SIOCGIFINDEX, &s_ifr);
773 if(ec == -1)
774 {
775 perror("iotcl");
776 return EXIT_FAILURE;
777 }
778
779 /* update with interface index */
780 i_ifindex = s_ifr.ifr_ifindex;
781
782 s_ifr.ifr_mtu = 7200;
783 /* update the mtu through ioctl */
784 ec = ioctl(fd_socket, SIOCSIFMTU, &s_ifr);
785 if(ec == -1)
786 {
787 perror("iotcl");
788 return EXIT_FAILURE;
789 }
790
791 /* set sockaddr info */
792 memset(&my_addr, 0, sizeof(struct sockaddr_ll));
793 my_addr.sll_family = AF_PACKET;
794 my_addr.sll_protocol = ETH_P_ALL;
795 my_addr.sll_ifindex = i_ifindex;
796
797 /* bind port */
798 if (bind(fd_socket, (struct sockaddr *)&my_addr, sizeof(struct sockaddr_ll)) == -1)
799 {
800 perror("bind");
801 return EXIT_FAILURE;
802 }
803
804 /* prepare Tx ring request */
805 s_packet_req.tp_block_size = c_buffer_sz;
806 s_packet_req.tp_frame_size = c_buffer_sz;
807 s_packet_req.tp_block_nr = c_buffer_nb;
808 s_packet_req.tp_frame_nr = c_buffer_nb;
809
810 /* calculate memory to mmap in the kernel */
811 size = s_packet_req.tp_block_size * s_packet_req.tp_block_nr;
812
813 /* set packet loss option */
814 tmp = mode_loss;
815 if (setsockopt(fd_socket, SOL_PACKET, PACKET_LOSS, (char *)&tmp, sizeof(tmp))<0)
816 {
817 perror("setsockopt: PACKET_LOSS");
818 return EXIT_FAILURE;
819 }
820
821 /* send TX ring request */
822 if (setsockopt(fd_socket, SOL_PACKET, PACKET_TX_RING, (char *)&s_packet_req, sizeof(s_packet_req))<0)
823 {
824 perror("setsockopt: PACKET_TX_RING");
825 return EXIT_FAILURE;
826 }
827
828 /* change send buffer size */
829 if(c_sndbuf_sz) {
830 printf("send buff size = %d\n", c_sndbuf_sz);
831 if (setsockopt(fd_socket, SOL_SOCKET, SO_SNDBUF, &c_sndbuf_sz, sizeof(c_sndbuf_sz))< 0)
832 {
833 perror("getsockopt: SO_SNDBUF");
834 return EXIT_FAILURE;
835 }
836 }
837
838 /* get data offset */
839 data_offset = TPACKET_HDRLEN - sizeof(struct sockaddr_ll);
840
841 /* mmap Tx ring buffers memory */
842 ps_header_start = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd_socket, 0);
843 if (ps_header_start == (void*)-1)
844 {
845 perror("mmap");
846 return EXIT_FAILURE;
847 }
848
849
850 int i,j;
851 int i_index = 0;
852 char * data;
853 int first_loop = 1;
854 struct tpacket_hdr * ps_header;
855 int ec_send = 0;
856
857 int i_index_start = i_index;
858
859 ps_header = ((struct tpacket_hdr *)((void *)ps_header_start + (c_buffer_sz*i_index)));
860 data = ((void*) ps_header) + data_offset;
861 //Datagram to represent the packet
862 char datagram[4096] , source_ip[32] , *pseudogram;
863
864 //zero out the packet buffer
865 memset (datagram, 0, 4096);
866
867 //Ethernet header
868 struct ether_header *eh = (struct ether_header *) datagram;
869
870 //IP header
871 struct iphdr *iph = (struct iphdr *) (datagram + sizeof (struct ether_header));
872
873 //TCP header
874 struct tcphdr *tcph = (struct tcphdr *) (datagram + sizeof (struct ether_header) + sizeof (struct ip));
875 struct sockaddr_in sin;
876 struct pseudo_header psh;
877
878 //some address resolution
879 strcpy(source_ip , inet_ntoa(ipaddr->sin_addr));
880 sin.sin_family = AF_INET;
881 sin.sin_port = htons(80);
882 if (fscanf(fp, "%253s", server) == 1)
883 sin.sin_addr.s_addr = inet_addr (server);
884 else
885 {
886 done = 1;
887 break;
888 }
889
890 //Fill in the Ethernet Header
891 eh->ether_dhost[0] = arp_resp->sender_mac[0];
892 eh->ether_dhost[1] = arp_resp->sender_mac[1];
893 eh->ether_dhost[2] = arp_resp->sender_mac[2];
894 eh->ether_dhost[3] = arp_resp->sender_mac[3];
895 eh->ether_dhost[4] = arp_resp->sender_mac[4];
896 eh->ether_dhost[5] = arp_resp->sender_mac[5];
897
898 memcpy(eh->ether_shost, ifr.ifr_hwaddr.sa_data, HWADDR_len);
899 eh->ether_type = htons(0x0800);
900
901 //Fill in the IP Header
902 iph->ihl = 5;
903 iph->version = 4;
904 iph->tos = 0;
905 iph->tot_len = htons(sizeof (struct iphdr) + sizeof (struct tcphdr));
906 iph->id = htons (54321); //Id of this packet
907 iph->frag_off = 0;
908 iph->ttl = 255;
909 iph->protocol = IPPROTO_TCP;
910 iph->check = 0; //Set to 0 before calculating checksum
911 iph->saddr = inet_addr ( source_ip );
912 iph->daddr = sin.sin_addr.s_addr;
913
914 //Ip checksum
915 iph->check = checksum2 (datagram + sizeof (struct ether_header), sizeof (struct iphdr));
916
917 //TCP Header
918 tcph->source = htons (1234);
919 tcph->dest = htons (80);
920 tcph->seq = 0;
921 tcph->ack_seq = 0;
922 tcph->doff = 5; //tcp header size
923 tcph->fin=0;
924 tcph->syn=1;
925 tcph->rst=0;
926 tcph->psh=0;
927 tcph->ack=0;
928 tcph->urg=0;
929 tcph->window = htons (5840); // maximum allowed window size
930 tcph->check = 0; //leave checksum 0 now, filled later by pseudo header
931 tcph->urg_ptr = 0;
932
933 //Now the TCP checksum
934 psh.source_address = inet_addr( source_ip );
935 psh.dest_address = sin.sin_addr.s_addr;
936 psh.placeholder = 0;
937 psh.protocol = IPPROTO_TCP;
938 psh.tcp_length = htons(sizeof(struct tcphdr));
939
940 int psize = sizeof(struct pseudo_header) + sizeof(struct tcphdr);
941 pseudogram = malloc(psize);
942
943 memcpy(pseudogram , (char*) &psh , sizeof (struct pseudo_header));
944 memcpy(pseudogram + sizeof(struct pseudo_header) , tcph , sizeof(struct tcphdr));
945
946 tcph->check = checksum2(pseudogram , psize);
947
948 memcpy(data, datagram, (sizeof(struct ether_header) + sizeof(struct iphdr) + sizeof(struct tcphdr)));
949 free(pseudogram);
950 len = sizeof(struct ether_header) + sizeof(struct iphdr) + sizeof(struct tcphdr);
951
952 i_index ++;
953 if(i_index >= c_buffer_nb)
954 {
955 i_index = 0;
956 first_loop = 0;
957 }
958
959 /* update packet len */
960 //ps_header->tp_len = c_packet_sz;
961 ps_header->tp_len = len;
962 /* set header flag to USER (trigs xmit)*/
963 ps_header->tp_status = TP_STATUS_SEND_REQUEST;
964
965 //int ec_send;
966 static int total=0;
967 //int blocking = 1;
968
969 /* send all buffers with TP_STATUS_SEND_REQUEST */
970 /* Wait end of transfer */
971 //ec_send = sendto(fd_socket,NULL,0,(blocking? 0 : MSG_DONTWAIT),(struct sockaddr *) ps_sockaddr,sizeof(struct sockaddr_ll));
972 ec_send = sendto(fd_socket,NULL,len,MSG_DONTWAIT,(struct sockaddr *) ps_sockaddr,sizeof(struct sockaddr_ll));
973
974 if(ec_send < 0) {
975 perror("sendto");
976 }
977 else if ( ec_send == 0 ) {
978 /* nothing to do => schedule : useful if no SMP */
979 printf("Sleeping\n");
980 usleep(0);
981 }
982 else {
983 total += ec_send/(len);
984 printf("send %d packets (+%d bytes)\n",total, ec_send);
985 fflush(0);
986 }
987 //ps_header_start = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd_socket, 0);
988 if (munmap(ps_header_start, size) == -1)
989 {
990 perror("munmap");
991 exit(EXIT_FAILURE);
992 }
993
994 close(fd_socket);
995 }
996 return 1;
997}
998% time seconds usecs/call calls errors syscall
999------ ----------- ----------- --------- --------- ----------------
1000 48.11 3.962165 395 10012 setsockopt
1001 16.69 1.374748 274 5014 mmap
1002 14.85 1.222565 244 5007 munmap
1003 10.91 0.898695 179 5016 close
1004 3.15 0.259055 25 10022 ioctl
1005 2.04 0.167613 33 5016 socket
1006 1.70 0.139623 27 5008 sendto
1007 1.41 0.116430 23 5025 write
1008 1.14 0.093826 18 5008 bind
1009 0.01 0.000505 26 19 read
1010 0.00 0.000000 0 4 mprotect
1011 0.00 0.000000 0 3 brk
1012 0.00 0.000000 0 4 pread64
1013 0.00 0.000000 0 3 1 access
1014 0.00 0.000000 0 1 getpid
1015 0.00 0.000000 0 1 recvfrom
1016 0.00 0.000000 0 2 recvmsg
1017 0.00 0.000000 0 1 execve
1018 0.00 0.000000 0 2 1 arch_prctl
1019 0.00 0.000000 0 1 set_tid_address
1020 0.00 0.000000 0 3 openat
1021 0.00 0.000000 0 4 newfstatat
1022 0.00 0.000000 0 1 set_robust_list
1023 0.00 0.000000 0 4 prlimit64
1024 0.00 0.000000 0 1 getrandom
1025------ ----------- ----------- --------- --------- ----------------
1026100.00 8.235225 149 55182 2 total
1027
ANSWER
Answered 2022-Jan-11 at 20:59If I follow the code correctly, you're redoing a ton of work for every IP address that doesn't need to be redone. Every time through the main loop you're:
- creating a new packet socket
- binding it
- setting up a tx packet ring buffer
- mmap'ing it
- sending a single packet
- unmapping
- closing the socket
That's a huge amount of work you're causing the system to do for one packet.
You should only create one packet socket at the beginning, set up the tx buffer and mmap once, and leave it open until the program is done. You can send any number of packets through the interface without closing/re-opening.
This is why your top time users are setsockopt
, mmap
, unmap
, etc. All of those operations are heavy in the kernel.
Also, the point of PACKET_TX_RING
is that you can set up a large buffer and create one packet after another within the buffer without making a send
system call for each packet. By using the packet header's tp_status
field you're telling the kernel that this frame is ready to be sent. You then advance your pointer within the ring buffer to the next available slot and build another packet. When you have no more packets to build (or you've filled the available space in the buffer [i.e. wrapped around to your oldest still-in-flight frame]), you can then make one send/sendto
call to tell the kernel to go look at your buffer and (start) sending all those packets.
You can then start building more packets (being careful to ensure they are not still in use by the kernel -- through the tp_status
field).
That said, if this were a project I were doing, I would simplify a lot - at least for the first pass: create a packet socket, bind it to the interface, build packets one at a time, and use send
once per frame (i.e. not bothering with PACKET_TX_RING
). If (and only if) performance requirements are so tight that it needs to send faster would I bother setting up and using the ring buffer. I doubt you'll need that. This should go a ton faster without the excess setsockopt
and mmap
calls.
Finally, a non-blocking socket is only useful if you have something else to do while you're waiting. In this case, if you have the socket set to be non-blocking and the packet can't be sent because the call would block, the send
call will fail and if you don't do something about that (enqueue the packet somewhere, and retry later, say), the packet will be lost. In this program, I can't see any benefit whatsoever to using a non-blocking socket. If the socket blocks, it's because the device transmit queue is full. After that, there's no point in you continuing to produce packets to be sent, you won't be able send those packets either. Much simpler to just block at that point until the queue drains.
Community Discussions contain sources that include Stack Exchange Network
Tutorials and Learning Resources in Web Servers
Tutorials and Learning Resources are not available at this moment for Web Servers