Jaehyuk-Lee / DFAssist

FFXIV Duty Finder & F.A.T.E. Assist
https://jaehyuk-lee.github.io/DFAssist
The Unlicense
48 stars 23 forks source link

Network class extender #15

Open lalafellsleep opened 5 years ago

lalafellsleep commented 5 years ago

pcapdotnet을 사용해 ffxiv에 이미 다른 프로그램이 후킹하거나 네트워크 포트를 붙잡아도 관계없이 패킷을 읽을 수 있게 도와줍니다. AlexanderPrime이라는 비공개 프로젝트에서 동일한 로직으로 별개 클래스로 사용하지만, 네트워크 관련 패킷을 제대로 잡지 못하는 문제가 있다는 커밋을 봐서 네트워크 클래스를 오버라이드하여 사용할 수 있도록 수정했습니다. 참고하여 해당 문제가 해결되기를 바랍니다.

    public class PcapNetwork : Network
    {
        private object lockAnalyse = new object();

        public WinPcapDeviceList Devices = WinPcapDeviceList.Instance;
        public List<IPEndPoint> IP { get; private set; }
        public WinPcapDevice Device;

        public PcapNetwork() : base()
        {

        }

        public override void StartCapture(Process Process)
        {
            base.Process = Process;
            Task.Factory.StartNew(() =>
            {
                try
                {
                    if (IsRunning) return;
                    if (Device != null) return;
                    UpdateGameConnections(Process);
                    if (connections.Count < 2) return;
                    var filter = "";
                    var ilist = new List<string>();
                    foreach(var i in connections)
                    {
                        ilist.Add(string.Format("(ip src host {0} and ip dst host {1})", i.LocalEndPoint.Address, i.RemoteEndPoint.Address));
                        ilist.Add(string.Format("(ip src host {0} and ip dst host {1})", i.RemoteEndPoint.Address, i.LocalEndPoint.Address));
                    }
                    filter = string.Join(" or ", ilist);
                    Debug.WriteLine(filter);
                    RegisterToFirewall();
                    foreach(var device in Devices)
                    {
                        foreach(PcapAddress addr in device.Addresses)
                        {
                            if (addr.Addr != null && addr.Addr.ipAddress != null)
                            {
                                if (IPlist.Contains(addr.Addr.ipAddress))
                                {
                                    Device = device;
                                    Device.OnPacketArrival += OnPacketRecive;
                                    Device.Open(DeviceMode.Promiscuous);
                                    Device.KernelBufferSize = 0x20000;
                                    Device.Mode = CaptureMode.Packets;
                                    if (Device.Filter != null)
                                        Device.Filter = Device.Filter + " or " + filter;
                                    else
                                        Device.Filter = filter;
                                    Device.NonBlockingMode = true;
                                    Device.StartCapture();
                                    Console.WriteLine("[NETW] SharpPcap is running now...");
                                }
                            }
                        }
                    }
                    IsRunning = true;
                }
                catch(Exception ex)
                {
                    Debug.WriteLine(ex.Message);
                    Debug.WriteLine(ex.GetBaseException().ToString());
                }
            });
        }

        private void OnPacketRecive(object sender, CaptureEventArgs e)
        {
            var time = e.Packet.Timeval.Date;
            var len = e.Packet.Data.Length;

            var packet = Packet.ParsePacket(e.Device.LinkType, e.Packet.Data);
            IpPacket ipPacket = packet.Extract(typeof(IpPacket)) as IpPacket;
            TcpPacket tcpPacket = packet.Extract(typeof(TcpPacket)) as TcpPacket;

            IPEndPoint sourceEndPoint = new IPEndPoint(ipPacket.SourceAddress, tcpPacket.SourcePort);
            IPEndPoint destinationEndPoint = new IPEndPoint(ipPacket.DestinationAddress, tcpPacket.DestinationPort);

            Connection connection = new Connection() { LocalEndPoint = sourceEndPoint, RemoteEndPoint = destinationEndPoint };
            Connection reverseConnection = new Connection() { LocalEndPoint = destinationEndPoint, RemoteEndPoint = sourceEndPoint };

            if (!(connections.Contains(connection) || connections.Contains(reverseConnection))) return;

            lock (lockAnalyse)
            {
                AnalyseFFXIVPacket(tcpPacket.PayloadData, sourceEndPoint, destinationEndPoint);
            }
        }
    }
