Why Nginx implement ip_hash load balancing method with these 3 primes - nginx

I notice that Nginx selected 3 primes, 89, 113 and 6271, to implement the ip_hash load balancing method, why these 3 primes?
Is it more fair than just % number of servers?
$ factor 89 113 6271
89: 89
113: 113
6271: 6271
// https://github.com/nginx/nginx/blob/4bf4650f2f10f7bbacfe7a33da744f18951d416d/src/http/modules/ngx_http_upstream_ip_hash_module.c
static ngx_int_t
ngx_http_upstream_init_ip_hash_peer(ngx_http_request_t *r,
ngx_http_upstream_srv_conf_t *us)
{
// ...
ngx_http_upstream_ip_hash_peer_data_t *iphp;
iphp = ngx_palloc(r->pool, sizeof(ngx_http_upstream_ip_hash_peer_data_t));
// ...
iphp->hash = 89;
// ...
}
static ngx_int_t
ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t *pc, void *data)
{
// ...
for ( ;; ) {
for (i = 0; i < (ngx_uint_t) iphp->addrlen; i++) {
hash = (hash * 113 + iphp->addr[i]) % 6271;
}
// ...
}
// ...
iphp->hash = hash;
}
As the document said, "The first three octets of the client IPv4 address, or the entire IPv6 address, are used as a hashing key.", So let there be a IPv4 address, iphp->addrlen = 3, and iphp->addr[0] is the first octet of the IPv4 address, iphp->addr[1] is the second one, ...

Related

How to parse IP address in P4

I have a basic task to connect some nodes to switch and let them communicate only with even-to-even and odd-to-odd IP addresses.
Scenario topology:
The starting point is an access network with full L2 connectivity based on a <DestMAC,OutputPort> table implemented on P4 switch.
Goal
Write a P4 code that creates two network slices, one enabling communication only between nodes with even IP addresses
and the other enabling communication only between nodes with odd IP addresses
header ipv4_t {
bit<4> version;
bit<4> ihl;
bit<8> diffserv;
bit<16> totalLen;
bit<16> identification;
bit<3> flags;
bit<13> fragOffset;
bit<8> ttl;
bit<8> protocol;
bit<16> hdrChecksum;
ip4Addr_t srcAddr;
ip4Addr_t dstAddr;
}
struct headers {
ethernet_t ethernet;
ipv4_t ipv4; //tay
}
/**SOME CODE*/
/*************************************************************************
************** I N G R E S S P R O C E S S I N G *******************
*************************************************************************/
control MyIngress(inout headers hdr,
inout metadata meta,
inout standard_metadata_t standard_metadata) {
action drop() {
mark_to_drop(standard_metadata);
}
action check_ip_odd_even(){
//TODO:
}
action forward_to_port(bit<9> egress_port) {
standard_metadata.egress_spec = egress_port;
}
table dmac_forward {
key = {
hdr.ethernet.dstAddr: exact;
}
actions = {
//ipv4_forward;
forward_to_port;
drop;
}
size = 8;
default_action = drop;
}
apply {
// if(hdr.ipv4.srcAddr & 1 == 1){
// //it's odd
// //dmac_forward.apply();
// }
// else {
// // it's even
// dmac_forward.apply();
// }
//10.0.0.13 vs 10.0.0.11
if (hdr.ipv4.srcAddr == 0x0a00000D && hdr.ipv4.dstAddr == 0x0a00000b){
dmac_forward.apply();
}
}
}
I tried to and with 1 so if it's 1 I would say it's odd but my solution didn't work. I also tried with exactly given IP addresses but this is not the general solution.
Any suggestion, please?

How to implement a TCP server that receives and sends data in two processes?

I am trying to implement a TCP server using C in Linux. I want this server to accept incoming data forever from multiple clients and at the same time send some data back to each connected client in every 3 seconds.
My problem is I don't know how to properly do send() in a different process than the one handling the client.
What I am doing is at the beginning of the program do a fork() and do
while (1) {
sleep(3);
// compute and `send()` data to each connected peers
}
in child process, do
sock = create_socket();
while (1) {
client_sock = accept_connection(sock);
if (fork() == 0) {
close(sock);
handle_client(client_sock);
exit(0);
}
close(client_sock);
// clean up zombies
}
in parent process. handle_client() is simply recv() data in a infinite loop. Because send() and recv() are executed in different processes, I couldn't use the socket file descriptors to send() in parent process. What do I need to do in the parent process to do the send()?
You have three levels of processes, a parent, a child, and many grandchildren. Get rid of these levels, and do not fork at all; instead using an event-driven model in a single process.
In rough pseudo-code (translate to your preferred language):
listening_fd = create_socket();
EventQueueOfSomeKind q; // kqueue()-style
q.add_or_update_event(listening_fd, EVFILT_READ, EV_ENABLE);
q.add_or_update_event(3, EVFILT_TIMER, EV_ENABLE, NOTE_SECONDS);
FDToContextMapOfSomeKind context_map;
EventVector event_vector; // vector of kevent-like things
while (1) {
q.wait_for_events(&event_vector); // kevent()-style
foreach e <- event_vector {
switch (e.type) {
case EVFILT_READ:
if (listening_fd == e.fd) {
client_sock = accept_connection(e.fd, SOCK_NONBLOCK);
q.add_or_update_event(client_sock, EVFILT_READ, EV_ENABLE);
q.add_or_update_event(client_sock, EVFILT_WRITE, EV_DISABLE);
context_map.add_new_context(client_socket);
} else {
// Must be one of the client sockets
if (e.flags & EV_EOF) {
context_map.remove_context(e.fd);
q.remove_event(e.fd, EVFILT_READ);
q.remove_event(e.fd, EVFILT_WRITE);
close(e.fd);
} else {
recv(e.fd, buffer);
handle_client_input(&context_map[e.fd], buffer);
}
}
break;
case EVFILT_WRITE:
if (has_queued_output(context_map[e.fd])) {
send(e.fd, pull_queued_output(&context_map[e.fd]));
} else {
q.add_or_update_event(client_sock, EVFILT_WRITE, EV_DISABLE);
}
break;
case EVFILT_TIMER:
foreach client_sock,context <- context_map {
push_queued_output(&context, computed_data(context));
q.add_or_update_event(client_sock, EVFILT_WRITE, EV_ENABLE);
}
break;
}
}
}
I have glossed over partial send()s and recv()s, write-side shutdown, and all error handling but this is the general idea.
Further reading
https://github.com/mheily/libkqueue
Jonathan Lemon. kqueue. OpenBSD System Calls Manual.
Jonathan Lemon. kqueue. Darwin BSD Calls Manual. Apple corporation.
This is a solution using Linux epoll and timerfd (error handling is omitted):
int start_timer(unsigned int interval) {
int tfd;
struct itimerspec tspec;
tspec.it_value.tv_sec = 1;
tspec.it_value.tv_nsec = 0;
tspec.it_interval.tv_sec = 3;
tspec.it_interval.tv_nsec = 0;
tfd = timerfd_create(CLOCK_MONOTONIC, 0);
timerfd_settime(tfd, TFD_TIMER_ABSTIME, &tspec, NULL);
return tfd;
}
void epset_add(int epfd, int fd, uint32_t events)
{
struct epoll_event ev;
ev.data.fd = fd;
ev.events = events;
epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev);
}
int main()
{
int epfd, tfd, sock, nfds, i;
struct epoll_event events[MAX_EVENTS];
/* create new epoll instance */
epfd = epoll_create1(0);
tfd = start_timer(TIMER_INTERVAL);
/* socket(), bind() and listen() omitted in create_socket() */
sock = create_socket(PORT_NUMBER);
/* add sock and tfd to epoll set */
epset_add(epfd, tfd, EPOLLIN);
epset_add(epfd, sock, EPOLLIN | EPOLLET);
for (;;) {
for (i = 0; i < nfds; ++i) {
if (events[i].data.fd == tfd) {
/* handle timer notification, it's run
periodically with interval TIMER_INTERVAL */
} else if (events[i].data.fd == sock) {
/* accept() incoming connections,
set non-blocking,
and add new connection sockets to epoll set */
} else {
/* recv() from connection sockets and handle */
}
}
}
}
This program was helpful https://github.com/eklitzke/epollet/blob/master/poll.c and I added timerfd to the epoll set so the server keeps listening and receiving data and at the same time can send data to the clients periodically.

Extension unknown: DER encoded OCTET string error in generated certificate