lalafellsleep commented 5 years ago

기존 네트워크 클래스에서 게임 커넥션 얻어오는 부분에 127.0.0.1 을 Address로 가진 항목을 제외시켜주시면 패킷 데이터를 정확하게 받아올 수 있습니다.

Jaehyuk-Lee commented 5 years ago

if(!remote.Address.Equals(IPAddress.Parse("127.0.0.1"))) // 원격 IP가 127.0.0.1(자기 컴퓨터)이면 커넥션 목록에 추가하지 않음

Network.cs에 GetConnections 함수에 이렇게 필터링을 오늘 추가했는데 이걸론 안되나요?

Jaehyuk-Lee commented 5 years ago

다름이 아니라 위에 올려주신 코드에는 127.0.0.1을 필터링하는 내용이 없는 것 같은데 위에 올려주신 코드와 어떤 연관이 있나 궁금해서요.

lalafellsleep commented 5 years ago

@Jaehyuk-Lee 일부 프로그램 (XIVHunt, 또는 동종의 네트워크 클래스를 사용한 다른 프로그램. ACT등)이 파판의 네트워크를 잡지 못하거나 임무찾기 도우미가 잡지 못하는 상황도 발생하더군요.

지금 추가하신 필터링 코드가 적용된 것에 사용하시면 관련된 네트워크 문제가 대부분 해결될 것이라고 생각하여 올린 코드입니다. :3

Jaehyuk-Lee commented 5 years ago

아 그런 경우를 경험하셨거나 들으셨나요?? 지금까지 저는 항상 ACT랑 같이 구동했었는데 잘되었고 XIV-hunt랑은 해본적이 없네요.(사실 XIV-hunt를 쓴다면 이 프로그램을 안써도 될 정도긴 한데) 다음에 부대밖으로 나가게 되면 테스트해봐야겠네요

참고로 위에 127.0.0.1 ip를 제거하면 된다고 하신건 아마~도? 잘 적용이 된 것 같아요. 이전 버전에서는 Logitech G HUB라는 프로그램에서 추가적인 네트워크 커넥션(127.0.0.1로)을 생성해서 작동을 안했다가 이번 버전부터는 같이 실행해도 잘 작동해서요.

lalafellsleep commented 5 years ago

정말 말도안되는 케이스이긴 한데 비슷한 방법으로 파이널 판타지 프로세스의 네트워크를 읽어들이는 소프트웨어와의 충돌이 있습니다. DFA가 2개가 동시에 켜지는지는 모르겠는데 둘중 하나는 동작을 안할것 같네요. 개인적인 프로그램이 초기에 해당 네트워크 클래스를 사용했어서 겪었던건데 아마 우선순위 문제라고 생각되는게 pcapdotnet 사용 이후 해당 현상이 재현되지 않았거든요...

lalafellsleep commented 5 years ago

류아네린님이 만드셨던 텔레그램 봇이랑도 충돌했던걸로... 아무튼 관련해서 이슈 발생이 추가적으로 있으면 한번 적용해 보시는걸 권해드립니다 ;ㅅ;

Jaehyuk-Lee commented 5 years ago

아 지금은 왠지 모르겠지만 안그런거 같은데(언젠가 devunt님이 코드를 바꿨던 걸 수도) 전에 DFA가 두개가 켜지면 맛이 갔긴 했습니다. 그 때는 그냥 둘 다 맛이 가서 작업관리자에서 꺼야했어요. 다음에 적용해볼게요. 아 지금은 안그렇다는게 두 개가 안켜져요.