I have created a SSL certificate using acme client acme4j: https://github.com/shred/acme4j.
But while I'm generating a self signed certificate I'm facing an exception while parsing it. Here is the my generated certificate:
{Version: V3
Subject: T=spid: yuz8xxz
Signature Algorithm: SHA256withRSA, OID = 1.2.840.113549.1.1.11
Key: Sun RSA public key, 2048 bits
modulus:
public exponent: 65537
Validity: [From: Mon Apr 10 17:56:36 IST 2017,
To: Mon Apr 17 17:56:36 IST 2017]
Issuer: T=spid: yuz8xxz
SerialNumber: [ 015b57d4 807c]
Certificate Extensions: 1
[1]: ObjectId: 1.3.6.1.5.5.7.1.26 Criticality=false
**Extension unknown: DER encoded OCTET string =**
0000: 04 23 30 21 A0 12 16 07 79 75 7A 38 78 78 7A 16 .#0!....yuz8xxz.
0010: 07 79 75 7A 38 78 78 7A A1 0B 16 06 31 32 33 34 .yuz8xxz....1234
0020: 35 36 02 01 01 56...
]
Algorithm: [SHA256withRSA]
Signature:
]
}
Acme4j code uses a java.security.cert.X509Certificate class. The toString() method of this class (when using Sun's default provider) is generating this "extension unknown" output (according to the corresponding code).
So, in order to parse it correctly (get a formatted output), you'll probably have to change acme4j's code (or write your own), including the code to parse this extension.
In my tests (Java 7 and BouncyCastle 1.56), I created a wrapper to X509Certificate and created a format method based on BouncyCastle's code (I copied the most part and just added code for TNAuthorizationList extension). The code below is not optimal (poor exception handling and some deprecated classes), but you can get an idea.
import org.bouncycastle.asn1.*;
import org.bouncycastle.asn1.misc.*;
import org.bouncycastle.asn1.util.ASN1Dump;
import org.bouncycastle.asn1.x509.*;
import org.bouncycastle.util.encoders.Hex;
public class CertificateWrapper {
private X509Certificate cert;
public CertificateWrapper(X509Certificate cert) {
this.cert = cert;
}
public String format() throws Exception {
StringBuffer buf = new StringBuffer();
String nl = System.getProperty("line.separator");
buf.append(" [0] Version: ").append(this.cert.getVersion()).append(nl);
buf.append(" SerialNumber: ").append(this.cert.getSerialNumber()).append(nl);
buf.append(" IssuerDN: ").append(this.cert.getIssuerDN().toString()).append(nl);
buf.append(" Start Date: ").append(this.cert.getNotBefore()).append(nl);
buf.append(" Final Date: ").append(this.cert.getNotAfter()).append(nl);
buf.append(" SubjectDN: ").append(this.cert.getSubjectDN().toString()).append(nl);
buf.append(" Public Key: ").append(this.cert.getPublicKey()).append(nl);
buf.append(" Signature Algorithm: ").append(this.cert.getSigAlgName()).append(nl);
byte[] sig = this.cert.getSignature();
buf.append(" Signature: ").append(new String(Hex.encode(sig, 0, 20))).append(nl);
for (int i = 20; i < sig.length; i += 20) {
if (i < sig.length - 20) {
buf.append(" ").append(new String(Hex.encode(sig, i, 20))).append(nl);
} else {
buf.append(" ").append(new String(Hex.encode(sig, i, sig.length - i))).append(nl);
}
}
TBSCertificateStructure tbs = TBSCertificateStructure.getInstance(ASN1Sequence.fromByteArray(cert.getTBSCertificate()));
X509Extensions extensions = tbs.getExtensions();
if (extensions != null) {
Enumeration e = extensions.oids();
if (e.hasMoreElements()) {
buf.append(" Extensions: \n");
}
while (e.hasMoreElements()) {
ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier) e.nextElement();
X509Extension ext = extensions.getExtension(oid);
if (ext.getValue() != null) {
byte[] octs = ext.getValue().getOctets();
ASN1InputStream dIn = new ASN1InputStream(octs);
buf.append(" critical(").append(ext.isCritical()).append(") ");
try {
if (oid.equals(Extension.basicConstraints)) {
buf.append(BasicConstraints.getInstance((ASN1Sequence) dIn.readObject())).append(nl);
} else if (oid.equals(Extension.keyUsage)) {
buf.append(KeyUsage.getInstance((DERBitString) dIn.readObject())).append(nl);
} else if (oid.equals(MiscObjectIdentifiers.netscapeCertType)) {
buf.append(new NetscapeCertType((DERBitString) dIn.readObject())).append(nl);
} else if (oid.equals(MiscObjectIdentifiers.netscapeRevocationURL)) {
buf.append(new NetscapeRevocationURL((DERIA5String) dIn.readObject())).append(nl);
} else if (oid.equals(MiscObjectIdentifiers.verisignCzagExtension)) {
buf.append(new VerisignCzagExtension((DERIA5String) dIn.readObject())).append(nl);
//*********************************************************
// *** HERE: code to handle TNAuthorizationList ***
//*********************************************************
} else if (oid.equals(TNAuthorizationList.TN_AUTH_LIST_OID)) {
buf.append(TNAuthorizationList.getInstance((ASN1Sequence) dIn.readObject())).append(nl);
} else {
buf.append(oid.getId());
buf.append(" value = ").append(ASN1Dump.dumpAsString(dIn.readObject())).append(nl);
}
} catch (Exception ex) {
buf.append(oid.getId());
buf.append(" value = ").append("*****").append(nl);
}
} else {
buf.append(nl);
}
}
}
return buf.toString();
}
}
Then, you just use this wrapper instead of X509Certificate:
X509Certificate cert = ...
System.out.println("Certificate " + new CertificateWrapper(cert).format());
The output format is different from SUN's default provider, but you can customize it to get what you need.
PS: This question is a complement (or "sequel") to this one. The OP's code was provided here and TNAuthorizationList class is in the accepted answer. But as this question is a different issue (related, but different), it was kept as a separate question.
1.3.6.1.5.5.7.1.26 seems to be the OID for a Telephony Number (TN) Authorization List, which is only defined in a draft document (https://datatracker.ietf.org/doc/draft-ietf-stir-certificates/); BouncyCastle likely doesn't have a pretty printer for it, so it's showing you the raw encoded payload.
While I'm not an expert in telephony, I'm pretty sure that ('yuz8xxz', 'yuz8xxz') isn't a valid Service Provider Code list, and '123456'-'123456' is not a valid telephone number range. So it's pretty unclear what you're looking for with this certificate extension, and I'd be highly surprised if Let's Encrypt signed off on it.

How to convert IP address to byte array using D?

I was looking at the std.socket and I was able to do the following to check the IP type but I can't find a way to get the byte array for the IP address.
auto results = getAddressInfo(ipaddress, AddressInfoFlags.NUMERICHOST);
if (results.length && results[0].family == AddressFamily.INET) {
writeln("IPv4 : " ~ results[0].address.toAddrString());
return 4;
}
else if (results.length && results[0].family == AddressFamily.INET6) {
writeln("IPv6 : " ~ results[0].address.toAddrString());
return 6;
}
I saw a couple of classes like InternetAddress and Internet6Address which have the addr() property that returns the byte array but I am not sure how to go from my code above to these 2 classes.
One way to do this is to get a pointer to the core.sys.posix.sys.socket.sockaddr structure using the Address.name.
Something like auto saddr_ptr = results[0].address.name; would do. Then you can extract the data you need by casting this pointer to a pointer of appropriate type (depending on the address family).
Here is a modified example from getAddress() documentation which uses sockaddr* to give you addresses as uint32_t values and conver them to ubyte[4] arrays:
module main;
import std.stdio;
import std.socket;
import std.c.linux.socket: sockaddr_in, in_addr;
void main(string[] args) {
// auto results = getAddressInfo("www.digitalmars.com");
try {
Address[] addresses = getAddress("dlang.org", 80);
writefln(" %d addresses found.", addresses.length);
foreach (int i, Address a; addresses) {
writefln(" Address %d:", i+1);
writefln(" IP address: %s", a.toAddrString());
writefln(" Hostname: %s", a.toHostNameString());
writefln(" Port: %s", a.toPortString());
writefln(" Service name: %s", a.toServiceNameString());
auto saddr_ptr = a.name;
auto in_ptr = *(cast(sockaddr_in*) saddr_ptr);
// let's convert it to ubyte[4] so we can access individual
// parts of the IPv4 address.
writeln(cast(ubyte[4])(in_ptr.sin_addr));
}
} catch (SocketException e) {
writefln(" Lookup error: %s", e.msg);
}
// Lets the user press <Return> before program returns
stdin.readln();
}
Output:
3 addresses found.
Address 1:
IP address: 162.217.114.56
Hostname: digitalmars.com
Port: 80
Service name: http
[162, 217, 114, 56]
Address 2:
IP address: 162.217.114.56
Hostname: digitalmars.com
Port: 80
Service name: http
[162, 217, 114, 56]
Address 3:
IP address: 162.217.114.56
Hostname: digitalmars.com
Port: 80
Service name: http
[162, 217, 114, 56]

localhost request packet not recognized by sharppcap?

I did asp.net program using mvc 4. I deployed in iis server as localhost; I want track HTTP Packet so I used SharpPcap.
Here is full code...
namespace CaseStudy
{
class Program
{
static void Main(string[] args)
{
var parmenter = SharpPcap.CaptureDeviceList.Instance;
/*If no device exists, print error */
if (parmenter.Count < 1)
{
Console.WriteLine("No device found on this machine");
return;
}
int i = 0;
Console.WriteLine("Choose Your Devices :");
Console.WriteLine("----------------------");
foreach (PcapDevice dev in parmenter)
{
/* Device Description */
Console.WriteLine("{0}] {1} [MAC:{2}]", i, dev.Interface.FriendlyName, dev.Interface.MacAddress);
i++;
}
Console.WriteLine("----------------------");
//Extract a device from the list
int deviceIndex = -1;
do
{
Console.WriteLine("Enter Your Choice :");
deviceIndex = int.Parse(Console.ReadLine());
} while (!(deviceIndex < parmenter.Count && deviceIndex >= -1));
ICaptureDevice device = parmenter[deviceIndex];
//Register our handler function to the 'packet arrival' event
//device.PcapOnPacketArrival += new SharpPcap.PacketArrivalEventHandler();
device.OnPacketArrival += new SharpPcap.PacketArrivalEventHandler(device_OnPacketArrival);
//Open the device for capturing
//true -- means promiscuous mode
//1000 -- means a read wait of 1000ms
device.Open(DeviceMode.Promiscuous, 1000);
device.Filter = "ip and tcp";
Console.WriteLine("-- Listenning on {0}, hit 'Enter' to stop...", device.MacAddress);
//Start the capturing process
device.StartCapture();
//Wait for 'Enter' from the user.
Console.ReadLine();
//Stop the capturing process
device.StopCapture();
//Close the capturing device
device.Close();
}
private static void device_OnPacketArrival(object sender, CaptureEventArgs e)
{
DateTime time = e.Packet.Timeval.Date;
int len = e.Packet.Data.Length;
byte[] data = e.Packet.Data;
//var packet = TcpPacket.ParsePacket(e.Packet.LinkLayerType, e.Packet.Data);
//Console.WriteLine(e.Packet.LinkLayerType.ToString());
Packet pack = Packet.ParsePacket(e.Packet.LinkLayerType, e.Packet.Data);
if (pack is PacketDotNet.EthernetPacket)
{
var eth = pack.Extract(typeof(EthernetPacket)) as EthernetPacket;
if (len > 100)
{
Console.WriteLine("ETHERNET/INTERNET/HTTP PACKET");
//Console.WriteLine(HttpServerUtility.UrlTokenEncode(eth.Bytes));
Console.WriteLine("{0}-{1}" , eth.DestinationHwAddress, eth.SourceHwAddress);
//Console.WriteLine(eth.PayloadPacket.PayloadPacket.PrintHex());
Console.WriteLine(System.Text.Encoding.UTF8.GetString(eth.Bytes));
}
}
if (pack is PacketDotNet.TcpPacket) {
var tcp = pack.Extract (typeof(TcpPacket)) as TcpPacket;
if (len > 100)
{
//Console.WriteLine("[{0}:{1}:{2}:{3}][{4}][{5}]",
//time.Hour, time.Minute, time.Second, time.Millisecond,
//len, Stringfy.RawPacketToHex(data));
Console.WriteLine("TCP PACKET");
Console.WriteLine(tcp.PrintHex());
//Console.WriteLine(arp.SenderHardwareAddress);
}
}
if (pack is PacketDotNet.InternetPacket)
{
var inet = pack.Extract(typeof(InternetPacket)) as InternetPacket;
if (len > 100)
{
//Console.WriteLine("[{0}:{1}:{2}:{3}][{4}][{5}]",
//time.Hour, time.Minute, time.Second, time.Millisecond,
//len, Stringfy.RawPacketToHex(data));
Console.WriteLine("INTERNET PACKET");
Console.WriteLine(inet.PrintHex());
//Console.WriteLine(arp.SenderHardwareAddress);
}
}
if (pack is PacketDotNet.IpPacket)
{
var ip = pack.Extract(typeof(IpPacket)) as IpPacket;
if (len > 100)
{
//Console.WriteLine("[{0}:{1}:{2}:{3}][{4}][{5}]",
//time.Hour, time.Minute, time.Second, time.Millisecond,
//len, Stringfy.RawPacketToHex(data));
Console.WriteLine("IP PACKET");
Console.WriteLine(ip.PrintHex());
//Console.WriteLine(arp.SenderHardwareAddress);
}
}
}
}
}
this code caputuring remote server http packet like google, stackoverflow, facebook communicate with my system.
However i want track packet with my system only as a localhost.
using
any one can help? please...
It's impossible.
Why?
SharpPcap uses WinPcap and WinPcap extends the system driver to capture packets. According to WinPcap faq Question 13, it's not possible to capture the loopbackdevice aka localhost. It's a limitation of Windows not WinPcap.

Resources